文章目录
常见编译选项
预处理
- -D 编译宏定义:-D<标识符>相当于#define <标识符>,如-DDBUG
- -I 头文件包含路径:-I/backup/include
- -sysroot 系统头文件路径:-sysroot=/home/sysroot
- -MD 自动生成依赖文件:-MD,
- -MP 为依赖项生成假目标:
- -MT 更改目标名称:
编译选项
- -Wall 打开所有警告
- -Werror 提高警告级别
- -Wcomment 注释不规范
- -Warray-bounds 数组越界
- -Wstrict-aliasing 严格别名
- -g 生成调试信息
- -On 代码优化级别,若n不存在,则不优化,n越大优化越大
- -march 为CPU架构
- -mtune 为CPU性能调优
- -mcpu CPU名称
- -fPIC 生成位置无关代码
- -fstack-protector 栈保护
屏蔽警告
- -w 屏蔽所有警告
- -Wno-comment
- -Wno-array-bounds
- -fno-strict-aliasing
- -fno-common
链接
- -l 链接库文件
- -L 链接库路径
- -shared
- -rdynamic
- -pie
- -Wl,-z,relro
- -Wl,-z,noexecstack
- -Wl,-z,now
- -Wl,–disable-new-dtags,-rpath
一般Cmake编译实例文件目录结构
构建工程
- add_subdirectory()会处理下层文件夹中的CMakeLists.txt文件
- cmake -P
主要文件介绍
- CMakeLists.txt:cmake配置文件,与代码同路径存放,共同进行配置管理
- *.sh:编译入口,调用cmake和make,执行编译
- config_***.cmake:编译器配置文件,包括编译类型的输出条件开关标志,输出文件名称、输出文件配置文件名称和输出文件存放路径等,一般存放在根目录下,单独的文件中重用
根目录结构
CMakeLists.txt 主CmakeLists.txt,cmake函数执行的入口
build
build.sh 编译工程入口,设置编译环境变量
build_all.sh
cmake_and_compile.sh 编译入口,开始工程编译
cmake 编译器配置文件
user_config
user_config.cmake
...
project_config 工程输出文件的配置文件夹
project_config.cmake
...
toolchain 针对某个工程的编译器配置文件夹
toolchain_config.cmake
...
output 编译输出目录
usrcodefile 源代码目录
CMakeLists.txt 告知cmake处理下层目录的CMakeLists.txt
appFile 源代码文件夹
CMakeLists.txt 底层源代码的CmakeLists.txt
...
otherSourceFile 源代码文件夹
CMakeLists.txt
...
...
Cmake编译
内部编译
- 进入主目录
- 执行:cmake . (命令后面的点号,表示本目录)
外部编译
- 清除主目录中,除了源代码、CmakeLists.txt之外的所有中间文件
- 在主目录中新建build目录,或其他地方建立build目录
- 进入build目录,运行cmake … (…代表父目录,如果在其他地方建立build目录,则需要运行cmake <程目录的主路径>),查看build目录,就会产生编译需要的Makefile以及其他的中间文件
- 在build中运行make构建工程,会在当前目录(build目录)获得目标文件,其中PROJECT_SOURCE_DIR指代码工程路径(代码主目录)PROJECT_BINARY_DIR指代码编译路径(buil目录路径)
常用命令
- cmake_mininum_required():设置cmake的最低版本要求,如cmake_mininum_required(VERSION 2.6)
- project():定义项目名称,如project(Tutorial)
- message():输出信息,可以输出cmake中的变量信息,如message(“linker:${LINKER}”)
- include():该命令可以包含一个cmake支持的文件,严禁包含CmakeLists.txt,只能包含*.cmake,如include(common_config.cmake)
- set():该命令可以修改cmake的环境变量和添加自定义变量,如设置系统变量set(CMAKE_SYSTEM_NAME linux),设置自定义变量set(usr_root ${CODE_ROOT_PATH}/usr)
- target_sources():向编译目标添加源文件,如target_sources(project_name PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.c)
- STREQUAL:判断两个字符串是否相等,一般与条件判断一起使用
- add_subdirectory():该命令处理下层文件夹中的CmakeLists.txt文件,如add_subdirectory(subfile_name)
- add_executable():用于创建一个可执行的Target
- add_library():可以创建动态库shared,静态库static,对象列表object,如生成动态库add_library( M O D U L E N A M E S H A R E D " " ) , 生 成 对 象 列 表 a d d l i b r a r y ( {MODULE_NAME} SHARED " "),生成对象列表add_library( MODULENAMESHARED""),生成对象列表addlibrary({MODULE_NAME} SOBJECT " ")
- add_custom_target():添加一个目标
- add_definitions():向C/C++编译器添加-D宏定义,如add_definitions(-DABC -DDEG),参数使用空格间隔
- add_dependencies():定义target依赖的其他target,确保在编译本target之前,其他的target以及被构建,如add_dependencies(target detarget1 detarget2 …)
命令详解
- PROJECT(project_name [CXX] [C] [Java])
这条指令隐式定义两个变量:<project_name>_BINARY_DIR、<project_name>_SOURCE_DIR,内部编译变量所指的都是工程所在路径,外部编译时所指代的内容有所不同,同时cmake系统也预定义PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR变量,变量值与<project_name>一致 - SET(var [value] [CACHE TYPE DOCSRING [FORCE]])
- MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] “message” …)
这个指令用于向终端输出用户定义的信息,SEND_ERROR产生错误,生成过程被跳过,STATUS输出前缀为_的信息,FATAL_ERROR立即终止所有cmake过程 - ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制文件存放的位置。EXCLUDE_FROM_ALL参数的含义是将这个目录从编译过程中排除。将source_dir子目录加入工程,并指定编译输出(包括中间结果)存放路径binary_dir目录下,如果不进行binary目录的指定,那么编译结果将存放build/source_dir目录中,与原有的source_dir目录对应。
可以通过set指令,重新指定最终的目标二进制文件(可执行文件和共享库)的位置:set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 和set(LIBBARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
使用外部共享库和头文件
- INCLUDE_DIRECTORIES([AFTER | BEFORE] [SYSTEM] dir1 dir2 …)
用于向工程添加多个特定的头文件搜索路径,路径之间使用空格分隔,如果路径包含空格,可以使用双引号括起来,默认的行为是追加到当前的头文件搜索路径的后面 - LINK_DIRECTORIES(dir1 dir2 …)
添加共享库搜索路径 - TARGET_LINK_LIBRARIES(target library1<debug | optimized> library2 …)
用来为taget添加需要链接的共享库
静态库与动态库构建
ADD_LIBRARY(libname [SHARED | STATIC | MODULE] [EXECLUDE_FROM_ALL] source1 source2 … sourceN)
- 不需要写全libname.so,只需要填写name即可,cmake自动生成
常用变量
- CMAKE_SYSTEM_NAME:编译系统的类型,例如set(CMAKE_SYSTEM_NAME linux)
- CMAKE_SYSTEM_PROCESSOR:编译系统处理器类型,如set(CMAKE_SYSTEM_PROCESSOR arm)
- CMAKE_CXX_COMPILER:C++编译时使用的编译器,如set(CMAKE_CXX_COMPILER arm-linux-gnueabi-g++)
- CMAKE_C_COMPILER:C编译时使用的编译器set(CMAKE_C_COMPILER arm-linux-gnueabi-gcc)
- CXX_FLAGS:C++文件编译时的编译参数
- MACRO_DEFS:源文件编译时,编译宏定义
- CMAKE_CURRENT_SOURCE_DIR:调用CMakeLists.txt时,所在目录的绝对路径,使用ADD_SUBDIRECTORY(src bin)可以更改这个变量的值,但是使用set(EXECUTABLE_OUTPUT_PATH
)不会改变这个变量,仅仅修改最终目标文件存放路径 - CMAKE_BINARY_DIR、PROJECT_BINARY_DIR、<project_name>_BINARY_DIR 工程编译产生的目录
- CMAKE_SOURCE_DIR、PROJECT_SOURCE_DIR、<project_name>_SOURCE_DIR
- CMAKE_CURRENT_LIST_FILE 输出调用这个变量的CMakeLists.txt的完整路径
- CMAKE_CURRENT_LIST_LINE 输出这个变量所在的行
- CMAKE_MODULE_PATH 用来自定义cmake模块所在的路径
- EXECUTABLE_OUTPUT_PATH 、LIBBARY_OUTPUT_PATH 分别用来重新定义可执行文件和库文件存放路径
cmake调用环境变量
- $ENV{name}:调用系统环境变量,如MESSAGE(STATUS “home dir:$ENV{HOME}”)
- SET(ENV{name} value):设置环境变量
控制指令
IF
IF(expr)
commands
...
ELSE(expr)
commands
...
ENDIF(expr)
- 另外一个指令是ELSEIF,凡是出现IF的地方一定要有对应的ENDIF,出现ELSEIF的地方,ENDIF是可选的
- 如果SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON),则可以写成:
IF(expr)
commands
...
ELSE()
commands
...
ENDIF()
#或
IF(expr1)
commands
...
ELSEIF(expr2)
commands
...
ELSEIF(expr3)
commands
...
ENDIF(expr1)
表达式的使用方法:
- IF(var):如果变量不是空、O、N、NO、OFF、FALSE、NOTT-OUND、_NOTFOUND时为真
- IF(NOT var):
- IF(var1 AND var2):当两个变量都为真时为真
- IF(var1 OR var2):当两个变量其中一个变量为真时为真
- IF(COMMAND cmd):当给定的cmd为命令,并可以调用时为真
- IF(EXISTS dir) 或 IF(EXISTS file):当目录或文件存在时为真
- IF(file1 IS_NEWER_THAN file2):当file1比file2新,或者file1/file2其中一个不存在时为真
- IF(IS_DIRECTORY dirname):当dirname为目录时为真
- IF(variable MATCHES regex):给定的变量能够匹配正则表达式时为真
- IF(string MATCHES regex):给定的字符串能够匹配正则表达式时为真
- IF(variable LESS/GREATER/EQUAL number):数字比较
- IF(string STRLESS/STRGREATER/STREQUAL string):按照字母序的排列进行比较
- IF(DEFINED variable):如果变量被定义,则为真
WHILE
WHILE(condition)
commands
...
ENDWHILE(condition)
FOREACH
只有遇到ENDFOREACH指令,整个语句才会真正执行
列表循环
FOREACH(loop_var arg1 arg2)
commands
...
ENDFOREACH(loop_var )
范围循环
FOREACH(var RANGE total)
commands
...
ENDFOREACH(var)
范围和步进循环
FOREACH(var RANGE start stop [step])
commands
...
ENDFOREACH(var)
FUNCTION
文件安装
普通文件安装
如果安装非目标文件的可执行程序安装,如脚本,则把FILES改成PROGRAMS
INSTALL(FILES files...
DESRINATION <dir>
[PERMISSIONS permissions ...]
[CONFIGURATIONS [Debug | Release | ...]]
[COMPONENT <component>]
[RENAME <name>]
[OPTIONAL]
)
目标文件安装
INSTALL(TARGETS targets...
[[ARCHIVE | LIBRARY | RUNTIME]
[DESRINATION <dir>]
[PERMISSIONS permissions ...]
[CONFIGURATIONS [Debug | Release | ...]]
[COMPONENT <component>]
[OPTIONAL]
] [...]
)
案例:
INSTALL(TARGETS myrun mylib mystaticlib
RUNTIME DESRINATION bin
LIBRARY DESRINATION lib
ARCHIVE DESRINATION libstatic
)
目录安装
INSTALL(DIRECTOR dir...
[DESRINATION <dir>]
[FILE_PERMISSIONS permissions...]
[DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS permissions...]
[CONFIGURATIONS [Debug | Release | ...]]
[COMPONENT <component>]
[[PATTERN <patern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS permissions...]]
[...]
)
- DIRECTORY后面连接的是所在source目录的相对路径,但abc和abc/有很大区别,如果目录不以/结尾,那么这个目录被安装为目标路径下的abc,如果目录名以/结尾,则将这个目录的内容安装到目标路径下,但不包括这个目录本身
- PATERN用于使用正则表达式进行过滤
- PERMISSIONS 用于指定PATERN过滤后的文件权限
案例:
INSTALL(DIRECTOR icons script/
DESRINATION share/myproj
PATTERN "cvs" EXCLUDE #不包含目录名为cvs的目录
PATTERN "script/*"
PERMISSIONS OWNER_EXECUTE OWNER_WRITE GROUP_READ
)
安装CMAKE脚本
INSTALL(
[[SCRIPT <file>] [CODE <code>]]
[...]
)
- SCRIPT参数用于在安装时调用cmake脚本文件(.cmake文件)
- CODE参数用于执行CMAKE指令,必须双引号括起来
案例:
INSTALL(
CODE ”MESSAGE(\"sample install message.\")"
)
Cmake案例
顶层CmakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(Tutorial)
//版本号,在源代码中可以直接使用
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
//设置C/C++的通用版本可以分别使用变量CMAKE_C_STANDARD(接受值为98,99和11)和CMAKE_CXX_STANDARD (接受值为CMAKE_CXX_STANDARD和14)全局指定
//set(CMAKE_C_STANDARD 99)
//set(CMAKE_CXX_STANDARD 11)
//本系统是否提供 log 和 exp 函数?
include(${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)
check_function_exists(log HAVE_LOG)
check_function_exists(exp HAVE_EXP)
//我们应该使用自己的 math 函数吗?
option(USE_MYMATH "Use tutorial provided math implementation" ON)
//配置一个头文件来向源代码传递一些 CMake 设置。
configure_file(
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
"${PROJECT_BINARY_DIR}/TutorialConfig.h"
)
//为包含文件的搜索路径添加二进制树,这样才能发现 TutorialConfig.h 头文件。
include_directories("${PROJECT_BINARY_DIR}")
//添加 MathFunctions 库吗
if(USE_MYMATH)
include_directories("${PROJECT_SOURCE_DIR}/MathFunctions")
//生成库
add_subdirectory(MathFunctions)
set(EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif(USE_MYMATH)
//添加可执行文件
add_executable(Tutorial tutorial.cxx)
//链接到库
target_link_libraries(Tutorial ${EXTRA_LIBS})
//添加安装的目标
install(TARGETS Tutorial DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" DESTINATION include)
//测试 1 :应用程序可以运行吗?
add_test(TutorialRuns Tutorial 25)
//测试 2 : 使用信息可用吗?
add_test(TutorialUsage Tutorial)
set_tests_properties(TutorialUsage PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
)
//定义一个可以简化引入测试过程的宏
macro(do_test arg result)
add_test (TutorialComp${arg} Tutorial ${arg})
set_tests_properties (TutorialComp${arg} PROPERTIES PASS_REGULAR_EXPRESSION ${result}
)
endmacro(do_test)
//执行一系列基于结果的测试
do_test(4 "4 is 2")
do_test(9 "9 is 3")
do_test(5 "5 is 2.236")<BR>do_test (7 "7 is 2.645")
do_test(25 "25 is 5")
do_test(-25 "-25 is 0")
do_test(0.0001 "0.0001 is 0.01")
TutorialConfig.h.in配置文件
//Tutorial 的配置选项与设置如下
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
#cmakedefine USE_MYMATH
//该平台提供 exp 和 log 函数吗?
//使用#define 或 #cmakedefine可以在源代码中直接使用,如
/*
printf(“Version %d.%d\n", Tutorial_VERSION_MAJOR)
#define HAVE_LOG
...
#endif
*/
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP
引入库源代码目录的CMakeLists.txt
//把库文件放到一个子目录 MathFunctions
add_library(MathFunctions mysqrt.cxx)
install(TARGETS MathFunctions DESTINATION bin)
install(FILES MathFunctions.h DESTINATION include)