目录
本节内容的学习:基本掌握CMakeLists.txt文件的编写以及Makefile文件的构建
简介
CMake是一个跨平台的管理源码构建的工具。
安装
- 在ubantu上使用
apt install cmake
命令进行安装 - 安装后使用
cmake -version
查看cmake的版本号
使用CMake构建软件包
前提:发布的软件源码使用CMake进行管理,使用CMake进行管理的项目通常在项目根目录下都有CMakeLists.txt这个文件
- 使用CMake user interaction tool进行构建软件包的步骤如下:
cd 源码根目录
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=安装的目标位置
# --build flag enables a particular mode of operation for the cmake tool
cmake --build .
# 安装
cmake --build . --target install
- 使用CMake user interaction tool构建时,可以传递一些变量
- CMAKE_PREFIX_PATH:指定搜索依赖包的路径。通常一个项目依赖的同一个包在系统中存在多个,需要显示指定。
- CMAKE_MODULE_PATH:指定搜索CMake modules的路径
- CMAKE_BUILD_TYPE:Build configuration, such as Debug or Release
- CMAKE_INSTALL_PREFIX:指定安装软件的位置
- BUILD_SHARED_LIBS:其值有ON和OFF。当使用add_library没有指定构建的类型时,这个选项用于标识是否构建shared library
CMake的基本语法
1.PROJECT关键字
- 可以用来指定工程的名称、支持的语言、工程的版本号。如果不指定语言,默认是支持所有语言的
- PROJECT(SERVER):指定了工程的名称,并支持所有语言
- PROJECT(SERVER CXX):指定了工程的名字,并且支持语言是C++
- PROJECT(SERVER CXX C):指定了工程的名字,并且支持语言是C++和C
2.SET关键字
- 可以用来为变量设置值,例如:
SET(SRC_LIST main.cpp)
,SRC_LIST变量的值就包括main.cpp
3.MESSAGE关键字
- 可以用来向终端用户输出自定义的信息。主要包括三种信息:
- SEND_ERROR:产生错误,生成过程被跳过。
- SATUS:输出前缀为--的信息。
- FATAL_ERROR:将会终止CMake构建过程
4.ADD_EXECUTABLE关键字
- 用于指定生成可执行文件的名称,例如:
ADD_EXECUTABLE(server ${SRC_LIST})
5.ADD_SUBDIRECTORY关键字
- 用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置
- 语法格式为:
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
- source_dir:指定向当前工程添加存放源文件的子目录
- binary_dir:指定CMake构建过程中中间二进制和目标二进制存放的位置
- 使用示例:
-
项目目录为:
-
项目根目录下的CMakeLists.txt内容为:
project(test2) # 向当前工程加入src目录,并指定构建的输出目录为bin(如果在test2/build目录下执行cmake ..) # 则输出目录为build/bin add_subdirectory(src bin)
- 源码目录src下的CMakeLists.txt内容为:
set(src_list main.cpp) add_executable(target ${src_list})
- 在build目录下执行
cmake ..
,即可在build目录下产生Makefile
-
6.ADD_LIBRARY关键字
- 用来构建动态库或者静态库。
- 语法示例:
ADD_LIBRARY(库名称 SHARED|STATIC ${LIBHELLO_SRC})
- SHARED:指定构建的是动态库
- STATIC:指定构建的是静态库
- ${LIBHELLO_SRC}指定构建库所需要的源文件
7.INSTALL关键字
- 使用INSTALL关键字可以用来安装二进制文件、动态库、静态库、文件、目录、脚本等
- CMAKE中预定义的变量:CMAKE_INSTALL_PREFIX,其值默认为 /usr/local/
- 该指令的使用示例:
-
项目目录如下:
-
项目根目录下的CMakeLists.txt内容为:
project(test3) add_subdirectory(src bin) # 安装文件COPYRIGHT和README install(FILES COPYRIGHT README DESTINATION share/cmake/) # 安装脚本test3.sh install(PROGRAMS test3.sh DESTINATION share/bin) # 安装目录,安装doc目录下的所有内容 install(DIRECTORY doc/ DESTINATION share/doc)
- 在build目录下执行cmake ..即可在build目录下产生Makefile
- make
- 安装:make install,即可在
${CMAKE_INSTALL_PREFIX}/<DESTINATION 定义的路径>
查看安装的内容
-
8.TARGET_LINK_LIBRARIES关键字
- 用来添加需要链接的共享库
9.CMake中的变量
- CMake中预定义了很多变量,比如说:
- PROJECT_BINARY_DIR:使用CMake构建输出的目录
- PROJECT_SOURCE_DIR:项目源码目录
- 变量取值:使用
${变量名称}
- 指令的参数之间使用空格或者分号分隔,例如
add_executable(fileserver ${net_srcs} ${fileserver_srcs} ${utils_srcs})
- 指令名称大小写无关,例如ADD_EXECUTABLE和add_executable都行的
简单示例
1.CMake构建静态库和动态库
- 静态库和动态库的区别:
- 静态库的扩展名一般为.a或者.lib,动态库的扩展名一般为.dll或者.so。
- 静态库在编译时会直接整合到目标程序中,编译成功的可执行文件可独立运行
- 动态库在编译时不会放到目标程序中,即可执行文件无法单独运行。它需要在运行时进行链接动态库
- 使用CMAKE单独构建静态库或者动态库示例:
-
项目目录如下:
-
项目根目录下的CMakeLists.txt内容为:
project(test4) add_subdirectory(lib bin)
- 源码目录src下的CMakeLists.txt内容为:
set(libhello_src hello.cpp) add_library(hello SHARED ${libhello_src})
- 在build目录下执行cmake ..即可在build目录下产生Makefile
- 执行make即可产生动态库libhello.so
-
- 静态库和动态库的同时构建
set(libhello_src hello.cpp)
# 构建静态库
add_library(hello_static STATIC ${libhello_src})
# 对hello_static进行重命名为hello
set_target_properties(hello_static PROPERTIES OUTPUT_NAME "hello")
# 清理掉hello_static这个库
set_target_properties(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
add_library(hello SHARED ${libhello_src})
set_target_properties(hello PROPERTIES OUTPUT_NAME "hello")
set_target_properties(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
-
安装共享库和头文件:示例将hello这个共享库安装到${CMAKE_INSTALL_PREFIX}/lib目录下,将头文件hello.h安装到${CMAKE_INSTALL_PREFIX}/include/hello目录下,完整示例如下:
-
项目目录如下:
-
项目根目录下的CMakeLists.txt内容为:
project(test4) add_subdirectory(lib bin)
- 源码目录src下的CMakeLists.txt内容为:
set(libhello_src hello.cpp) # 构建静态库 add_library(hello_static STATIC ${libhello_src}) # 对hello_static进行重命名为hello set_target_properties(hello_static PROPERTIES OUTPUT_NAME "hello") set_target_properties(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) add_library(hello SHARED ${libhello_src}) set_target_properties(hello PROPERTIES OUTPUT_NAME "hello") set_target_properties(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1) # 将头文件hello.h放到${CMAKE_INSTALL_PREFIX}/include/hello目录下 install(FILES hello.h DESTINATION include/hello) # 二进制、静态库、动态库安装的第一个参数都使用TARGETS # ARCHIVE指的是静态库 # LIBRARY指的是动态库 install(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
- 在build目录下执行cmake ..即可在build目录下产生Makefile
- 执行make即可产生动态库libhello.so和静态库libhello.a
- 安装:
-
-
共享库和头文件的使用,示例如下
-
项目目录如下:
-
main.cpp内容如下:
#include <hello.h> int main() { // 调用动态库中的函数 func(); }
- 项目根目录下的CMakeLists.txt内容为:
project(test5) # 加入头文件搜索路径 include_directories(/usr/local/include/hello) # 添加非标准的共享库搜索路径 link_directories(/usr/local/lib) add_subdirectory(src bin)
- 源码目录src下的CMakeLists.txt内容为:
set(src_list main.cpp) add_executable(target ${src_list}) # 添加需要链接的共享库 target_link_libraries(target libhello.so)
- 在build目录下执行cmake ..即可在build目录下产生Makefile
- 执行make即可生成目标可执行文件
- 查看可执行文件所依赖的共享库列表:
# ldd全称list dynamic dependencies ldd target
-
参考:参考