CMAKE---- 控制编译

1.Introduction

根据CMKAE官网的介绍,主要是用来管理编译和单元测试。我们第一部分总结CMAKE如何进行管理编译的。

C M a k e   i s   a n   o p e n − s o u r c e , c r o s s − p l a t f o r m   f a m i l y   o f   t o o l s   d e s i g n e d   t o   b u i l d ,   t e s t   a n d   p a c k a g e   s o f t w a r e . \color {red}CMake \, is \, an \, open-source, cross-platform \, family \, of \, tools \, designed \, to \, build, \, test \, and \, package \, software. CMakeisanopensource,crossplatformfamilyoftoolsdesignedtobuild,testandpackagesoftware. CMake is used to control the software compilation process using simple platform and compiler independent configuration files, and generate native makefiles and workspaces that can be used in the compiler environment of your choice.

备注:如果没有实战过CMAKE的,建议先从实战这一节看,然后再从头开始看。

2.Background

既然是编译需要知道编译的过程,分为预编译->编译->链接。
根据这篇文章[1]

  1. 在预编译过程时,将source files加载到translation 工具中,head files 根据sources files的需求加载,可能会被加载很多次。
  2. 在编译过程时,每个source files 生成机器语言.o文件
  3. 最后将这些.o文件进行链接,生成可执行文件或者库文件。

分析一下CMAKE的主要数据结构
p r o j e c t : \color {red}project: project: 管理一堆可执行文件和库文件,一个大的project下面可以有很多小的project。
t a r g e t : \color {red}target: target: 自然就是最后生成的可执行文件或者库文件了。
s o u r c e s : \color {red}sources: sources:自然是生成这个target所需要的源文件,也就是各种.c,.cxx。
d i r e c t o r i e s : \color {red}directories: directories: 链接的时候需要寻找对应的文件:所以.so, .a, .h这些文件的地址非常重要。

3.探究CMAKE

根据background这章,我们知道,生成一个target其实很简单啊,只要说清楚target需要哪些source file,需要哪些链接库,最后再把链接库和头文件的地址跟target说一下,不就ok了吗? 那么为什么一个项目的CMAKE有时候搞的这么复杂啊。

3.1最基础的CMAKE项目

如果是一个最简单的项目,我们确实可以按照上面说的

cmake_minimum_required(VERSION 3.13)   #CMKAE版本设定

project(Tutorial VERSION 1.0)    # 新建了一个项目

add_executable(Tutorial main.cxx )  # 生成可执行文件
target_link_libraries(Tutorial lcm)  #添加链接库
target_link_directories(Tutorial "/usr/local/lib/")  #添加链接地址
target_include_directories(Tutorial PRIVATE        #添加include地址
    "/usr/local/include/lcm/")

注意事项:安装在标准位置的库,因为库已经在gcc的默认搜索位置,不需要再重复声明了
默认的link_directories,包括了标准库的安装位置和当前项目下生成的库位置
默认的include_directories,包括gcc的默认搜索位置和CMAKE_CURRENT_SOURCE_DIR

/usr/lib/gcc/x86_64-redhat-linux/4.8.2/…/…/…/…/include/c++/4.8.2
/usr/lib/gcc/x86_64-redhat-linux/4.8.2/…/…/…/…/include/c++/4.8.2/x86_64-redhat-linux
/usr/lib/gcc/x86_64-redhat-linux/4.8.2/…/…/…/…/include/c++/4.8.2/backward
/usr/lib/gcc/x86_64-redhat-linux/4.8.2/include
/usr/local/include
/usr/include

分析这么写 c m a k e 繁琐的地方在哪里? \color {red} 分析这么写cmake繁琐的地方在哪里? 分析这么写cmake繁琐的地方在哪里?
sources file 太多了。
include_directories也很麻烦,尤其是source files太多,依赖的header file也很多的情况下

3.2 应用场景

  • 调用第三方库
    先include_directories 和 link_directories 标记出所使用的库文件和相应头文件的位置。然后target_link_libraries

3.3 使用cmake时的一些简化技巧

改进1:source files用库文件表示

使用动态链接库,将一些source file 模块化,并且可以让项目重用
因为库也是一个target,所以和生成可执行文件没有任何区别。
项目就产生了层级关系,用一个CMakeLIsts.txt没办法完成了
需要在顶层cmakelists中对应add_directories,这样在project_binary_dir里面才会出现子文件夹,对应source 部分的子文件夹下的CMakeLists.txt才能编译。如果某一些文件夹和他的子目录都不需要编译生成target,那就不需要添加CMakeLists.txt

改进2:source files 化整为零

方法1:用 t a r g e t s o u r c e s \color {red}target_sources targetsources:将sources file分成多个子文件夹,在每个子文件夹中用target_sources进行添加,这样在顶层时,不需要一下子添加那么多sources file;
方法2:使用 F I L E ( G L O B   s o u r c e s d i r ) \color {red}FILE(GLOB \, sources dir) FILE(GLOBsourcesdir) 或者是 f i l e ( G L O B   R E C U R S E   s o u r c e s   d i r ) \color {red} file(GLOB \, RECURSE \, sources \, dir) file(GLOBRECURSEsourcesdir) 如果真的是sources files多到头皮发麻,实在是不想一个个写,用这种方法。

改进3:include_directories用usage requirements

header files经常被重复使用,这里cmake借鉴了面向对象的思想,通过target_include_directories()添加PUBLIC, PRIVATE 或者INTERFACE在target之间进行共享

改进4:用find_

有时候一些文件不知道放在什么地方了,尤其是在编译中生成的文件。
find_file, find_library_, find_path, find_program, 以及find_package

高级功能

1.因为cmake可以做一些测试,可以定义一些函数,如果其他的CMAKE需要调用这些函数,就需要INCLUDE(头文件)
2.条件编译:option,if endif, 可以用list数据结构
3.export功能
这方面目前连接的较少,后续再逐渐添加.
4.设置g++11和gnu++11:
错误提示:

#error This file requires compiler and library support for the ISO C++ 2011 standard. This support must be enabled with the -std=c++11 or -std=gnu++11 compiler options.

解决办法:在cmake中添加,参考[2]

include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
        message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

5.设置config.cmake文件
通过ubuntu apt install 的库,往往没有库对应的libconfig.cmake文件。

list(APPEND CMAKE_FIND_ROOT_PATH ${CMAKE_SOURCE_DIR})
find_package(NLOPT REQUIRED)

文件的命名NLOPTConfig.cmake

References

[1] https://www.toptal.com/c-plus-plus/c-plus-plus-understanding-compilation
[2] https://blog.csdn.net/heroacool/article/details/50906151

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值