文章目录
- 概述
- 编译最简单的hello world
- 编译工程化的helloWorld
- 更工程化的Hello World: 构建静态库与动态库
- 如何使用外部共享库和头文件
- 其他有用的cmake命令
- include_directories
- find_package
- ` file(GLOB variable [RELATIVE path] [globbing expressions]...)`
- windows 下 C++开发中的cmake
- 问题
概述
本文为《cmake practice》的个人笔记。
注意,如果仅仅使用qt编程的话,没必要使用cmake,因为qmake已经足够专业。
cmake的正常使用顺序:
- 找一个合适的位置,mkdir build & cd build (也就是 out-of-source build)
- cmake … (…代表的是父目录,也就是cmakelists所在的路径)
- make
注意,清理工程的命令为: make clean
编译最简单的hello world
工程结构:
CMakeLists.txt中的内容:
PROJECT(HELLO)
SET(SRC_LIST main.c)
MESSAGE(STATUS "This is BINARY dir" ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir" ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
- 注意SRC_LIST 外面需要加上
${}
。这是cmake的语法,变量会需要这样去取值。但是后续需要注意的是,在IF语句中会直接使用变量名。
在进行常规cmake和make操作后,在build文件夹中就会出现目标文件 hello.o,可以直接用于运行。
如果想要看到具体的make信息,可以输入 make VERBOSE=1
。
1. PROJECT(projectname [CXX] [C] [Java])
用于定义工程名称,默认情况下支持所有语言。该指令运行的同时,隐式地定义了两个cmake变量,即<projectname>_BINARY_DIR
以及<projectname>_SOURCE_DIR
。注意,通过外部编译进行工程构建,HELLO_SOURCE_DIR 仍然指代工程路径,即
/backup/cmake/t1而 HELLO_BINARY_DIR 则指代编译路径,即/backup/cmake/t1/build。
2. SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
显式定义变量
3. MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)
向终端输出用户定义的信息:
- SEND_ERROR,产生错误,生成过程被跳过;
- SATUS,输出前缀为—的信息;
- FATAL_ERROR,立即终止所有 cmake 过程
4. ADD_EXECUTABLE(hello ${SRC_LIST})"
生成一个文件名为 hello 的可执行文件。
相关的源文件是 SRC_LIST 中定义的源文件列表。
编译工程化的helloWorld
新建src文件夹,在src文件夹中放入main.c文件,且新建一个cmakelists,内容是:ADD_EXECUTABLE(hello main.c)
。
而后,跳出src文件夹,再新建一个cmakelists,内容是:
PROJECT(HELLO) ADD_SUBDIRECTORY(src bin)
。
我们就可以惊奇的发现,编译后的hello文件竟然在build/bin文件夹下。
而能够实现这种惊奇的命令就是: ADD_SUBDIRECTORY
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
这个命令用于向当前工程添加存放源代码的子目录,且可以指定中间二进制以及目标二进制存放的位置。
所谓EXECLUDE_FROM_ALL
参数的含义是将该目录从编译过程中排除掉,举个例子,工程里的example,往往需要工程构建完后,再进到example目录里面单独编译。
ADD_SUBDIRECTORY(src bin)
做的事情就是,在编译时将src重命名为bin,并将中间结果与目标二进制放到bin里面。
此时的目录结构为:
实际上,我们还可以通过SET
指令重新定义 EXECUTABLE_OUTPUT_PATH
和LIBRARY_OUTPUT_PATH
来仅仅指定目标二进制输出的位置,注意,此时不包含编译生成的中间文件。
具体为:
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
更工程化的Hello World: 构建静态库与动态库
如何使用外部共享库和头文件
其他有用的cmake命令
include_directories
find_package
我们可以通过find_package
引入其他cmake编译安装的库。
file(GLOB variable [RELATIVE path] [globbing expressions]...)
file(GLOB variable [RELATIVE path] [globbing expressions]...)
file(GLOB_RECURSE variable [RELATIVE path] [FOLLOW_SYMLINKS] [globbing expressions]...)
GLOB选项将会为所有匹配查询表达式的文件生成一个文件list,并将该list存储进变量variable里。
文件名查询表达式与正则表达式类似,只不过更加简单。
如果为一个表达式指定了RELATIVE标志,返回的结果将会是相对于给定路径的相对路径。
文件名查询表达式的例子有:
*.cxx - 匹配所有扩展名为cxx的文件。
*.vt? - 匹配所有扩展名是vta,…,vtz的文件。
f[3-5].txt - 匹配文件f3.txt, f4.txt, f5.txt。
GLOB_RECURSE选项将会生成一个类似于通常的GLOB选项的list,只是它会寻访所有那些匹配目录的子路径并同时匹配查询表达式的文件。
参考文献:https://www.cnblogs.com/coderfenghc/archive/2012/07/08/2581734.html
windows 下 C++开发中的cmake
通常来说,在windows开发的时候,cmakelist写完了生成sln。
往往还是会选择用visual studio 而不是 visual studio code 来进行开发。
调用第三方库的时候,一定要问清楚自己以下几点:
- 是不是正确include了?
- 是不是正确链接 lib库了?
- dll有没有放到跟exe同级的目录下,或者直接编到系统库上?
- 到底是x86还是x64,有没有搞错这里。
问题
- cmakelists如何同时链接debug库和release库?