文章目录
- 06.指定头文件路径
- 07.通过CMake制作库文件
- 制作动态库或静态库
- 制作静态库
- 制作动态库
- 指定动态库/静态库输出的路径
- 08.在程序中链接静态库
- 09.在程序中链接动态库
- 11. 在cmake中打印日志信息
- 12.字符串操作
- 使用set拼接
- 使用list拼接
- list字符串移除
- list其他命令
06.指定头文件路径
在编译项目源文件的时候,很多时候都需要将源文件对应的头文件路径指定出来,这样才能保证在编译过程中编译器能够找到这些头文件,并顺利通过编译。在CMake 中设置要包含的目录也很简单,通过一个命令就可以搞定了,他就是
include_directories
:
include_directories(headpath)
使用示例:
cmake_minimum_required(VERSION 3.0.0)
project(test)# 指定使用C++标准
set(CMAKE_CXX_STANDARD 11)
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)# 指定头文件路径
include_directories(${PROJECT_SOURCE_DIR}/include)
add_executable(app ${INCLUDE} ${SRC})
注意:include_directories指定的路径,并不是某一个头文件
07.通过CMake制作库文件
制作动态库或静态库
有些时候我们编写的源代码并不需要将他们编译生成可执行程序,而是生成一些动态库或者静态库提供给第三方使用,下面来讲解cmake中生成这两类库文件的方法。
制作静态库
在cmake中,如果需要制作静态库,需要使用以下命令:
add_library(库名称 STATIC 源文件1 [源文件2] ...)
在Linux中,静态库名字分为三部分:lib
+库名字
+.a
,此处只需要指定出库名就可以了,另外两部分在生成该文件的时候会自动填充。
在windows中虽然库名和Linux格式不同,但也只需要指定出名字即可。
接下来我们将之前写的add.cpp
div.cpp
mult.cpp
sub.cpp
放在src目录下并编译生成静态库。
cmake_minimum_required(VERSION 3.15)
project(test)# 指定使用C++标准
set(CMAKE_CXX_STANDARD 11)
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
include_directories(${PROJECT_SOURCE_DIR}/include)add_library(calc STATIC ${SRC})
制作动态库
cmake_minimum_required(VERSION 3.15)
project(test)# 指定使用C++标准
set(CMAKE_CXX_STANDARD 11)
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
include_directories(${PROJECT_SOURCE_DIR}/include)add_library(calc SHARED ${SRC})
动态库是有可执行权限的,静态库是没有可执行权限的
发布给使用者:必须提供一个头文件才能知道库里有什么函数可以被调用
1. 头文件
2. 生成的静态库/动态库
指定动态库/静态库输出的路径
由于在 Linux 下生成的静态库默认不具有可执行权限,所以在指定静态库生成的路径的时候就不能使用
EXECUTABLE_OUTPUT_PATH
(这个只适用动态库)宏了,而应该使用LIBRARY_OUTPUT_PATH
,这个宏对应静态库文件和动态库文件都适用
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
注意:如果改路径不存在生成库文件之前会被自动创建
08.在程序中链接静态库
在cmake中,链接静态库的命令如下:
link_libraries(<static lib> [<static lib>...])
参数1:指定要链接的静态库名字,可以是全名libxxx.a
, 也可以是掐头(lib
)去尾(.a
)之后的名字 xxx
参数2-N:要链接的其它静态库名字
如果该静态库不是系统提供的(自己制作或者第三方提供的静态库)可能出现静态库找不到的情况,此时可以将静态库路径也指定出来:
link_directories(<lib_path>) # 可以包含多个路径
link_directories既可以指定静态库路径也可以指定动态库路径
cmake_minimum_required(VERSION 3.15)
project(test)# 指定使用C++标准
set(CMAKE_CXX_STANDARD 11)# 源文件main.cpp
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)# 头文件
include_directories(${PROJECT_SOURCE_DIR}/include)# 链接静态库文件
link_libraries(calc)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib1)# 生成可执行文件
add_executable(app ${SRC})
在生成可执行文件的时候,如果链接的是静态库,静态库会被打包到可执行程序中,如果是动态库,并不会被打包到可执行程序中
09.在程序中链接动态库
在程序编写过程中,除了在项目中引入静态库,好多时候也会使用一些标准的或者第三方提供的一些动态库
cmake连接动态库的命令如下:
target_link_libraries(<target><PRIVIATE|PUBLIC|INTERFACE> <item>...[<<PRIVIATE|PUBLIC|INTERFACE> <item>...>...]
)
target
:指定要加载动态库文件的名字
- 该文件可能是一个源文件
- 该文件可能是一个动态库文件
- 该文件可能是一个可执行文件
PRIVIATE|PUBLIC|INTERFACE
:动态库访问权限,默认为PUBLIC
1.如果各个动态库之间没有依赖关系,无需做任何设置,三者没有区别,一般无需指定,使用默认的PUBLIC即可
2. 动态库的链接具有传递性,如果动态库A链接了动态库B、C,动态库D链接了动态库A,此时动态库D相当于也链接了B,C,并且可以使用动态库B,C的方法。注意:此时B,C库的链接权限必须是PUBLIC,否则D无法链接B,C库。
target_link_libraries(A B C)
target_link_libraries(D A)
PUBLIC
:在public后面的库会被Link到前面的target中,并且里面的符号(库中定义的函数)也会被导出,提供给第三方使用
PRIVATE
:在private后面的库仅被link到前面的target中,并且终结掉,第三方不能感知你调用了啥库
INTERFACE
:在interface后面引入的库不会被链接到前面的target中,只会导出符号。即target只会知道有某个函数,但是不知道函数的拥有者是哪个动态库。
在物理内存中,动态库有且仅有一份。
target_link_libraries一般都会写到CMakeLists.txt文件最后
cmake_minimum_required(VERSION 3.15)
project(test)# 指定使用C++标准
set(CMAKE_CXX_STANDARD 11)# 源文件main.cpp
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
include_directories(${PROJECT_SOURCE_DIR}/include)link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib2)
add_executable(app ${SRC})
target_link_libraries(app calc)
要将target_link_libraries放到最后
11. 在cmake中打印日志信息
在CMake中更可以用用户显示一条信息,该命令为
message
message([STATUS|WARNING|AUTHOR_WARNING|SEND_ERROR|FATAL_ERROR] "message to display" ..)
(无)
:重要消息
STATUS
:非重要消息
WARNING
:CMake警告,会继续执行
AUTHOR_WARNING
:CMake警告(dev),会继续执行
SEND_ERROR
:CMake错误,继续执行,但是会跳过生成的步骤
FATAL_ERROR
:CMake错误,终止所有处理过程
CMake的命令行工具会在stdout上显示STATUS消息,在stderr上显示其他所有消息。CMake的GUI会在它的log区域显示所有消息。
CMake警告和错误消息的文本显示使用的是一种简单的标记语言。文本没有缩进,超过长度会回卷,段落之间以新行作为分隔符。
# 输出一条日志信息
message(STATUS "source path: ${PROJECT_SOURCE_DIR}")
# 输出警告信息
message(WARNING "source path: ${PROJECT_SOURCE_DIR}")
# 输出错误信息
message(FATAL_ERROR "source path: ${PROJECT_SOURCE_DIR}")
12.字符串操作
有时候项目中的源文件并不一定都在同一个目录下,但是这些源文件最终要一起进行编译来生成最后的可执行文件或者库文件。如果我们通过
file
命令对各个目录下的源文件进行搜索,最后还需要做一个字符串拼接的操作,关于字符串拼接可以使用set
命令或者list
命令
使用set拼接
set(变量名1 ${变量名1} ${变量名2} ...)
例子:
set(tmp hello world)
message(${tmp}) # 输出:helloworld
set(temp1 ${tmp} ${SRC})
message(${tmp1}) # 输出: helloworld+SRC字符串
使用list拼接
使用list进行字符串拼接:
list(APPEND <list>[<element> ...])
示例:
list(APPEND tmp "xxx1" "xxx2")
message(${tmp})
list字符串移除
list(REMOVE_ITEM <list><value>[<value>...])
示例:
list(REMOVE_item SRC ${CMAKE_CURRENT_DIR}/src/main.cpp) # 删除SRC中的main.cpp
list其他命令
获取list长度
list(LENGTH <list> <output variable>)
注意:”output variable“是一个字符串,并不是整数
读取列表中指定索引的元素,可以用于指定多个索引
list(GET <list> <element index> [<element index>...] <output variable>)
list
:当前操作的列表
element index
: 列表元素索引
- 从0开始编号,索引0的元素为列表第一个元素
- 索引也可以是负数,-1表示列表最后一个元素,-2表示列表倒数第二个元素
- 当索引不管是正数还是负数的时候,超过列表长度,都会报错
output variable
:新创建的变量,存储指定索引元素的返回结果,也是一个列表
本文参考:
https://www.bilibili.com/video/BV14s4y1g7Zj?p=13&spm_id_from=pageDriver&vd_source=cf0b4c9c919d381324e8f3466e714d7a