1.cmake用法详解
①编写CMakeLists.txt
②执行cmake PATH生成Makefile(PATH是cmakelists.txt所在路径)
③make编译
假设我们的项目中只有一
个源文件
main.cpp,CMakeLists.txt文件如下所示:
1 PROJECT(main) 2 CMAKE_MINIMUM_REQUIRED(VERSION 2.6) //aux_source_directory(<dir> <variable>)把参数 <dir> 中所有的源文件名称赋值给参数 <variable> 3 AUX_SOURCE_DIRECTORY(. DIR_SRCS) //指示变量 DIR_SRCS 中的源文件需要编译 成一个名称为 main 的可执行文件 4 ADD_EXECUTABLE(main ${DIR_SRCS})
假设我们的源代码
分布情况如下:
step2 dir(main.cpp、src(test1.h、test1.cpp))其中 src 目录下的文件要编译成一个链接库,则
CMakeLists.txt文件如下所示:
//目录 step2 中的 CMakeLists.txt PROJECT(main) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) ADD_SUBDIRECTORY( src )//ADD_SUBDIRECTORY 指明本项目包含一个子目录 src AUX_SOURCE_DIRECTORY(. DIR_SRCS) ADD_EXECUTABLE(main ${DIR_SRCS}) TARGET_LINK_LIBRARIES( main Test )//指明可执行文件 main 需要连接一个名为Test的链接库
//目录 src 中的 CmakeLists.txt AUX_SOURCE_DIRECTORY(. DIR_TEST1_SRCS) ADD_LIBRARY ( Test ${DIR_TEST1_SRCS})//将 src 目录中的源文件编译为共享库
在执行 cmake 的过程中,首先解析目录 step2 中的 CMakeLists.txt ,当程序执行命令 ADD_SUBDIRECTORY( src ) 时进入目录 src 对其中的 CMakeLists.txt 进行解析。
找到安装在不同位置的库文件,假如需要一个数据库中的头文件db_cxx.h 和链接库 libdb_cxx.so ,现在该项目中有一个源代码文件 main.cpp ,放在项目的根目录中。
在项目的根目录中创建目录 cmake/modules/ ,在 cmake/modules/ 下创建文件 Findlibdb_cxx.cmake ,内容如下:
//文件Findlibdb_cxx.cmake MESSAGE(STATUS "Using bundled Findlibdb.cmake...")//MESSAGE 会将参数的内容输出到终端。 // FIND_PATH 指明头文件查找的路径 //find_path(<VAR> name1 [path1 path2 ...]) 该命令在参数 path* 指示的目录中查找文件 name1 并将查找到的路径保存在变量 VAR中 FIND_PATH( LIBDB_CXX_INCLUDE_DIR db_cxx.h /usr/include/ /usr/local/include/ ) //查找链接库并将结果保存在变量中 FIND_LIBRARY( LIBDB_CXX_LIBRARIES NAMES db_cxx PATHS /usr/lib/ /usr/local/lib/ )
在项目的根目录中创建 CmakeList.txt :
01 PROJECT(main) 02 CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 03 SET(CMAKE_SOURCE_DIR .) //到目录 ./cmake/modules 中查找 Findlibdb_cxx.cmake 04 SET(CMAKE_MODULE_PATH ${CMAKE_ROOT}/Modules ${CMAKE_SOURCE_DIR}/cmake/modules) 05 AUX_SOURCE_DIRECTORY(. DIR_SRCS) 06 ADD_EXECUTABLE(main ${DIR_SRCS}) 0708 FIND_PACKAGE( libdb_cxx REQUIRED) 09 MARK_AS_ADVANCED( 10 LIBDB_CXX_INCLUDE_DIR 11 LIBDB_CXX_LIBRARIES 12 ) 13 IF (LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES) 14 MESSAGE(STATUS "Found libdb libraries") 15 INCLUDE_DIRECTORIES(${LIBDB_CXX_INCLUDE_DIR}) 16 MESSAGE( ${LIBDB_CXX_LIBRARIES} ) 17 TARGET_LINK_LIBRARIES(main ${LIBDB_CXX_LIBRARIES}) 19 ENDIF (LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES)
然后在根目录编译cmake ..和make
·设置编译类型
add_executable(demo demo.cpp) # 生成可执行文件 add_library(common STATIC util.cpp) # 生成静态库 add_library(common SHARED util.cpp) # 生成动态库或共享库
add_library 默认生成是静态库,通过以上命令生成文件名字:
在 Linux 下是:demo、libcommon.a、libcommon.so
在 Windows 下是:demo.exe、common.lib、common.dll
·指定编译包含的源文件
明确指定包含哪些源文件:
add_library(demo demo.cpp test.cpp util.cpp)
搜索所有的 cpp 文件:
aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件 add_library(demo ${SRC_LIST})
自定义搜索规则:
file(GLOB SRC_LIST "*.cpp" "protocol/*.cpp") add_library(demo ${SRC_LIST}) # 或者 file(GLOB SRC_LIST "*.cpp") file(GLOB SRC_PROTOCOL_LIST "protocol/*.cpp") add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST}) # 或者 aux_source_directory(. SRC_LIST) aux_source_directory(protocol SRC_PROTOCOL_LIST) add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
· 查找指定的库文件
find_library(VAR name path)查找到指定的预编译库,并将它的路径存储在变量中。
find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log )
·设置包含的目录
include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include ) 或 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}")
·设置链接库搜索目录
link_directories( ${CMAKE_CURRENT_SOURCE_DIR}/libs ) 或 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/libs")
·设置 target 需要链接的库
target_link_libraries( # 目标库 demo # 目标库需要链接的库 # log-lib 是上面 find_library 指定的变量名 ${log-lib} )
在 Windows 下,系统会根据链接库目录,搜索xxx.lib 文件,Linux 下会搜索 xxx.so 或者 xxx.a 文件,如果都存在会优先链接动态库(so 后缀)。
·指定链接动态库或静态库
target_link_libraries(demo libface.a) # 链接libface.a target_link_libraries(demo libface.so) # 链接libface.so
·指定全路径
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a) target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.so)
·指定链接多个库
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a boost_system.a boost_thread pthread)
·设置变量的值
set(SRC_LIST main.cpp test.cpp) add_executable(demo ${SRC_LIST})
·包含其它 cmake 文件
include(./common.cmake) # 指定包含文件的全路径 include(def) # 在搜索路径中搜索def.cmake文件 set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # 设置include的搜索路径
2.CMakeLists常用变量
- 一般一个代码文件夹包含:src、build、bin、include、lib、CMakeLists.txt
PROJECT_SOURCE_DIR:工程的根目录
PROJECT_BINARY_DIR:运行 cmake 命令的目录,通常是 ${PROJECT_SOURCE_DIR}/build
PROJECT_NAME:返回通过 project 命令定义的项目名称
CMAKE_CURRENT_SOURCE_DIR:当前处理的 CMakeLists.txt 所在的路径
CMAKE_CURRENT_BINARY_DIR:target 编译目录
CMAKE_CURRENT_LIST_DIR:CMakeLists.txt 的完整路径
CMAKE_CURRENT_LIST_LINE:当前所在的行
CMAKE_MODULE_PATH:定义自己的 cmake 模块所在的路径,SET(CMAKE_MODULE_PATH${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块
EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置(set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin))
LIBRARY_OUTPUT_PATH:重新定义目标链接库文件的存放位置(set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib))BUILD_SHARED_LIBS:这个开关用来控制默认的库编译方式,如果不进行设置,使用 add_library 又没有指定库类型的情况下,默认编译生成的库都是静态库。如果 set(BUILD_SHARED_LIBS ON) 后,默认生成的为动态库
CMAKE_C_FLAGS:设置 C 编译选项,也可以通过指令 add_definitions() 添加
CMAKE_CXX_FLAGS:设置 C++ 编译选项,也可以通过指令 add_definitions() 添加
3.CMakeLists.txt编写
·复杂项目目录结构如下(多个目录,多个源文件,多个项目):
demo 根目录下的 CMakeLists.txt 文件如下:
cmake_minimum_required (VERSION 2.8) project(demo) aux_source_directory(. DIR_SRCS) # 添加math子目录 add_subdirectory(math) # 指定生成目标 add_executable(demo ${DIR_SRCS}) # 添加链接库 target_link_libraries(demo MathFunctions)
math 目录下的 CMakeLists.txt 文件如下:
aux_source_directory(. DIR_LIB_SRCS) # 生成链接库 add_library(MathFunctions ${DIR_LIB_SRCS})
·自定义编译选项:
cmake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。
例如,可以将 MathFunctions 库设为一个可选的库,如果该选项为 ON ,就使用该库定义的数学函数来进行运算,否则就调用标准库中的数学函数库。
修改根目录下的 CMakeLists.txt 文件如下:# CMake 最低版本号要求 cmake_minimum_required (VERSION 2.8) # 项目信息 project (Demo) # 加入一个配置头文件,用于处理 CMake 对源码的设置 configure_file ( "${PROJECT_SOURCE_DIR}/config.h.in" "${PROJECT_BINARY_DIR}/config.h" ) # 是否使用自己的 MathFunctions 库 option (USE_MYMATH "Use provided math implementation" ON) # 是否加入 MathFunctions 库 if (USE_MYMATH) include_directories ("${PROJECT_SOURCE_DIR}/math") add_subdirectory (math) set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions) endif (USE_MYMATH) # 查找当前目录下的所有源文件 # 并将名称保存到 DIR_SRCS 变量 aux_source_directory(. DIR_SRCS) # 指定生成目标 add_executable(Demo ${DIR_SRCS}) target_link_libraries (Demo ${EXTRA_LIBS})
- configure_file 命令用于加入一个配置头文件 config.h ,这个文件由 cmake 从 config.h.in 生成,通过这样的机制,将可以通过预定义一些参数和变量来控制代码的生成。
- option 命令添加了一个 USE_MYMATH 选项,并且默认值为 ON 。根据 USE_MYMATH 变量的值来决定是否使用我们自己编写的 MathFunctions 库。
修改 main.cc 文件,让其根据 USE_MYMATH 的预定义值来决定是否调用标准库还是MathFunctions 库:
#include "config.h" #ifdef USE_MYMATH #include "math/MathFunctions.h" #else #include <math.h> #endif int main(int argc, char *argv[]) { if (argc < 3){ printf("Usage: %s base exponent \n", argv[0]); return 1; } double base = atof(argv[1]); int exponent = atoi(argv[2]); #ifdef USE_MYMATH printf("Now we use our own Math library. \n"); double result = power(base, exponent); #else printf("Now we use the standard library. \n"); double result = pow(base, exponent); #endif printf("%g ^ %d is %g\n", base, exponent, result); return 0; }
编写 config.h.in 文件
注意 main.cc 的第一行,这里引用了一个 config.h 文件,这个文件预定义了 USE_MYMATH 的值。但我们并不直接编写这个文件,为了方便从 CMakeLists.txt 中导入配置,我们编写一个 config.h.in 文件,内容如下:#cmakedefine USE_MYMATH
这样 cmake 会自动根据 CMakeLists.txt 配置文件中的设置自动生成 config.h 文件。
参考
来源:CSDN
作者:咕唧咕叽
链接:https://blog.csdn.net/weixin_41541150/article/details/103568840