add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
这个指令用于向当前的工程添加存放源文件的目录,并可以指定中间二进制和目标二进制存放的位置。 EXCLUDE_FROM_ALL参数的含义是将这个目录从编译的过程中排除,比如,工程中的example,可以就需要工程构建完成后,再进入example目录单独进行构建。
有这样一种情况。自己写了一个库,需要写测试程序。类似如下结构
hello-world/
├── CMakeLists.txt
├── main.c
├── test
│ ├── CMakeLists.txt
│ └── main.c
├── hello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── world
├── CMakeLists.txt
├── world.c
└── world.h
hello/ 目录生成 libhello.so,world/ 目录生成 libworld.so,test/ 目录存储测试程序,测试上述两个库功能是否正常。请注意 test/ 与 hello/ 和 world/ 的目录层级关系。我们只关注 test/CMakeLists.txt 文件。第一反应,是这么写:
cmake_minimum_required(VERSION 3.5)
project(test C)
#库目录
set(TOP_DIR ${CMAKE_CURRENT_LIST_DIR}/../)
add_subdirectory(${TOP_DIR}/hello)
add_subdirectory(${TOP_DIR}/world)
add_executable(${PROJECT_NAME} main.c)
target_link_libraries(${PROJECT_NAME} PRIVATE hello)
target_link_libraries(${PROJECT_NAME} PRIVATE world)
target_include_directories(${PROJECT_NAME} PRIVATE ${TOP_DIR}/hello)
target_include_directories(${PROJECT_NAME} PRIVATE ${TOP_DIR}/world)
编译结果:
-- The C compiler identification is GNU 5.3.1
-- 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
CMake Error at CMakeLists.txt:10 (add_subdirectory):
add_subdirectory not given a binary directory but the given source
directory "/home/sdc/pro/hello-world/hello" is not a subdirectory of
"/home/sdc/pro/hello-world/test". When specifying an out-of-tree source a
binary directory must be explicitly specified.
CMake Error at CMakeLists.txt:11 (add_subdirectory):
add_subdirectory not given a binary directory but the given source
directory "/home/sdc/pro/hello-world/world" is not a subdirectory of
"/home/sdc/pro/hello-world/test". When specifying an out-of-tree source a
binary directory must be explicitly specified.
-- Configuring incomplete, errors occurred!
See also "/home/sdc/pro/hello-world/test/build/CMakeFiles/CMakeOutput.log".
add_subdirectory 发生错误。
错误原因: hello/ 目录不是 test/ 的子目录。
解决方法: 显式指定 binary directory。
在使用 add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])命令时,如果 source_dir 不是当前目录(CMakeLists.txt 所在目录,例子中的 test/ 目录)的子目录,那么就需要显式指定 [binary_dir] 参数,用于存储 source_dir 相关文件。
修改CMakeLists.txt 文件中的 add_subdirectory()命令为如下方式即可:
#指定 [binary_dir] 参数
add_subdirectory(${TOP_DIR}/hello hello_binary_dir)
add_subdirectory(${TOP_DIR}/world world_binary_dir)
**说明:**例子中的 hello/ 和world/ 目录与 test/ 目录是平级关系。实际上,只要不是上下级关系(比如,hello/ 和 world/ 目录在其他目录下或者是 test/ 目录的上级),在使用 add_subdirectory() 时都需要指定 [binary_dir] 参数。
、从“Hello, world!”开始
了解cmake的基本原理并在系统中安好cmake后,我们就可以用cmake来演示那个最经典的”Hello, world!”了。
第一步,我们给这个项目起个名字——就叫HELLO吧。因此,第一部为项目代码建立目录hello,与此项目有关的所有代码和文档都位于此目录下。
第二步,在hello目录下建立一个main.c文件,其代码如下:
#include
int main(void)
{
printf("Hello,World\n");
return 0;
}
至此,整个hello项目就已经构建完毕,可以进行编译了。
第三步,在hello目录下建立一个新的文件CMakeLists.txt,它就是 cmake所处理的“代码“。其实,使用cmake管理项目本身也是在编程,所以称之为“代码(或脚本)”并不为过。在CMakeLists.txt文件中输入下面的代码(#后面的内容为代码行注释):
#cmake最低版本需求,不加入此行会受到警告信息
#cmake最低版本需求,不加入此行会受到警告信息
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
#项目名称
PROJECT(HELLO)
#把当前目录(.)下所有源代码文件和头文件加入变量SRC_LIST
AUX_SOURCE_DIRECTORY(. SRC_LIST)
#生成应用程序 hello (在windows下会自动生成hello.exe)
ADD_EXECUTABLE(hello ${SRC_LIST})
第四步,编译项目。为了使用外部编译方式编译项目,需要先在目录hello下新建一个目录build(也可以是其他任何目录名)。现在,项目整体的目录结构为:
hello/
|– CMakeLists.txt
|– build /
|– main.c
在windows下,cmake提供了图形界面,设定hello为source目录,build为二进制目录,然后点击configure即可开始构建,之后进入build目录运行make命令编译。
在linux命令行下,首先进入目录build,然后运行命令(注:后面的“..”不可缺少):
该命令使cmake检测编译环境,并生成相应的makefile。接着,运行命令make进行编译。编译后,生成的所有中间文件和可执行文件会在build目录下。 下面是我在ubuntu上的运行过程:
-- Configuring done
-- Generating done
-- Build files have been written to: /home/zc/fs4412/train/lianXunFactory/a10Cmake/HELLO/hello/build
1
ls
CMakeCache.txt CMakeFiles cmake_install.cmake Makefile
2
make
Scanning dependencies of target hello
[ 50%] Building C object CMakeFiles/hello.dir/main.c.o
[100%] Linking C executable hello
[100%] Built target hello
3
ls
CMakeCache.txt CMakeFiles cmake_install.cmake hello Makefile
4
./hello
Hello,World
第一个问题:上面,我们提到了一个名词,叫外部编译方式。其实,cmake还可以直接在当前目录进行编译,无须建立build目录。但是,这种做法会将所有生成的中间文件和源代码混在一起,而且cmake生成的makefile无法跟踪所有的中间文件,即无法使用”make distclean”命令将所有的中间文件删除。因此,我们推荐建立build目录进行编译,所有的中间文件都会生成在build目录下,需要删除时直接清空该目录即可。这就是所谓的外部编译方式。
第二个问题: cmake 的手册详解:http://www.cnblogs.com/coderfenghc/archive/2012/06/16/CMake_ch_01.html
第三个问题:在Linux中使用cmake 构建应用程序: http://www.ibm.com/developerworks/cn/linux/l-cn-cmake/
CMake 是一个跨平台的自动化建构系统,它使用一个名为 CMakeLists.txt 的文件来描述构建过程,可以产生标准的构建文件,如 Unix 的 Makefile 或Windows Visual C++ 的 projects/workspaces 。文件 CMakeLists.txt 需要手工编写,也可以通过编写脚本进行半自动的生成。CMake 提供了比 autoconfig 更简洁的语法。在 linux 平台下使用 CMake 生成 Makefile 并编译的流程如下:
编写 CmakeLists.txt。
执行命令“cmake PATH”或者“ccmake PATH”生成 Makefile ( PATH 是 CMakeLists.txt 所在的目录 )。
使用 make 命令进行编译。