在CMake 3.6 Documentation中,以命令行工具、GUI互动对话框、方法参考手册等方面介绍CMake。下面从自身脚本语法和配置工程两个方面了解CMake,但在这之前先熟悉一下如何执行脚本。
CMake命令行纲要
cmake [<options>] (<path-to-source> | <path-to-existing-build>)
cmake [(-D <var>=<value>)...] -P <cmake-script-file>
cmake --build <dir> [<options>...] [-- <build-tool-options>...]
cmake -E <command> [<options>...]
cmake --find-package <options>...
这里主要介绍下列选项,其他详见官方手册。
- 第二行语义表示执行一个CMake语法的脚本文件
-D <var>:<type>=<value>, -D <var>=<value> 可选的,创建缓存变量。 -P <cmake-script-file> 必须的,指定所需执行的脚本文件;如果使用了-D,则必须在-P之前指定。
注释以#为开始的。其他操作(赋值、比较等)全是以命令方式来执行的。
格式COMMAND(arg1, arg2, ...)
,命令不区分大小写,命令每个参数均以空格,或者分号分割。
set(who "World!")
message("Hello ${who}")
脚本名字一般xx.cmake比较好认,参考C:\Program Files\CMake\share\cmake-3.6\Modules下的脚本,如FindOpenSSL.cmake,将其命名为Hello.cmake。
执行:cmake -P Hello.cmake
输出:Hello world!
- 变量 无需声明,没有类型(只有字符串或字符串列表),区分大小写,作用域为脚本全局,在构建树会传播到子目录但不会污染父目录。
- 赋值命令 SET
set(<variable> <value>... [PARENT_SCOPE])
set(<variable> <value1> ... <valueN>)
:<variable>
is set to a semicolon separated list of values. set var as ;list
set(var "hello world!")
message(${var})
message("${var}")
set(var hello "world!")
message(${var})
message("${var}")
message(hello world!)
执行后输出:
hello world!
hello world!
helloworld!
hello;world!
helloworld!
可以看出第二处var被赋值为逗号分隔的字符串列表时,加与不加引号的变量输出差异(猜var={"hello", "world!"},参数为列表时相当于javascript中的message.apply(null, [argsArray])调用方式,也就是数组代替压栈传递参数,又或者像宏一样展开列表里的项作为参数;而加了引号则列表转为字符串ToString且固定为逗号分隔的字符串)。
注意:写路径时,如Windows上,需要双反斜杠:
#find_package(OpenSSL REQUIRED)
set(OPENSSL_INCLUDE_DIR "C:\\OpenSSL\\include")
set(OPENSSL_LIBRARIES "C:\\OpenSSL\\lib")
不然提示(不知为啥即使设置了OPENSSL_ROOT_DIR
并从Win32 OpenSSL安装了x86 x64的,find_package
就是找不到openssl库):
-- Looking for gethostbyname_r
-- Looking for gethostbyname_r - not found
CMake Error at CMakeLists.txt:678 (set):
Syntax error in cmake code at
I:/src/c/libevent/CMakeLists.txt:678
when parsing string
C:\OpenSSL\include
Invalid character escape '\O'.
-- Configuring incomplete, errors occurred!
See also "I:/src/c/libevent/build/CMakeFiles/CMakeOutput.log".
See also "I:/src/c/libevent/build/CMakeFiles/CMakeError.log".
# set(who "World!")
message(STATUS "Hello ${who}")
执行:cmake -P Hello.cmake -Dwho=World -P Hello.cmake
输出:
-- Hello
-- Hello world
注意,在-P
指定的脚本中使用到 who
变量,那必须让-D
在前,且-P脚本里变量创建和修改不会传播到另一个。
调用其他模块,如调用find_package,会调用其他模块脚本FindJava.cmake,并返回一些值。 模块的参数和返回值等具体使用描述可参考FindJava.cmake里的解释。
find_package(Java COMPONENTS Development)
message("Result Java_JAVA_EXECUTABLE: ${Java_JAVA_EXECUTABLE}")
message("Result Java_VERSION: ${Java_VERSION}")
message("Result Java_VERSION_STRING: ${Java_VERSION_STRING}")
message("Result Java_INCLUDE_DIRS: ${Java_INCLUDE_DIRS}")
一般说来find_package一些库等可能使用到一些变量,指定编译器、指定
这里根据爱好等,构建一个工程目录结构
+--Helloworld : a project root directory
+--Build/ : build out of source
+--Documentation/
+--Include/ : common headers
+--Source/
+--Hello/ : a customized library
--CMakeLists.txt
--hello.c
--Hello.h
+--Demo/
--CMakeLists.txt
--main.cpp
--main.h
+--Test/
+--Modules/
`--CMakeLists.txt : a top cmake script file.
当然也可以把Hello放到Modules里,也许还可以把Modules改为Libs,Third等等,而Demo里的直接放到外面即Source里。
由于只演示一个简单Helloworld工程,如C:\Users\fangss\Desktop\Helloworld目录结构如下:
+--Helloworld
--CMakeLists.txt
--main.cpp
CMakeLists.txt,其中add_definitions追加一个预处理定义。
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) # define minimum version
PROJECT(Helloworld) #The project name
ADD_EXECUTABLE(demo main.cpp) #generate exe
add_definitions(-DDEMO_VERSION=${DEMO_VERSION}) # pass a preprocessor definition
main.cpp
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
#ifdef DEMO_VERSION
cout << "demo version: " << DEMO_VERSION << endl;
#endif
cout<<"Hello World!"<<endl;
}
执行cd C:\Users\fangss\Desktop\Helloworld && "C:\Program Files\CMake\bin\cmake.exe" -D DEMO_VERSION=1.0 .
,输出
-- Building for: Visual Studio 14 2015
-- The C compiler identification is MSVC 19.0.23026.0
-- The CXX compiler identification is MSVC 19.0.23026.0
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/cl.exe -
- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/cl.exe
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/cl.exe
-- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/fangss/Desktop
在Windows上自动探测MSVC并创建了Visual Studio解决方案。接下来,就可以用Visual Studio打开了。目录下文件变成这样:
2015/10/02 16:31 <DIR> .
2015/10/02 16:31 <DIR> ..
2015/10/02 16:31 52,923 ALL_BUILD.vcxproj
2015/10/02 16:31 289 ALL_BUILD.vcxproj.filters
2015/10/02 16:31 11,801 CMakeCache.txt
2015/10/02 16:31 <DIR> CMakeFiles
2015/10/02 16:27 863 CMakeLists.txt
2015/10/02 16:31 1,309 cmake_install.cmake
2015/10/02 16:31 63,397 demo.vcxproj
2015/10/02 16:31 581 demo.vcxproj.filters
2015/10/02 16:31 3,134 Helloworld.sln
2015/10/02 16:28 214 main.cpp
2015/10/02 16:31 37,671 ZERO_CHECK.vcxproj
2015/10/02 16:31 526 ZERO_CHECK.vcxproj.filters
CMake命令行传递预处理定义处理
按照上面在CMakeLists.txt里使用add_definitions
,就能够传递预处理定义了,搜一下,会发现在demo.vcxproj文件里:
grep --color -r "DEMO_VERSION" /cygdrive/c/Users/fangss/Desktop/HelloWorld
demo.vcxproj: <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;DEMO_VERSION=1.0;CMAKE_INTDIR=\"RelWithDebInfo\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
可以看出预处理定义为字符串(#define DEMO_VERSION "1.0"
)时,需要这样传递-D DEMO_VERSION=\"1.0\"
,否则"1.0"和1.0最终都是DEMO_VERSION=1.0
。
分组密码加密中的四种模式:
图片来自:对称加密和分组加密中的四种模式(ECB、CBC、CFB、OFB)