Cmake与autotools一样都是生成makefile的工具,但其步骤更清晰明了,这里做一下解析。
CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码。因此CMake的编译基本就两个步骤:
- cmake
- make
CMakeLists.txt是以目录为执行单位的,CMakeLists.txt中可以添加子目录,子目录下也存在一个该目录的CMakeLists.txt文件。
以mbedtls的CMakeLists.txt为例:
调试方法:
在buildroot环境中,调试CMakeLists.txt的方法如下:
- 修改CMakeLists.txt,在其中加入调试语句
message( [STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR]
"message to display" ...)
打印变量的示例如下:message(STATUS ${CMAKE_COMPILER_IS_MSVC})
2. 执行如下命令,就会输出加入的调试信息。
$ make mbedtls-reconfigure > m1.txt 2>&1
实例分析:
cmake_minimum_required(VERSION 2.6)
cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])
该命令指定了编译该工程对cmake的最高、最低版本要求,如果 CMake 的运行版本低于所需版本,它将停止处理项目并报告错误。
project("mbed TLS" C)
project(<PROJECT-NAME> [<language-name>...])
指定工程名称以及语言
option(USE_PKCS11_HELPER_LIBRARY "Build mbed TLS with the pkcs11-helper library." OFF)
option(<variable> "<help_text>" [value])
- variable:定义选项名称
- help_text:说明选项的含义
- value:定义选项默认状态,一般是OFF或者ON,除去ON之外,其他所有值都为认为是OFF。
string(REGEX MATCH "IAR" CMAKE_COMPILER_IS_IAR "${CMAKE_C_COMPILER_ID}")
string(REGEX MATCH <regular_expression> <output_variable> <input> [<input>...])
从所有<input> ...
中查找<regular_expression>
匹配到的字符串,并存放于<output_variable>
,查不到输出为空字符串。多个输入时先连接再做操作。只匹配第一次。以上语句是查找Cmake的编译器是否是IAR规范。
set(WARNING_BORDER "*******************************************************\n")
set(NULL_ENTROPY_WARN_L1 "**** WARNING! MBEDTLS_TEST_NULL_ENTROPY defined!\n")
set(NULL_ENTROPY_WARN_L2 "**** THIS BUILD HAS NO DEFINED ENTROPY SOURCES\n")
set(NULL_ENTROPY_WARN_L3 "**** AND IS *NOT* SUITABLE FOR PRODUCTION USE\n")
set(NULL_ENTROPY_WARNING "${WARNING_BORDER}"
"${NULL_ENTROPY_WARN_L1}"
"${NULL_ENTROPY_WARN_L2}"
"${NULL_ENTROPY_WARN_L3}"
"${WARNING_BORDER}")
set(<variable> <value>... [PARENT_SCOPE])
unset(<variable>... [PARENT_SCOPE])
- variable:要被赋值的变量
- value:要赋给变量的值
设置NULL_ENTROPY_WARNING 字符串变量的值;
message(STATUS "NULL_ENTROPY_WARNING is:\n${NULL_ENTROPY_WARNING}")
打印出该值为:
NULL_ENTROPY_WARNING is:
*******************************************************
;**** WARNING! MBEDTLS_TEST_NULL_ENTROPY defined!
;**** THIS BUILD HAS NO DEFINED ENTROPY SOURCES
;**** AND IS *NOT* SUITABLE FOR PRODUCTION USE
;*******************************************************
find_package(Perl)
find_package(<package> [version] [EXACT] [QUIET] [MODULE]
[REQUIRED] [[COMPONENTS] [components...]]
[OPTIONAL_COMPONENTS components...]
[NO_POLICY_SCOPE])package:必填参数。需要查找的包名,注意大小写。
version和EXACT:可选参数,version指定的是版本,如果指定就必须检查找到的包的版本是否和version兼容。如果指定EXACT则表示必须完全匹配的版本而不是兼容版本就可以。
QUIET:可选参数,表示如果查找失败,不会在屏幕进行输出(但是如果指定了REQUIRED字段,则QUIET无效,仍然会输出查找失败提示语)。
MODULE:可选字段。前面提到说“如果Module模式查找失败则回退到Config模式进行查找”,但是假如加入了MODULE选项,那么就只在Module模式查找,如果Module模式下查找失败并不切换到Config模式查找。
REQUIRED:可选字段。表示一定要找到包,找不到的话就立即停掉整个CMake。而如果不指定REQUIRED则CMake会继续执行。
COMPONENTS,components:可选字段,表示查找的包中必须要找到的组件(components),如果有任何一个找不到就算失败,类似于REQUIRED,导致CMake停止执行。
查找是否已经有Perl依赖包
if(PERL_FOUND),如果Perl已经有安装,PERL_FOUND为true
从cmake的官方文档查到
Find perl
this module looks for Perl
PERL_EXECUTABLE - the full path to perl PERL_FOUND - If false, don't attempt to use perl. PERL_VERSION_STRING - version of perl found (since CMake 2.8.8)
execute_process(COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/config.pl -f ${CMAKE_CURRENT_SOURCE_DIR}/include/mbedtls/config.h get MBEDTLS_TEST_NULL_ENTROPY
RESULT_VARIABLE result)
execute_process(COMMAND <cmd1> [<arguments>]
[COMMAND <cmd2> [<arguments>]]...
[WORKING_DIRECTORY <directory>]
[TIMEOUT <seconds>]
[RESULT_VARIABLE <variable>]
[RESULTS_VARIABLE <variable>]
[OUTPUT_VARIABLE <variable>]
[ERROR_VARIABLE <variable>]
[INPUT_FILE <file>]
[OUTPUT_FILE <file>]
[ERROR_FILE <file>]
[OUTPUT_QUIET]
[ERROR_QUIET]
[COMMAND_ECHO <where>]
[OUTPUT_STRIP_TRAILING_WHITESPACE]
[ERROR_STRIP_TRAILING_WHITESPACE]
[ENCODING <name>]
[ECHO_OUTPUT_VARIABLE]
[ECHO_ERROR_VARIABLE]
[COMMAND_ERROR_IS_FATAL <ANY|LAST>])execute_process 命令将从当前正在执行的CMake进程中派生一个或多个子进程,从而提供了在配置项目时运行任意命令的方法。可以在一次调用 execute_process 时执行多个命令。但请注意,每个命令的输出将通过管道传输到下一个命令中。该命令接受多个参数:
COMMAND:子进程命令行。
WORKING_DIRECTORY:指定应该在哪个目录中执行命令。
TIMEOUT:如果在指定的时间内(以秒为单位计算,允许有小数位)子进程执行仍未完成,则将会被中断。
RESULT_VARIABLE:包含进程运行的结果。这要么是一个整数表示执行成功,要么是一个带有错误条件的字符串。
RESULTS_VARIABLE:变量将被设置为以分号分隔的列表形式包含所有进程的结果,按给定命令参数的顺序排列。每个条目都是对应子项的整数返回码或描述错误条件的字符串。
OUTPUT_VARIABLE和ERROR_VARIABLE将包含执行命令的标准输出和标准错误。由于命令的输出是通过管道传输的,因此只有最后一个命令的标准输出才会保存到OUTPUT_VARIABLE中。
INPUT_FILE指定标准输入重定向的文件名。
OUTPUT_FILE指定标准输出重定向的文件名。
ERROR_FILE指定标准错误输出重定向的文件名。
设置OUTPUT_QUIET和ERROR_QUIET后,CMake将静默地忽略标准输出和标准错误。
COMMAND_ECHO <where>:正在运行的命令将被回送到<where>,而<where>将被设置为STDERR、STDOUT或NONE中的一个。
设置OUTPUT_STRIP_TRAILING_WHITESPACE,可以删除运行命令的标准输出中的任何尾随空 格。
设置ERROR_STRIP_TRAILING_WHITESPACE,可以删除运行命令的错误输出中的任何尾随空格。
ENCODING <name>:适用于windows平台,编码名称有NONE、AUTO、ANSI、OEM、UTF8或UTF-8。
ECHO_OUTPUT_VARIABLE, ECHO_ERROR_VARIABLE:标准输出或标准错误不会被专门重定向到配置的变量。
COMMAND_ERROR_IS_FATAL <ANY|LAST>:
1.ANY:如果命令列表中的任何命令失败,execute_process()命令将因错误而停止。2.LAST:如果命令列表中的最后一个命令失败,则execute_process()命令会因错误而停止。列表中前面的命令不会导致致命错误。
如果在同一管道中同时指定了多个OUTPUT_*或ERROR_*选项,则优先级顺序是未知的(应避免这种情况)。如果未指定任何OUTPUT_*或ERROR_*选项,则命令CMake所在进程共享输出管道。
执行命令并设定返回值为result
function(link_to_source base_name)
# Get OS dependent path to use in `execute_process`
file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${base_name}" link)
file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${base_name}" target)
if (NOT EXISTS ${link})
if (CMAKE_HOST_UNIX)
set(command ln -s ${target} ${link})
else()
if (IS_DIRECTORY ${target})
set(command cmd.exe /c mklink /j ${link} ${target})
else()
set(command cmd.exe /c mklink /h ${link} ${target})
endif()
endif()
execute_process(COMMAND ${command}
RESULT_VARIABLE result
ERROR_VARIABLE output)
if (NOT ${result} EQUAL 0)
message(FATAL_ERROR "Could not create symbolic link for: ${target} --> ${output}")
endif()
endif()
endfunction(link_to_source)
function(<name> [<arg1> ...])
<commands>
endfunction([<name>])
CMake中的function类似编程语言的函数,允许我们将一系列复杂的命令封装起来,方便调用与重复使用。<name>:表示定义的函数名,通过这个名字来调用整个函数,
[<arg1>…]表示函数的参数,可以省略
<commands>就是函数中的具体命令组合,这些命令组合可以使用传进来的参数。
endfunction()表示整个函数以及定义完成,其中括号里可填,可不填,如果要填的话,其名字必须与function中定义的函数名一致。
add_subdirectory(library)
add_subdirectory(include)
添加子目录。
add_subdirectory (source_dir [binary_dir] [EXCLUDE_FROM_ALL])
source_dir
必选参数。该参数指定一个子目录,子目录下应该包含CMakeLists.txt
文件和代码文件。子目录可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前目录的一个相对路径。binary_dir
可选参数。该参数指定一个目录,用于存放输出文件。可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前输出目录的一个相对路径。如果该参数没有指定,则默认的输出目录使用source_dir
。EXCLUDE_FROM_ALL
可选参数。当指定了该参数,则子目录下的目标不会被父目录下的目标文件包含进去,父目录的CMakeLists.txt
不会构建子目录的目标文件,必须在子目录下显式去构建。例外情况:当父目录的目标依赖于子目录的目标,则子目录的目标仍然会被构建出来以满足依赖关系(例如使用了target_link_libraries)
。