文章目录
04. CMake项目的二进制目录和源目录
CMake 会为每个项目的二进制目录、源目录隐式生成两个变量: <project_name>_BINARY_DIR 、<project_name>_SOURCE_DIR。
<project_name>_BINARY_DIR = PROJECT_BINARY_DIR
执行cmake
命令所在的目录;<project_name>_SOURCE_DIR = PROJECT_SOURCE_DIR
对应源文件的目录,即CMakeLists.txt对应的目录。
建议使用PROJECT_xxxx
,不会随着项目名称改变而改变。
05. CMake构建静态库和动态库
命令add_library
生成静态库/动态库
05.1 格式
add_library(lib_name [SHARE|STATIC|MODULE] [EXCLUDE_FROM_ALL] src1 src2)
参数说明
- lib_name:指定生成库名称
- SHARED:动态库
- STATIC: 静态库
- MODULE: 使用dyld(苹果的动态链接器)的系统有效,如不支持dyld,则为SHARED
- EXCLUDE_FROM_ALL: 指定此参数,则该库默认不被构建,有其他组件用到该库或手动构建时才被构建
- src1、src2…:用于构建库的源文件的
05.2 案例
05.2.1 文件结构
.
├── CMakeLists.txt
├── HelloLibrary.cpp
├── HelloLibrary.h
└── Main.cpp
05.2.2 CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.8) #检测CMake最低版本,最低版本3.8
project(HelloLibrary) #项目工程名称
add_library(hello_library SHARED HelloLibrary.cpp) #指定库名为hello_library,因指明生成 SHARED(动态库),实际生成库文件名称为 libhello_library.so ,用于生成该库的源文件为 HelloLibrary.cpp
#add_library(hello_library STATIC HelloLibrary.cpp) #指定库名为hello_library,因指明生成 STATIC(静态库),实际生成库文件名称为 libhello_library.a ,用于生成该库的源文件为 HelloLibrary.cpp
include_directories(${PROJECT_SOURCE_DIR}) #添加包含头文件的路径。此处,把项目源文件添加到包含头文件的路径中
add_executable(hello_main Main.cpp) #指定生成可执行文件,生成的可执行文件名为 hello_main ,所需源文件为 Main.cpp
target_link_libraries(hello_main hello_library) #指定某个目标的生成所依赖的库。此处,生成可执行文件hello_main要依赖hello_library库,即add_library指令生成的库
06. CMake添加工程子目录
命令add_subdirectory
用于向当前工程添加子目录,并可指定中间二进制和目标二进制文件存放的位置,还可将指定目录排除出编译过程。
06.1 格式
add_subdirectory(src_dir [bin_dir] [EXCLUDE_FROM_ALL])
参数说明
- src_dir:把
src_dir
子目录加入工程 - bin_dir:指定编译输出(包含编译的中间结果)的目录为
bin_dir
,如不指定默认输出目录为src_dir
,即与src_dir
的同名目录。指定本质是将src_dir
重命名为bin_dir
- EXCLUDE_FROM_ALL: 指定此参数,将给定的目录从编译中排除,即不编译该指定目录,如,一些示例的目录,需等工程构建完后再单独构建。
06.2 案例
06.2.1 文件结构
.
├── CMakeLists.txt
└── src
├── CMakeLists.txt
└── main.cpp
06.2.2 CMakeLists.txt 文件
- 工程路径下
CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(SubDirectory)
#add_subdirectory(src) #指定源文件子目录为src,编译输出(包含编译的中间结果)的目录命名为src
add_subdirectory(src bin) #指定源文件子目录为src,编译输出(包含编译的中间结果)的目录命名为bin
- src 子目录路径下
CMakeLists.txt
add_executable(sub_directory main.cpp)
07. CMake指定目标保存目录
虽命令add_subdirectory
可用于指定编译输出目录,但无法将编译中间文件与目标文件分隔开,需要结合set
设置EXECUTABLE_OUTPUT_PATH
、LIBRARY_OUTPUT_PATH
来指定最终目标二进制文件存放的位置与编译中间结果分隔开。
07.1 格式
set(EXECUTABLE_OUTPUT_PATH <dir>)
set(LIBRARY_OUTPUT_PATH <dir>)
参数说明
- EXECUTABLE_OUTPUT_PATH:最终可执行文件存放的目录
- LIBRARY_OUTPUT_PATH:最终库文件(静态、动态库)存放的目录
07.2 案例
07.2.1 文件结构
.
├── CMakeLists.txt
└── src
├── CMakeLists.txt
├── Main.cpp
├── SayHello.cpp
└── SayHello.h
07.2.2 CMakeLists.txt 文件
- 工程路径下
CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(OutputPath)
add_subdirectory(src)
- src 子目录路径下
CMakeLists.txt
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) #把可执行文件生成于项目编译目录下的bin目录
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) #把库文件生成于项目编译目录下的lib目录
add_library(SayHello SayHello.cpp) #指定库名为 SayHello,默认采用STATIC(静态库)编译,实际生成库文件名称为 libSayHello.a ,用于生成该库的依赖源文件为 SayHello.cpp
include_directories(${PROJECT_SOURCE_DIR}/src) #将源文件所在目录加入包含头文件目录中,如不加,会找不到SayHello.h该头文件
add_executable(OutputPath Main.cpp)
target_link_libraries(OutputPath SayHello)
08. CMake自定义安装
命令INSTALL
用于自定义安装规则,并配合CMAKE_INSTALL_PREFIX
变量来指定安装的路径,自定义安装规则内容可以是可执行二进制文件、动态库(共享库)、静态库、普通文件、目录、非目标可执行文件(如脚本)、安装时执行cmake脚本等。
08.1 格式
08.1.1 二进制目标文件(可执行、动态库(共享库)、静态库)的安装
INSTALL(TARGRTS targets... [ARCHIVE|LIBRARY|RUNTIME]
[DESTINATION <dir>] [PERMISSIONS permisssions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component> [OPTIONAL][...])
参数说明
- TARGRTS : 后跟的 targets 即为
add_executable
、add_library
定义的目标二进制可执行文件、目标二进制库 - ARCHIVE|LIBRARY|RUNTIME : 分别指静态库、动态库(共享库)、可执行二进制文件
- DESTINATION <dir> : 定义安装的路径,结合
CMAKE_INSTALL_PREFIX
,路径为${CMAKE_INSTALL_PREFIX}/DESTINATION
, 如 以/
开头,则直接从根目录开始, 此时CMAKE_INSTALL_PREFIX 路径无效,一般<dir>
写相对路径 - CONFIGURATIONS : 指定权限
- COMPONENT : 指定版本
二进制目标文件示例
INSTALL(TARGETS exe sharedlib staticlib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION static_lib)
此句含义:
exe
安装到${CMAKE_INSTALL_PREFIX}/bin
路径下sharedlib
安装到${CMAKE_INSTALL_PREFIX}/lib
路径下staticlib
安装到${CMAKE_INSTALL_PREFIX}/static_lib
路径下
08.1.2 普通文件的安装
INSTALL(FILES files... [DESTINATION <dir>]
[PERMISSIONS permisssions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>][OPTIONAL])
参数说明
用于安装普通文件,可指定访问权限,文件名是此指令所在路径下的相对路径如不指定PERMISSIONS
,安装后的权限为644权限
08.1.3 非目标可执行程序(如脚本)的安装
INSTALL(PROGRAMS files... [DESTINATION <dir>]
[PERMISSIONS permisssions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>][OPTIONAL])
参数说明
类似安装普通文件,只是默认权限不一样安装后的权限为755权限
08.1.4 目录的安装
INSTALL(DIRECTORY dirs...
[FILE_PERMISSIONS permisssions...]
[DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[[PATTERN <pattern> | REGEX <regex>] [EXCLUDE] [PERMISSIONS permissions...]]
[...])
参数说明
- DIRECTORY : 后跟的是所在源目录的相对路径, 目录后有无
/
区别很大!!dir
是将 dir 这个目录安装为目录路径下的 dir , 而dir/
是将 dir目录下的内容安装到目标目录.但不包含dir目录本身/ - ARCHIVE|LIBRARY|RUNTIME : 分别指静态库、动态库(共享库)、可执行二进制文件
- DESTINATION <dir> : 定义安装的路径,结合
CMAKE_INSTALL_PREFIX
,路径为${CMAKE_INSTALL_PREFIX}/DESTINATION
, 如 以/
开头,则直接从根目录开始, 此时CMAKE_INSTALL_PREFIX 路径无效,一般<dir>
写相对路径 - PATTERN : 使用正则表达式进行过滤
- PERMISSIONS : 用于指定 PATTERN 过滤后的文件权限
目录安装示例
INSTALL(DIRECTORY samples modules/ DESTINATION share
PATTERN "TXT" EXCLUDE
PATTERN "modules/*"
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ)
此句含义:
samples
目录安装到${CMAKE_INSTALL_PREFIX}/share
路径下modules/
目录中的内容安装到${CMAKE_INSTALL_PREFIX}/share
路径下,不包含目录名为 TXT 的目录,并对 modules/ 目录下的文件赋予750权限
08.1.5 安装时执行cmake脚本
INSTALL([[SCRIPT <file>] [CODE <code]] [...])
参数说明
- SCRIPT : 用于在安装时调用 cmake 脚本文件,即 xxxx.cmake 文件
- CODE : 执行 cmake 指令,要用双引号
INSTALL(CODE "MESSAGE(\"Sample install message.\")")
08.2 案例
08.2.0 操作方法
- a) 命令归纳
cmake -DCMAKE_INSTALL_PREFIX=/tmp ..
make
make install
- b) 操作打印
gene@gene:~/00_CMakeLists/cmake-master/08_CustomizeInstall/build$ cmake -DCMAKE_INSTALL_PREFIX=/tmp ..
-- The C compiler identification is GNU 7.5.0
-- The CXX compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/gene/00_CMakeLists/cmake-master/08_CustomizeInstall/build
gene@gene:~/00_CMakeLists/cmake-master/08_CustomizeInstall/build$ make
Scanning dependencies of target customize_install
[ 50%] Building CXX object bin/CMakeFiles/customize_install.dir/Main.cpp.o
[100%] Linking CXX executable customize_install
[100%] Built target customize_install
gene@gene:~/00_CMakeLists/cmake-master/08_CustomizeInstall/build$ make install
[100%] Built target customize_install
Install the project...
-- Install configuration: ""
-- Up-to-date: /tmp/CustomizeInstall/copyright
-- Up-to-date: /tmp/CustomizeInstall/readme
-- Up-to-date: /tmp/CustomizeInstall/bin/run_customize_install.sh
-- Up-to-date: /tmp/CustomizeInstall/share/doc
-- Up-to-date: /tmp/CustomizeInstall/share/doc/customize_install_doc.txt
-- Installing: /tmp/CustomizeInstall/bin/customize_install
08.2.1 文件结构
.
├── CMakeLists.txt
├── copyright
├── doc
│ └── customize_install_doc.txt
├── readme
├── run_customize_install.sh
└── src
├── CMakeLists.txt
└── Main.cpp
08.2.2 CMakeLists.txt 文件
- 工程路径下
CMakeLists.txt
cmake_minimum_required(VERSION 3.8) # 指定最小CMake版本
project(CustomizeInstall) # 指定项目工程名称
add_subdirectory(src bin) # 将 src 源文件子目录加入项目中
install(FILES copyright readme DESTINATION CustomizeInstall) # 将 copyright, readme 这两个文件安装到目录/${CMAKE_INSTALL_PREFIX}/CustomizeInstall下
install(PROGRAMS run_customize_install.sh DESTINATION CustomizeInstall/bin) # 将 run_customize_install.sh 脚本文件安装到目录/${CMAKE_INSTALL_PREFIX}/CustomizeInstall/bin下
install(DIRECTORY doc/ DESTINATION CustomizeInstall/share/doc) # 将 doc/ 目录下所有文件(不包含该目录本身)安装到目录/${CMAKE_INSTALL_PREFIX}/CustomizeInstall/share/doc下
- src 子目录路径下
CMakeLists.txt
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) #设置二进制目标可执行文件存放路径
add_executable(customize_install Main.cpp) #生成二进制目标可执行文件
install(TARGETS customize_install DESTINATION CustomizeInstall/bin) #指定该可执行二进制文件要安装的路径,此处为:/${CMAKE_INSTALL_PREFIX}/CustomizeInstall/bin
09. CMake设置生成库的属性
命令set_target_properties
可用于设置目标的属性, get_target_properties
可用于获得目标的属性。
09.1 格式
09.1.1 设置属性
set_target_properties(target1 target2... properties prop1 value1 prop2 value2 ...)
参数说明
get_target_property(VAR target prop)
参数说明
- VAR:获取的属性存放的变量
- target:目标
- prop:要获取的属性名
09.2 案例
09.2.1 文件结构
.
├── CMakeLists.txt
└── src
├── CMakeLists.txt
├── linear.cpp
└── linear.h
09.2.2 CMakeLists.txt 文件
- 工程路径下
CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(LibraryProperty)
add_subdirectory(src)
- src 子目录路径下
CMakeLists.txt
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) # 设置生成库的存放目录,为编译目录的 lib 子目录
add_library(linear SHARED linear.cpp) # 添加生成动态库目标,目标名为 linea
add_library(static_linear STATIC linear.cpp) # 添加生成静态库目标,目标名为 static_linea
set_target_properties(static_linear PROPERTIES OUTPUT_NAME "linear") # 设置静态库目标输出名为 linear
get_target_property(OUTPUT_VALUE static_linear OUTPUT_NAME) # 获取 static_linear 属性值(OUTPUT_NAME)保存至 OUTPUT_VALUE 变量中
message(STATUS "OUTPUT_NAME = ${OUTPUT_VALUE}") # 将 OUTPUT_VALUE 变量中的值打印出来 (打印结果:OUTPUT_NAME = linear)
get_target_property(UNDEFINE_VALUE static_linear UNDEFINE_NAME) # 获取 static_linear E未定义属性值(UNDEFINE_NAM)保存至 OUTPUT_VALUE 变量中
message(STATUS "UNDEFINE_NAME = ${UNDEFINE_VALUE}") # 将 UNDEFINE_VALUE 变量中的值打印出来,作对比(打印结果:UNDEFINE_NAME = UNDEFINE_VALUE-NOTFOUND)
set_target_properties(linear PROPERTIES VERSION 1.0 SOVERSION 1) # 设置动态库版本号(VERSION) API号(SOVERSION)
install(TARGETS linear static_linear LIBRARY DESTINATION lib ARCHIVE DESTINATION lib/${PROJECT_NAME}) # 动态库安装到<perfix>/lib 静态库安装到<prefix>lib/${PROJECT_NAME}
install(FILES linear.h DESTINATION include/${PROJECT_NAME}) # 头文件安装到<perfix>/include/${PROJECT_NAME}
10. CMake调用外部库
命令target_link_libraries
用于调用外部库,为目标添加需要链接的库,命令link_libraries
用于为目标添加需要链接的库的目录,二者结合使用,前者指定具体库名称,后者指定库路径所在目录路径。include_directories
用于添加头文件搜索路径。link_directories
用于添加非系统(非标准)的库搜索路径。。
10.1 格式
命令汇总
target_link_libraries(target lib1 <debug | optimized> lib2 ...)
include_directories([AFTER | BEFORE] [SYSTEM] dir1 dir2 ...)
link_directories(dir1 dir2 ...)
link_libraries([item1 [item2 [...]]]
[[debug | optimized | general] <item>])
10.1 .1 添加链接库
target_link_libraries(target lib1 <debug | optimized> lib2 ...)
参数说明
- target:目标二进制文件
- lib1:库名称
添加需要链接外部库示例
target_link_libraries(main linear)
target_link_libraries(main liblinear.so)
target_link_libraries(main liblinear.a)
该句含义:
- 目标 main 链接到 linear 动态库
- 目标 main 链接到 linear 动态库
- 目标 main 链接到 linear 静态 库
10.1 .2 添加头文件搜索路径
include_directories([AFTER | BEFORE] [SYSTEM] dir1 dir2 ...)
说明
- 多个路径用空格分开,如路径有空格,路径用双引号引起来;
- 默认添加到搜索路径的后面,可通过
AFTER
和BEFORE
来控制添加到前面还是后面 - CMake 变量
CMAKE_INCLUDE_DIRECTORIES_BEFORE
设置为on 也可把路径添加至前面
10.1 .3 添加非系统(非标准)的库搜索路径
link_directories(dir1 dir2 ...)
说明
此命令要放在add_executable
目标之前, 如, 要放在 add_executable
或 add_library
之前
10.1 .4 添加链接库目录
link_libraries([item1 [item2 [...]]]
[[debug | optimized | general] <item>])
说明
此命令要放在目标之前, 如, 要放在 add_executable
或 add_library
之前, 指定的库要全称
10.2 案例
10.2.1 文件结构
- 工程文件结构
.
├── CMakeLists.txt
└── src
├── CMakeLists.txt
└── Main.cpp
- 外部库文件结构
.
├── liblinear.so -> liblinear.so.1
├── liblinear.so.1 -> liblinear.so.1.0
├── liblinear.so.1.0
└── LibraryProperty
└── liblinear.a
10.2.2 CMakeLists.txt 文件
- 工程路径下
CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(ExternalLibrary)
add_subdirectory(src)
- src 子目录路径下
CMakeLists.txt
# 版本1 使用link_libraries 添加动/静态库
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) # 设置二进制目标文件输出的存放目录,为编译目录的bin子目录
link_libraries(/tmp/lib/liblinear.so) # 添加(动态)链接库,注意:全路径, 一定在 add_executable 前面 (无此类似句,会报" undefined reference to `linear_fit()' ... " 错误,即没找到要链接的库)
# link_libraries(/tmp/lib/LibraryProperty/liblinear.a) # 添加(静态)链接库,注意:全路径, 一定在 add_executable 前面 (无此类似句,会报" undefined reference to `linear_fit()' ... " 错误,即没找到要链接的库)
add_executable(ExternalLibrary Main.cpp) # 添加二进制目标,依赖 Main.cpp
include_directories(/tmp/include/LibraryProperty) # 添加对应头文件的目录 (无此句,会报"No such file or directory ..." 错误,即没找到对应头文件)
#版本2 使用target_link_libraries链接静态库
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) # 设置二进制目标文件输出的存放目录,为编译目录的bin子目录
link_directories(/tmp/lib/LibraryProperty) # 添加静态库对应的目录,注意:在 add_executable前面!!(因该路径下只有静态库,虽 target_link_libraries 指定动态库,实际结果也会是静态库)
# link_directories(/tmp/lib) # 添加动态库对应的目录,注意:在 add_executable前面!!(虽该路径下有含静态库的目录LibraryProperty,但依旧会报错,即此时 target_link_libraries 链接不到静态库)
add_executable(ExternalLibrary Main.cpp) # 添加二进制目标,依赖 Main.cpp
include_directories(/tmp/include/LibraryProperty) # 添加对应头文件的目录 (无此句,会报"No such file or directory ..." 错误,即没找到对应头文件)
target_link_libraries(ExternalLibrary liblinear.a) # 添加链接(静态)库,注意:在 add_executable后面 (无此类似句,会报" undefined reference to `linear_fit()' ... " 错误,即没找到要链接的库)
#版本3 使用target_link_libraries链接动态库
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) # 设置二进制目标文件输出的存放目录,为编译目录的bin子目录
link_directories(/tmp/lib) # 添加动态库对应的目录,注意:在 add_executable前面!!
add_executable(ExternalLibrary Main.cpp) # 添加二进制目标,依赖 Main.cpp
include_directories(/tmp/include/LibraryProperty) # 添加对应头文件的目录 (无此句,会报"No such file or directory ..." 错误,即没找到对应头文件)
target_link_libraries(ExternalLibrary liblinear.so) # 添加链接(动态)库,注意:在 add_executable后面 (无此类似句,会报" undefined reference to `linear_fit()' ... " 错误,即没找到要链接的库)