建议直接看 二、项目构建
一、常用命令解释
下面用的是 C 语言的注释,实际编写 CMakeLists.txt 时不要把注释也写上了。
1.PROJECT() 关键字
用来指定工程的名字和支持的语言,默认支持所有语言。
PROJECT(HELLO) //指定了工程的名字,并且按默认支持所有语言
PROJECT(HELLO CXX) //指定了工程的名字,并且支持语言是C++
PROJECT(HELLO C CXX) //指定了工程的名字,并且支持语言是 C和C++
2.SET() 关键字
1)用来显示的指定变量的
SET(SRC_LIST hello.c) //SRC_LIST 变量包含了 hello.c
SET(SRC_LIST1 1.c 2.c 3.c) //多个包含就这样写,中间用空格隔开
2)更改二进制的保存路径
SET 指定重新定义 EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH 变量 来指定最终的目标二进制的位置
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
3.MESSAGE() 关键字
向终端输出用户自定义信息
主要包含三种:
SEND_ERROR //产生错误,生成过程被跳过
STATUS //输出前缀为--的信息。 eg: ---- This is BINARY dir/home/pl/Desktop/LinuxCode/CMake/simpledemo
FATAL_ERROR //立即终止所有 cmake 过程
4.ADD_EXECUTABLE() 关键字
生成可执行文件
ADD_EXECUTABLE(hello ${SRC_LIST}) //生成的可执行文件名为 hello,源文件读取变量 SRC_LIST 中的内容。
//也可以直接把 SRC_LIST 中的文件,直接写过来,而不用SRC_LIST变量。
PROJECT(HELLO)中指定是工程文件名,和这个生成的可执行文件名 hello 没有任何关系。
5.ADD_SUBDIRECTORY() 关键字
用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置,语法如下:
ADD_SUBDIRECTORY(source_dir [binary_dir][EXCLUDE_FROM_ALL])
EXCLUDE_FROM_ALL函数是将写的目录从编译中排除,
ADD_SUBDURECTORY(src bin)
将 src子目录加入工程,并指定编译输出(包含编译中间结果)路径为 bin目录
如果不进行 bin目录指定,那么编译结果(包含编译中间结果)都将存放在 build/src目录
7.INSTALL() 关键字 //用于安装 工程相关文件
INSTALL(FILES COPYRIGHT README DESTINATION testcmake/install/cmake/) //安装 项目工程相关文件
INSTALL(PROGRAMS runhello.sh DESTINATION testcmake/install/cmake/bin) //安装项目工程相关 可执行程序
INSTALL(DIRECTORY doc/ DESTINATION testcmake/install/cmake/doc) //安装项目工程相关 文件夹下所有内容
FILES :指定要安装的文件名
DESTINATION :指定目标安装路径
路径有两种:
1)相对路径
实际为 ${CMAKE_INSTALL_PREFIX}/<DESTINATION>
CMAKE_INSTALL_PREFIX 默认为 /usr/local/
cmake -DCMAKE_INSTALL_PREFIX = /usr //在cmake的时候指定CMAKE_INSTALL_PREFIX 变量的路径
2)绝对路径
推荐这个,不容器出错。
PROGRAMS :非目标文件的可执行程序安装(比如脚本之类)
DIRECTORY :指定要安装的文件夹下的所有内容
注意 doc/ //:代表将doc文件夹下的内容安装到 目标安装路径
doc //:代表将目录名 doc 安装到目标安装路径
8.安装方法:
1)从代码编译后直接make install //就跟安装cmake时的方法是一样的,
路径由上面INSTALL 关键字在CMakeLists.txt中指定。
2)安装时时指定目录安装:
简单: make install DESTDIR=/tmp/test
复杂: ./configure -prefix=/usr
9.静态库和动态库
静态库:扩展名一般为".a" 或 ".lib"
在编译时会直接整合到目标程序中,编译成功的可执行文件独立运行。
动态库:扩展名一般为".so"或".dll"
在编译时不会放到连接的目标程序中,即可执行文件不能独立运行。
10.ADD_LIBRARY() 关键字
用来生成 库文件
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
hello :正常的库名,生成的 名字前面会【自动加上 lib】, 最终产生的文件为 libhello.so
SHARED :动态库
STATIC :静态库
${LIBHELLO_SRC} :变量,指代源文件
11.SET_TARGET_PROPERTIES() 关键字
这条指令可以用来设置输出的名称,使用方法看 13.
对于动态库,还可以指定动态库版本和 API版本:
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
VERSION :指代动态库版本
SOVERSION:指代API版本
12.同时构建同名的静态库和动态库
SET(SRC_LIST 1.c 2.c 3.c)
ADD_LIBRARY(hello_static STATIC ${SRC_LIST})
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello") //对hello_static 重命名为 hello
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) //cmake在构建新的target时 会尝试清掉其他使用这个名字的库, 在构建下面 libhello.so时 会清理掉 libhello.a
ADD_LIBRARY(hello_so SHARED ${SRC_LIST})
SET_TARGET_PROPERTIES(hello_so PROPERTIES OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello_so PROPERTIES CLEAN_DIRECT_OUTPUT 1)
13.安指定共享库和头文件安装位置
其实就是将头文件安装到lib 或 lib64 文件夹。
INSTALL(FILES hello.h DESTINATION /usr/include/hello) //安装头文件,DESTINATION 后跟绝对路径
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION /usr/lib ARCHIVE DESTINATION /usr/lib) //安装动态库和静态库文件到 lib位置
14.指定引用头文件位置 和 静动态库文件位置
一般默认把头文件安装到 /usr/include/ 文件夹下
如果安装到其他文件夹下,那就应该使用如下命令在使用cmake编译时包含该路径,包含方法如下:
INCLUDE_DIRECTORIES(/usr/include/hello) //包含头文件方法 这个一定在 ADD_EXECUTABLE() 之前
TARGET_LINK_LIBRARIES(test /usr/lib/libhello.so) //包含 动、静态库文件,这个一定在 ADD_EXECUTABLE() 之后
15.ADD_DEFINITIONS() 关键字
用来添加参数
ADD_DEFINITIONS(
-O3 -g -W -Wall -lpthread
-Wunused-variable -Wunused-parameter -Wunused-function -Wunused
-Wno-deprecated -Woverloaded-virtual -Wwrite-strings
-D__WUR= -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DTIXML_USE_STL
)
16.cmake_minimum_required(VERSION 3.23)
用来指定cmake向下兼容的最低版本。cmake --vsersion 查看。
cmake_minimum_required(VERSION 3.23)
99.CMake自带的变量
<projectname>_BINARY_DIR //指向该工程二进制编译所在目录
<projectname>_SOURCE_DIR //指向该工程源文件所在目录
100.基本语法规则
1)变量的使用:① ${} 方式取值
② IF 控制语句中直接使用变量名
2)指定多个参数时,用 空格或分号 分开 eg:ADD_EXECUTABLE(hello 1.c 2.c 3.c)
3)指令 是大小写无关的,参数和变量 是大小写相关的。 推荐全部大写。
4)语法注意事项
①如果文件名叫 h ello.c // h e中间有空格
你就要加引号,写成 SET(SRC_LIST "h ello.c")
②文件的后缀可以不写,但是如果有重名不同后缀的会报错。
eg: ADD_EXECUTABLE(hello 1 2 3.c) //若文件夹只存在1.c 2.c 就不会报错
//若文件夹存在1.cpp 1.c 那就会出错
二、构建项目教程
-
项目的目录结构如下所示,包括静态库和动态库项目,同时也包括一个测试项目
. ├── bin │ └── test1 ├── CMakeLists.txt ├── include │ └── apple.h ├── lib │ ├── liblearn.a │ ├── liblearn.so -> liblearn.so.1 │ ├── liblearn.so.1 -> liblearn.so.1.0 │ └── liblearn.so.1.0 ├── src │ ├── apple.cpp │ └── CMakeLists.txt └── test ├── CMakeLists.txt └── main.cpp 5 directories, 11 files #bin 可执行文件的生成目录, #lib 链接库文件的生成目录, #include 头文件所在目录, #src 源代码文件所在目录, #test 测试程序源代码所在目录。
-
根目录 CMakeList.txt
cmake_minimum_required(VERSION 3.5) project( cmake_learn ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") add_subdirectory( src ) add_subdirectory( test )
-
src 目录 CMakeList.txt
# 搜集所有在指定路径下的源文件的文件名,将输出结果列表储存在指定的变量中。 aux_source_directory(. SOURCE_FILES ) # 或者使用下面这种方式。 #set( SOURCE_FILES # apple.cpp # orage.cpp ) # 添加包含目录,CMake将在这些目录寻找 .cpp 文件中引用到的头文件。 include_directories( ${PROJECT_SOURCE_DIR}/include ) # 指定编译后的库文件的输出路径。 set( LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib ) # 生成目标动态库。 add_library( learn SHARED ${SOURCE_FILES} ) # 生成目标静态库。 add_library( learn_static STATIC ${SOURCE_FILES} ) # 指定静态库的输出名称。 set_target_properties( learn_static PROPERTIES OUTPUT_NAME "learn" ) # 允许静态库与动态库同时存在。 set_target_properties( learn PROPERTIES CLEAN_DIRECT_OUTPUT 1 ) set_target_properties( learn_static PROPERTIES CLEAN_DIRECT_OUTPUT 1 ) # 指定动态库的版本: # VERSION 动态库版本; # SOVERSION API的版本。 set_target_properties( learn PROPERTIES VERSION 1.0 SOVERSION 1 )
-
test 目录 CMakeList.txt
# 搜集所有在指定路径下的源文件的文件名,将输出结果列表储存在指定的变量中。 aux_source_directory(. SOURCE_FILES )# 添加包含目录,CMake将在这些目录寻找 .cpp 文件中引用到的头文件。 include_directories( ${PROJECT_SOURCE_DIR}/include ) # 指定编译后的可执行程序的输出路径。 set( EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin ) # 指定生成可执行程序。 add_executable( test1 ${SOURCE_FILES} ) # 添加链接库目录,CMake将在如下如目录中查找所链接的外部库。 link_directories( ${PROJECT_SOURCE_DIR}/lib ) # 指定链接库。 target_link_libraries( test1 learn )
-
按上面步骤配置完成后VSCode的Cmake工具会自动生成build文件夹,然后直接进入build文件夹执行make命令即可。
生产的静态库与动态库都按预期出现在了 lib 目录中, make生成的可执行文件也 生成在了 bin 目录中。
三、库构建及安装
-
一般CMake项目文件结构说明
src #文件夹,存放项目源代码文件 build #文件夹,存放编译文件,一般在该文件夹内执行 cmake .. 及 make 命令 doc #文件夹,存放项目文档 不需要不创建就行了 CMakeLists.txt #文件, CMake命令集 README #文件, 项目基础说明 不需要不创建就行了 runhello.sh #文件, 项目脚本 不需要不创建就行了 COPYRIGHT #文件, 项目版权文件 不需要不创建就行了 src 中 CMakeLists.txt文件 #CMake命令集
-
一般CMake构建静、动态库项目文件结构说明
build #文件夹,存放编译文件,一般在该文件夹内执行 cmake .. 及 make 命令 lib #文件夹,存放构建动静态的源文件 CMakeLists.txt #文件, CMake命令集 lib中 CMakeLists.txt文件 #CMake命令集
-
内部构建项目文件结构及CMakeLists.txt语句
PROJECT(HELLO) SET(SRC_LIST hello.c) //设置变量 MESSAGE(STATUS "This is BINARY dir" ${HELLO_BINARY_DIR}) //打印信息 MESSAGE(STATUS "This is SOURCE dir" ${HELLO_SOURCE_DIR}) ADD_EXECUTABLE(hello ${SRC_LIST}) //执行
-
外部构建可安装项目文件结构及CMakeLists.txt语句
外面的CMakeLists.txt内容: PROJECT(HELLO_PROJECT) ADD_SUBDIRECTORY(src bin) INSTALL(FILES COPYRIGHT README DESTINATION testcmake/install/cmake/) //安装文件 INSTALL(PROGRAMS runhello.sh DESTINATION testcmake/install/cmake/bin) //安装脚本 INSTALL(DIRECTORY doc/ DESTINATION testcmake/install/cmake/doc) //安装文件夹中所有内容 src内部的CMakeLists.txt内容: SET(SRC_LIST hello.c) ADD_EXECUTABLE(hello ${SRC_LIST}) //生成
-
外部构建动、静态库文件结构及CMakeLists.txt语句
外面的CMakeLists.txt内容: PROJECT(HELLO) ADD_SUBDIRECTORY(lib bin) lib内部的CMakeLists.txt内容: SET(SRC_LIST hello.c) //构建静态库 ADD_LIBRARY(hello_static STATIC ${SRC_LIST}) SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello") SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) //避免不能构建下面同名的动态库 //构建动态库 ADD_LIBRARY(hello_so SHARED ${SRC_LIST}) SET_TARGET_PROPERTIES(hello_so PROPERTIES OUTPUT_NAME "hello") SET_TARGET_PROPERTIES(hello_so PROPERTIES CLEAN_DIRECT_OUTPUT 1) //安装上面构建的静、动态库 INSTALL(FILES hello.h DESTINATION /usr/include/hello) INSTALL(TARGETS hello_static hello_so LIBRARY DESTINATION /usr/lib ARCHIVE DESTINATION /usr/lib)