windows--cmake语法讲解
前言
继上篇cmake实战演练后,初步掌握了通过cmake构建多工程的技能,但是cmake还有许多语法规则未掌握,今天继续学习下语法规则。
链接: 上一篇:cmake实战1
camke进一步理解:
cmake允许开发者编写一种平台无关的CMakeLists.txt文件来制定整个编译流程,然后再根据目标用户的平台进一步生成所需要的Makefile和工程文件,如Unix的Makefile或Windows的vs工程。从而做到"write once , run everywhere"。显然,cmake是一个比上述几种make更高级的编译配置工具。一些使用cmake作为项目架构的知名开源项目有 VTK,ITK,KDE,OpenCV,OSG等。
在linux平台上使用cmake生成Makefile并编译的流程如下:
- 编写CMake配置文件 CMakeLists.txt
- 执行命令cmake PATH 或者ccmake PATH 生成Makefile (ccmake提供了一个交互式界面)。其中,PATH是CMakeLists.txt所在目录。
- 使用make命令进行编译。
或许见过好几种Make工具,例如,QT的,微软的,,等等。这些Make工具遵循着不同的规范和标准,所执行的Makefile格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的Make工具,就得为每一种标准写一次Makefile,这将是一件让人抓狂的工作。
cmake就是针对上面问题所设计的工具。
一、cmake语法
-
1.PROJECT
PROJECT(hello) 项目名称。此时会自动生成一些变量-- {PROJECT_NAME};
-
2.CMAKE_MINIMUM_REQUIRED
CMAKE_MINIMUM_REQUIRED(VERSION 2.10) 限定cmake最低版本;
-
3.AUX_SOURCE_DIRECTORY
AUX_SOURCE_DIRECTORY(< dir > < avariable >) 例 :AUX_SOURCEZ_DIRECTORY(. DIR_SRCS),将当前目录中的源文件名称赋值给变量 {DIR_SRCS};
-
4.ADD_SUBDIRECTORY
ADD_SUBDIRECTORY(dir) 添加子文件夹dir;
-
5.SET
SET(SOURCES src/Hello.cpp src/main.cpp) 创建变量${SOURCES},包含了这些cpp文件。注:set只能分批设置具体的一个文件,不能设置*.cpp或*.h这样的文件;
SET(CMAKE_CXX_STANDARD 11) 设置c++标准;
SET(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/bin") 将库文件输出到根目录下的bin文件夹里
-
6.ADD_EXECUTABLE
ADD_EXECUTABLE(main SOURCES) 将${SOURCES}中包含的源文件编译生成名为main的可执行文件;
-
7.ADD_LIBRARY
ADD_LIBRARY(hello_lib STATIC src/hello.cpp) 从指定的源文件创建一个库。默认生成在构建文件夹; STATIC 表示创建静态库,windows下静态库名称为hello_lib.a,linux下静态库名称为hello_lib.a; SHARED 表示创建动态库,windows下静态库名称为hello_lib.dll,linux下静态库名称为hello_lib.so;
-
8.TARGET_LINK_LIBRARIES
TARGET_LINK_LIBRARIES(main hello_lib) 指明可执行文件main需要连接名为hello_lib的链接库,添加链接库;
-
9.TARGET_INCLUDE_DIRECTORYS
TARGET_INCLUDE_DIRECTORYS(hello_lib PUBLIC ${PROJECT_SOURCE_DIR}/include 添加了一个目录,这个目录是库所包含的头文件的目录,并设置库属性为public;
-
10.MESSAGE
MESSAGE(STATUS "is printing.....") 将字符串输出到终端。STATUS 为级别,ERROR、FATAL等;
-
11.FIND_PATH
FIND_PATH(< var > name1 [path1 path2...]) 该命令在参数path指示的目录中查找文件name1,并将查找到的路径保存在变量VAR中;
-
12.FIND_LIBRARY
FIND_LIBRARY(< var > name1 [path1 path2...]) 用于查找链接库并将结构保存在变量中;
-
13.include_directories
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...]) 将指定目录添加到编译器的头文件搜索路径之下,指定目录被解释为当前源码路径的相对路径。 [AFTER|BEFORE]定义了追加指定目录的方式在头还是尾。 [SYSTEM]告诉编译器在一些平台上指定目录被当作系统头文件目录。
-
14.find_package
共支持两种模式 mode1: Module, 此模式需访问Find<PackageName>.cmake文件 find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [[COMPONENTS] [components...]] [OPTIONAL_COMPONENTS components...] [NO_POLICY_SCOPE]) mode2: Config, 此模式需访问<lowercasePackageName>-config.cmake or <PackageName>Config.cmake find_package(<PackageName> [version] [EXACT] [QUIET] [REQUIRED] [[COMPONENTS] [components...]] [OPTIONAL_COMPONENTS components...] [CONFIG|NO_MODULE] [NO_POLICY_SCOPE] [NAMES name1 [name2 ...]] [CONFIGS config1 [config2 ...]] [HINTS path1 [path2 ... ]] [PATHS path1 [path2 ... ]] [PATH_SUFFIXES suffix1 [suffix2 ...]] [NO_DEFAULT_PATH] [NO_PACKAGE_ROOT_PATH] [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH] [NO_SYSTEM_ENVIRONMENT_PATH] [NO_CMAKE_PACKAGE_REGISTRY] [NO_CMAKE_BUILDS_PATH] # Deprecated; does nothing. [NO_CMAKE_SYSTEM_PATH] [NO_CMAKE_SYSTEM_PACKAGE_REGISTRY] [CMAKE_FIND_ROOT_PATH_BOTH | ONLY_CMAKE_FIND_ROOT_PATH | NO_CMAKE_FIND_ROOT_PATH]) find_package一般用于加载外部库到项目中,并且会加载库的细节信息。如上find_package有两种模式:Module与Config。
二、Cmake常用变量
- CMAKE_BINARY_DIR:
如果是 in source 编译,指得就是工程顶层目录,如果是 out-of-source 编译,指的是工程编译发生的目录。
- PROJECT_BINARY_DIR
同上。
- CMAKE_SOURCE_DIR
工程顶层目录。
- PROJECT_SOURCE_DIR
工程顶层目录。
- CMAKE_CURRENT_SOURCE_DIR
当前CMakeLists.txt所在目录。
- CMAKE_CURRENT_BINARY_DIR
如果是 in-source 编译,它跟 CMAKE_CURRENT_SOURCE_DIR 一致,如果是 out-of-source 编译,他指的是 target 编译目录。
使用我们上面提到的 ADD_SUBDIRECTORY(src bin)可以更改这个变量的值。
使用 SET(EXECUTABLE_OUTPUT_PATH <新路径>)并不会对这个变量造成影响,它仅仅修改了最终目标文件存放的路径。
- CMAKE_CURRENT_LIST_FILE
输出调用这个变量的 CMakeLists.txt 的完整路径
- CMAKE_CURRENT_LIST_LINE
输出这个变量所在的行
- CMAKE_MODULE_PATH
这个变量用来定义自己的 cmake 模块所在的路径。如果你的工程比较复杂,有可能会自己编写一些 cmake 模块,这些 cmake 模块是随你的工程发布的,
为了让 cmake 在处理CMakeLists.txt 时找到这些模块,你需要通过 SET 指令,将自己的 cmake 模块路径设置一下。
比如 SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),这时候你就可以通过 INCLUDE 指令来调用自己的模块了。
- EXECUTABLE_OUTPUT_PATH
用来重新定义EXE的存放目录
- LIBRARY_OUTPUT_PATH
用来重新定义库文件的存放目录
- PROJECT_NAME
项目名称
三、总结
学习路漫漫,持续搞起来!