源程序经过预处理、编译、汇编、链接步骤后,才能生成可执行程序。
gcc -E hello_world.c -o hello_world.i
gcc -S
gcc -c hello_world.s -o hello_world.o
gcc hello.world.o -o hello_world
CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多。CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库(so(shared object))。
cmake 指向CMakeLists.txt所在的目录,例如cmake .. 表示CMakeLists.txt在当前目录的上一级目录。cmake后会生成很多编译的中间文件以及makefile文件。
cmake的特点:开源、跨平台、可扩展、简化编译构建过程和编译过程。
(1)cmake 变量
CMake支持简单的变量,它们或者是字符串,或者是字符串的列表。引用一个变量的语法是 ${VAR_NAME}
set(V 1 2 3) # V的值是1 2 3
command(${V}) # 等价于command(1 2 3)
要把一个列表变量作为整体传递,只需要加上双引号即可:
command("${V}") # 等价于command("1 2 3")
(2)cmake 实现原理
CMake包含一系列重要的概念抽象,包括目标(Targets)、生成器(Generators)、命令(Commands)等,这些命令均被实现为C++类。理解这些概念后才能编写高效的CMakeLists文件。
CMake的执行开始时,会创建一个cmake对象并把命令行参数传递给它。cmake对象管理整体的配置过程,持有构建过程的全局信息(例如缓存值)。cmake会依据用户的选择来创建合适的全局生成器(VS、Makefiles等等),并把构建过程的控制权转交给全局生成器(调用configure和generate方法)。
全局生成器负责管理配置信息,并生成所有Makefiles/工程文件。一般情况下全局生成器把具体工作委托给本地生成器执行,全局生成器为每个目录创建一个本地生成器。
(3)目标
Makefile对象中存放的最重要的对象是目标(Targets),目标代表可执行文件、库、实用工具等。每个 add_library 、 add_executable 、 add_custom_target 命令都会创建一个目标。
# 创建一个静态库,包含两个源文件
add_library(foo STATIC foo1.c foo2.c)
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo1)
# 指定生成目标
add_executable(Demo main.cc)
# 指定多个源文件,生成目标
add_executable(Demo main.cc MathFunctions.cc)
aux_source_directory,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})
add_subdirectory
add_subdirectory
指明本项目包含一个子目录 ,这样 子目录下的 CMakeLists.txt 文件和源代码也会被处理
# 如在主目录下有个子目录math,添加 math 子目录
add_subdirectory(math)
语法:TARGET_LINK_LIBRARIES(targetlibrary1
TARGET_LINK_LIBRARIES(myProject hello),连接libhello.so库
TARGET_LINK_LIBRARIES(myProject libhello.a)
TARGET_LINK_LIBRARIES(myProject libhello.so)
命令 target_link_libraries
指明可执行文件 Demo 需要连接一个名为 MathFunctions 的链接库
# 添加链接库
target_link_libraries(Demo MathFunctions)
set(SRC_LIB "${CMAKE_SOURCE_DIR}/src/main/jnilibs")
定义了一个变量SRC_LIB,并且变量的值为${CMAKE_SOURCE_DIR}/src/main/jnilibs,其中CMAKE_SOURCE_DIR 是一个cmake内置变量,指定了CMakeLists.txt所在的目录
message( [STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR]
"message to display" ...)
无) = 重要消息;
STATUS = 非重要消息;
WARNING = CMake 警告, 会继续执行;
AUTHOR_WARNING = CMake 警告 (dev), 会继续执行;
SEND_ERROR = CMake 错误, 继续执行,但是会跳过生成的步骤;
FATAL_ERROR = CMake 错误, 终止所有处理过程;
add_custom_command
add_custom_command(OUTPUT output1 [output2 ...]
COMMAND command1 [ARGS] [args1...]``
[COMMAND command2 [ARGS] [args2...] ...]
[MAIN_DEPENDENCY depend]
[DEPENDS [depends...]]
[BYPRODUCTS [files...]]
[IMPLICIT_DEPENDS depend1
[ depend2] ...]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[DEPFILE depfile]
[JOB_POOL job_pool]
[VERBATIM] [APPEND] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS])
add_custom_command(TARGET
PRE_BUILD | PRE_LINK | POST_BUILD
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[BYPRODUCTS [files...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[VERBATIM] [USES_TERMINAL])
cmake_minimum_required(VERSION 3.0)
project(test)
add_custom_command(OUTPUT COPY_RES
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etc
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/log.txt ${CMAKE_CURRENT_SOURCE_DIR}/etc
)
add_custom_target(CopyTask ALL DEPENDS COPY_RES)
link_directories(directory1 directory2 ...)
它相当于g++
命令的-L
选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH
的路径的作用。
link_directories("/lib/directory/")
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so")
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")
cmake的宏定义分为全局宏定义和针对某个目标定义宏定义。
定义全局宏定义:
# 定义宏MACRO_NAME,注意前面的-D
add_definitions(-DMACRO_NAME)
# 赋值
add_definitions(-DMACRO_NAME=${value})
应用举例:
在工程CMakeLists.txt 中,使用add_definitions()函数控制代码的开启和关闭。
option(TEST_DEBUG "option for debug" OFF)
if (TEST_DEBUG)
add_definitions(-DTEST_DEBUG)
endif(TEST_DEBUG)
option用法 /*TEST_DEBUG为编译开关,中间的字符串为描述信息,ON/OFF 为默认选项*/
运行构建项目的时候可以添加参数控制宏的开启和关闭
cmake -DTEST_DEBUG = on .. #打开
源码中使用该宏进行控制条件编译
#ifdef TEST_DEBUG
...
...
#else
...
#endif
option: 为选项开关
针对某个目标添加宏定义:
# 仅仅能用于 add_executable() 或 add_library() 添加的目标
# 格式:
target_compile_definitions(
# PUBLIC、INTERFACE可以将宏定义传递给target的PUBLIC、INTERFACE条目
[items1...]
[ [items2...] ...])
# 示例:
target_compile_definitions(hello PRIVATE A=1 B=0)
# 你也可以直接设置目标属性 COMPILE_DEFINITIONS
应用举例
target_compile_definitions(目标进程
PUBLIC
宏名称
)
设置目标的一些属性来改变它们构建的方式。
set_target_properties(target1 target2 ...
PROPERTIES prop1 value1
prop2 value2 ...)
为目标增加编译定义。
target_compile_definitions(
[items1...]
[ [items2...] ...]
)
将给定目录加给编译器搜索到的包含文件
target_include_directories( [SYSTEM] [BEFORE]
[items1...]
[ [items2...] ...]
BEFORE or AFTER 可以加在前面或者后面. 如果设定 SYSTEM 选项 编译器认定为系统包含目录。
https://zhuanlan.zhihu.com/p/97369704?utm_source=wechat_session
设置编译选项可以通过add_compile_options
命令,也可以通过set命令修改CMAKE_CXX_FLAGS
或CMAKE_C_FLAGS。
add_compile_options
命令添加的编译选项是针对所有编译器的(包括c和c++编译器),而set命令设置CMAKE_C_FLAGS
或CMAKE_CXX_FLAGS
变量则是分别只针对c和c++编译器的。
#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持
if(CMAKE_COMPILER_IS_GNUCXX)
add_compile_options(-std=c++11)
message(STATUS "optional:-std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)
只针对c++编译器添加这个option。
#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
message(STATUS "optional:-std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)
list(LENGTH
说明:
LENGTH will return a given list’s length.#返回列表的长度
GET will return list of elements specified by indices from the list.#读取列表指定索引
APPEND will append elements to the list. #将子元素追加到列表
FIND will return the index of the element specified in the list or -1 if it wasn’t found.
INSERT will insert elements to the list to the specified location.
REMOVE_AT and REMOVE_ITEM will remove items from the list. The difference is that REMOVE_ITEM will remove the given items, while REMOVE_AT will remove the items at the given indices.
REMOVE_DUPLICATES will remove duplicated items in the list.
REVERSE reverses the contents of the list in-place.
SORT sorts the list in-place alphabetically.
其他参考:Cmake命令之list介绍 - 百度文库
file GLOB命令主要用于匹配规则在指定的目录内匹配到所需要的文件,命令行格式:
file(GLOB [LIST_DIRECTORIES true[false] [RELATIVE ] [CONFIGURE_DEPENDS] [ ...])
如:寻找当前路径下的cpp文件,且返回的结果中为/public/home的相对路径,
file(GLOB TEST_RESULT LIST_DIRECT true RELATIVE /public/home *.cpp)
message("--------TEST_RESULT: ${TEST_RESULT}")
获取指定路径下全部源文件,按照绝对路径的形式
FILE (GLOB_RECURSE PROJECT_SRC ${PROJECT_SOURCE_DIR}/*.hpp ${PROJECT_SOURCE_DIR}/*.cpp)
install用于指定在安装时运行的规则。它可以用来安装很多内容,可以包括目标二进制、动态库、静态库以及文件、目录、脚本等
install(TARGETS
install({FILES | PROGRAMS}
install(DIRECTORY
install(SCRIPT
install(CODE [...])
install(EXPORT
如:
INSTALL(TARGETS myrun mylib mystaticlib
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
可执行二进制myrun
安装到${CMAKE_INSTALL_BINDIR}
目录,动态库libmylib.so
安装到${CMAKE_INSTALL_LIBDIR}
目录,静态库libmystaticlib.a
安装到${CMAKE_INSTALL_LIBDIR}
目录。
CMake支持条件、循环控制结构,同时支持子过程(macro、function)
if (condition)
command1
else(condition)
command2
endif(condition)
使用 elseif语句
if(MSVC80)
#...
elseif(MSVC90)
#...
elseif(APPLE)
#...
endif()
判断条件:
foreach (item list)
# do something with item
endforeach (item)
此命令用于迭代一个列表,第一个参数是每次迭代使用变量的名称,其余参数为被迭代的列表。
while(${COUNT} LESS 2000)
set(TASK_COUNT, ${COUNT})
endwhile()
使用阿里云 centos 8.0 环境
(1)安装cmake
yum install cmake
查看安装情况:
(2)安装gcc-c++
(1)构建c++ 工程
#include
using namespace std;
int main() {
return 0;
}
(2)需要在同一目录下放置CMakeLists.txt文件,编写如下内容:
# 需要最小的CMake版本
cmake_minimum_required(VERSION 3.3)
# 工程的名称,会作为MSVS的Workspace的名字
project(intellij_taste)
# 全局变量:CMAKE_SOURCE_DIR CMake的起始目录,即源码的根目录
# 全局变量:PROJECT_NAME 工程的名称
# 全局变量:PROJECT_SOURCE_DIR 工程的源码根目录的完整路径
# 全局变量:构建输出目录。默认的,对于内部构建,此变量的值等于CMAKE_SOURCE_DIR;否则等于构建树的根目录
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin) # ${}语法用于引用变量 自动创建bin目录
# 全局变量:可执行文件的输出路径
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
# 全局变量:库文件的输出路径
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
# 设置头文件位置
include_directories("${PROJECT_SOURCE_DIR}")
# 设置C++标志位
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# 设置源文件集合
set(SOURCE_FILES main.cpp)
# 添加需要构建的可执行文件,第二个以及后续参数是用于构建此文件的源码文件
add_executable(intellij_taste ${SOURCE_FILES})
(3)执行cmake
# 创建一个build子目录作为构建树
mkdir build
cd build
cmake ..
# 在build/bin子目录中生成可执行文件:
# cmake --build [options] [-- [native-options]]
cmake --build build -- -j3 # --表示把其余选项传递给底层构建工具
# 注意,亦可使用底层构建系统,例如make命令或者MSVC的IDE
cd build
make -j3
(1)source_group
定义一组源文件到项目文件中. 主要用来配置Visual Studio中的文件标签. 任何被列出的或者与正则表达式匹配的文件都将被放入组中. 如
source_group(name [REGULAR_EXPRESSION regex] [FILES src1 src2 ...])
应用举例:
source_group(test\\vs项目文件集名称 REGULAR_EXPRESSION "代码目录/.+\.(h|inc|cc)")
【1】Cmake知识----编写CMakeLists.txt文件编译C/C++程序 : Cmake知识----编写CMakeLists.txt文件编译C/C++程序 - horsetail - 博客园
【2】Makefile和Cmake的联系与区别 : Makefile和Cmake的联系与区别_hjxu2016的博客-CSDN博客_cmake和makefile区别
【3】CMake 入门实战(精):CMake 入门实战(精)_起风了-CSDN博客_cmake 入门
【4】CMake之message()函数的使用和打印变量值: CMake之message()函数的使用和打印变量值_斧冰-CSDN博客_cmake message
【5】Cmake 内置变量: Cmake 内置变量_测试-CSDN博客
【6】Cmake官网: Documentation | CMake
【7】【CMake】cmake的add_custom_command和add_custom_target指令: 【CMake】cmake的add_custom_command和add_custom_target指令_Yngz_Miao的博客-CSDN博客_add_custom_command
【8】CMake 添加需要链接的库文件目录LINK_DIRECTORIES:CMake 添加需要链接的库文件目录LINK_DIRECTORIES | 浩瀚宇宙 灿烂星空
【9】link_directories, LINK_LIBRARIES, target_link_libraries使用总结: link_directories, LINK_LIBRARIES, target_link_libraries使用总结_w_w的专栏-CSDN博客
【10】linux 下 g++编译程序时,-I(大写i) 与-L(大写l)-l(小写l) 的作用: linux 下 g++编译程序时,-I(大写i) 与-L(大写l)-l(小写l) 的作用_月落及晨曦-CSDN博客
gcc -I(大写的i),-L(大写L)和-l(小写的L)详解:gcc -I(大写的i),-L(大写L)和-l(小写的L)详解_TMD_MCU的博客-CSDN博客
【11】CMAKE 中add_definitions的用法: CMAKE 中add_definitions的用法_邦戈邦戈栗子的博客-CSDN博客
【12】add_library,target_link_libraries,set_target_properties,target_link_libraries使用联系: add_library,target_link_libraries,set_target_properties,target_link_libraries使用联系_michaelhan3的博客-CSDN博客
【13】cmake CMakeLists.txt 命令 add_compile_options、add_definitions、target_compile_definitions、build_command: cmake CMakeLists.txt 命令 add_compile_options、add_definitions、target_compile_definitions、build_command_whatday的专栏-CSDN博客
【14】CMake-scope-PRIVATE-PUBLIC-INTERFACE: CMake-scope-PRIVATE-PUBLIC-INTERFACE_行走-CSDN博客
【15】cmake的四个命令:add_compile_options、add_definitions、target_compile_definitions、build_command...: cmake的四个命令:add_compile_options、add_definitions、target_compile_definitions、build_command..._DragonWar%的博客-CSDN博客
【16】CMake学习笔记:绿色记忆:CMake学习笔记
【17】CMake 入门1/5:基于阿里云 ECS搭建体验环境: CMake 入门1/5:基于阿里云 ECS搭建体验环境_weixin_33947521的博客-CSDN博客
【18】cmake:设置编译选项的讲究(add_compile_options和CMAKE_CXX_FLAGS的区别)_10km的博客-CSDN博客_add_compile_options
【19】CMAKE 批量获取目录下指定类型文件并转换为相对路径_黑色低级高中生的博客-CSDN博客