cmake基础教程(下)
针对更复杂的目录结构
再上一节的教程中,我们已经演示了如何优化目录结构来编译代码,下面我们展示一个更加复杂的目录并尝试构建项目。
build/ CMakeLists.txt src/ bin/
| | |
| | V
V | 存放生成的可执行文件
(用于执行cmake的目录) V
CMakeLists.txt main.cpp dir1/ dir2/ (和dir1/目录结构一样,有b.cpp)
| |
| V
| a.cpp a.h CMakeLists.txt
V
main函数所在的函数
会使用到a.cpp和 b.cpp实现的函数
观察该目录结构,顶层目录有一个CMakeLists.txt,他应该继续执行 src/ 层的 CMakeLists.txt 然后执行 dir1/ 和 dir2/ 层的 CMakeLists.txt 。因为 main.cpp 中调用 a.cpp 和 b.cpp 中实现的函数,我们这里将 dir1/ 和 dir2/ 下的源码编译为静态库,再链接到 main.cpp 生成的可执行文件中。下面看一下四个CMakeLists.txt怎么编写:
- 顶层的CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
PROJECT(TEST3)
# 添加子目录,会在该子目录中寻找CMakeLists.txt继续执行
ADD_SUBDIRECTORY(src)
- src/层的CMakeLists.txt
# CMake的最低版本号需求
cmake_minimum_required (VERSION 2.8)
# 将main.cpp的值赋给SRC_LIST
SET(SRC_LIST main.cpp)
# 添加头文件路径
INCLUDE_DIRECTORIES(dir1)
INCLUDE_DIRECTORIES(dir2)
# 添加子目录,会执行子目录的CMakeLists.txt
ADD_SUBDIRECTORY(dir1)
ADD_SUBDIRECTORY(dir2)
# 生成可执行文件Test
ADD_EXECUTABLE(Test ${SRC_LIST})
# 链接可执行文件所需要的库(test1和test2)
TARGET_LINK_LIBRARIES(Test test1 test2)
# 将可执行文件安装到顶层同级的bin目录下
INSTALL(TARGETS Test DESTINATION ${PROJECT_SOURCE_DIR}/bin)
这里注意,我们在使用静态库或者动态库的时候,除了需要库文件以外,还需要头文件,所以这里我们还需要把头文件所在的目录添加进来。
- dir1/ 和 dir2/ 层的CMakeLists.txt(这里给出的是 dir1/ , dir2/ 与之类似)
# 加载所有的源码到变量DIR_SRCS中 (这里作用和 SET(DIR_SRCS a.c) 一样 )
AUX_SOURCE_DIRECTORY(. DIR_SRCS)
# 将代码编译为静态库,供上一层的CMakeLists.txt使用
# 如若想编译为动态库, 则使用 ADD_LIBRARY(test1 SHARED ${DIR_SRCS})
ADD_LIBRARY(test1 ${DIR_SRCS})
1. INCLUDE_DIRECTORIES
添加找寻头文件的目录
2. TARGET_LINK_LIBRARIES
用于将指定的动态库或者静态库链接到指定的可执行文件
3. ADD_LIBRARY
用于将源文件生成动态库或者静态库
构建项目
进入到 build 目录中,执行以下命令即可成功构建项目。
cmake ..
make
make install
使用源码来编译
刚刚编译的方式是将子目录下的文件编译为静态库来连接到可执行文件中,那我们可以通过源码直接编译吗?答案当然是肯定的,对于原先那个工程,我们现在所需的CMakeLists结构如下:
build/ CMakeLists.txt src/ bin/
| | |
| | V
V | 存放生成的可执行文件
(用于执行cmake的目录) V
CMakeLists.txt main.cpp dir1/ dir2/ (和dir1/目录结构一样,有b.cpp)
| |
| V
| a.cpp a.h
V
main函数所在的函数
会使用到a.cpp和 b.cpp实现的函数
dir1/ 和 dir2/ 下面不需要CMakeLists.txt文件了,顶层的CMakeLIsts.txt的编写和上一个版本的编写是相同的,我们这里不重复给出,下面看一下 src/ 层的 CMakeLIsts.txt 的编写:
# CMake的最低版本号需求
cmake_minimum_required (VERSION 2.8)
# 将main.cpp的值赋给SRC_LIST
SET(SRC_LIST main.cpp)
# 将dir1和dir2的值赋给SUB_DIR_LIST
SET(SUB_DIR_LIST "dir1" "dir2")
# 遍历所有的子目录
foreach(SUB_DIR ${SUB_DIR_LIST})
#将对应子目录的源文件加入到SRC_LIST中
AUX_SOURCE_DIRECTORY(${SUB_DIR} SRC_LIST)
endforeach()
# 添加头文件路径
INCLUDE_DIRECTORIES(dir1)
INCLUDE_DIRECTORIES(dir2)
# 生成可执行文件Test
ADD_EXECUTABLE(Test ${SRC_LIST})
# 将可执行文件安装到顶层同级的bin目录下
INSTALL(TARGETS Test DESTINATION ${PROJECT_SOURCE_DIR}/bin)
foreach() … endforeach()
用于遍历一个列表里的所有变量
AUX_SOURCE_DIRECTORY
找在某个路径下的所有源⽂件
构建项目
进入到 build 目录中,执行以下命令即可成功构建项目。
cmake ..
make
make install
将工程打包为动态库
以上我们演示了如何将工程编译为可执行文件,但有些时候,我们希望将代码打包为动态库以便提供给其他人使用。同时,我们之前并没有去区分编译出的文件是release版本还是debug版本,这里我们希望能指定编译的版本,并且将对应版本的动态库放置到对应的目录下。现在的目录结构如下:
a.cpp a.h build/ Debug/ Release/ CMakeLists.txt
| |
| V
V 存放release版本的动态库
存放debug版本的动态库
下面看一下如何编写 CMakeLists.txt 来实现我们的需求
cmake_minimum_required(VERSION 2.8s)
PROJECT(TEST4)
# 设置得到的是realse版本还是debug版本(默认一般是debug)
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
SET(BuildType "Relaese")
else()
SET(BuildType "Debug")
endif()
#设置生成的so动态库的目录
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/${BuildType})
# 增加-fPIC的编译选项
ADD_COMPILE_OPTIONS(-fPIC)
# 获取当前目录下的所有源文件
AUX_SOURCE_DIRECTORY(. DIR_LIB_SRCS)
# 生成动态库
ADD_LIBRARY (test SHARED ${DIR_LIB_SRCS})
这里注意 CMAKE_BUILD_TYPE 和 LIBRARY_OUTPUT_PATH 是Cmake提供的两个变量用于确定cmake的编译模式和库输出的路径,而非DIR_LIB_SRCS 这种我们自己定义的变量。
构建项目生成动态库
默认生成Debug版本的动态库,进入build 目录执行以下命令
cmake .. # 或者 cmake -DCMAKE_BUILD_TYPE=Debug ..
make
执行完会发现会生成一个Debug目录,下面有一个 libtest.so 动态库.
欲生成Release版本的动态库,进入build执行以下命令
cmake -DCMAKE_BUILD_TYPE=Release ..
make