PS:要转载请注明出处,本人版权所有。

PS: 这个只是基于《我自己》的理解,

如果和你的原则及想法相冲突,请谅解,勿喷。

前置说明

  本文作为本人csdn blog的主站的备份。(BlogID=069)

  本文发布于 2018-08-07 17:10:19,现用MarkDown+图床做备份更新。blog原图已丢失,使用csdn所存的图进行更新。(BlogID=069)

环境说明

  Linux 4.15.0-29-generic #31-Ubuntu SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

前言


  1. 我在2016-05-08的时候,写了一篇关于Makefile的文章,在我来此公司实习的时候(2016.11左右),为一个稍微大一点的项目完全手动的构建了一个基于Makefile的编译环境。现在已经过去了一年半多左右,根据此项目组的成员给我的反馈是:依然可用。但是如果要添加一些新内容到项目中,如果不了解这个Makefile的话,很有可能就是新内容没有生效。我想了想,也确实是这样的,如果不对Makefile进行一部分了解的话,想添加新的内容是很麻烦的一件事情。但是这个问题其实是Makefile只是在shell command上的一层封装,抽象的层级不是太高,也就导致了本身其构建起来很繁琐,不太适合大型工程管理和构建。

  2. 根据这两年来的接触,我经常了解到封装层级在Makefile上的框架有两个,一个是Autoconfig,一个就是CMake。其中我Autoconfig我完全停留在用的层面,完全没有去了解相关的内容,但是对于CMake,近一年多来,多次接触,苦于没有一个合适的机会进行总结。最近,由于需要为一个项目构建一套合适的编译环境,我选择了CMake,也许,这是一个合适的机会进行总结。

注意:也许我这里介绍的CMake用起来比Make或者更低一级的gcc简单了许多倍,但是,我希望各位学习此文的同时,一定要去了解了解Make和GCC相关的内容,别的不说,自己写个小工程,分别用gcc原始命令生成目标,同时用Make来生成目标。这样或许你会对此篇文章更加深刻。

CMake 简要内容


  CMake 是cross platform make的简写,从这里你完全可以看出,CMake是基于Make来实现相关的内容的,换句话说,CMake就是在Make的基础上抽象出来的更高级的框架。

  CMakeLists.txt的编译test.cpp生成test可执行文件的基本例子:

cmake_minimum_required(VERSION 2.8.10)
SET(PROJECT_NAME test)
project(${PROJECT_NAME})
add_executable(test test.cpp)

  通过以下Shell Command:

mkdir -p build && cd build && cmake .. && make

  通过上文的shell命令,其实你也已经发现了,cmake会生成Makefile,然后我们需要调用make来生成可执行文件。

CMakeLists.txt 编写要点


常用的cmake指令解释
cmake_minimum_required(VERSION xxx) #cmake最小版本需求,新版本的cmake改了很多东西,提升了便利性,也可能让你自己挖坑了
project(xxx) #设置此项目的名称
add_executable(target target_source_codes) #生成可执行文件target ,后面填写的是生成此可执行文件所依赖的源文件列表。
SET(var_name var_value)# 设置一个名字var_name 的变量,同时给此变量赋值为var_value
MESSAGE("MSG") #类比echo 打印消息
option(var_name "comment" var_value) #给变量var_name赋值为var_value,comment是此变量的注释,和SET 有类似的功效,用于给某变量设置默认值
include_directories(xxx) #添加include路径,也就是 gcc -I xxx 的意思,或者vs ide中添加头文件包含目录
add_subdirectory(xxx) #调用xxx子目录的CMakeLists.txt执行
add_compile_options(xxx) #给编译器添加xxx参数,但是貌似没有什么用,我一般不这样添加参数,不直接
link_directories(xxx) #给编译器添加库目录,也就是 gcc -L xxx 的意思,或者vs ide中添加库的包含目录
add_library(lib_name SHARED or STATIC lib_source_code) #和add_executable类似,生成库文件,SHARED代表动态库,STATIC代表静态库, 最后一个参数代表此库的源文件列表,此指令只有三个参数
target_link_libraries(target_name lib_name ...) #给目标添加依赖库,类似与gcc -l lib_name,此指令有两个用处,一个是给可执行target_name 添加库依赖,二是给库target_name 添加库依赖。

  我常见的cmake指令也就是上述的这些,还有部分比较常见的指令这里没有列出,我放到了下面单独讲解如:install()

cmake 流控制指令相关

  条件语句

if(xxx)
...
elseif(xx)
...
else()
...
endif() #常见条件语句用法为:
# if (va) va为bool型
# if (va MATCHES xxx) va 是string类型,如果va包含了xxx,则此句为真

  循环语句

foreach(va va_lists)
...
endforeach()

  在foreach中,va的值会依次被va_lists的值替换

macro 和 function
macro(name arg ...)
...
endmacro()
function(name arg ...)
...
endfunction()

  宏和函数效果都类似,唯一区别为function中的变量为局部的。

install 指令(主要是生成Makefile中的install target)
install(FILES flie DESTINATION dir_path) #执行make install时,把file拷贝到dir_path
install(PROGRAMS file DESTINATION dir_path) #执行make install时,把file拷贝到dir_path,并给予file可执行权限
INSTALL(TARGETS ylib ylib_s
#RUNTIME DESTINATION xxx
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)# 安装libylib.so到lib目录,安装libylib_s.a到lib目录,RUNTIME 是安装可执行文件到xxx目录,注意这个指令有个坑,我后面会说明这个问题。
configure_file指令
configure_file(fileA fileB @ONLY)
#把fileA 复制并重命名为fileB,此时,fileA中的@var@的值会被替换为cmakelists.txt 中var的值。@ONLY是只转换@va@这种变量
CMakeLists.txt常用的内置变量
CMAKE_INSTALL_PREFIX  #make install 的安装路径
CMAKE_BUILD_TYPE #生成的目标为debug或者release
CMAKE_C_FLAGS #gcc 的编译参数指定,这个非常好用,一般通过set 修改其值
CMAKE_CXX_FLAGS #g++ 和上面CMAKE_C_FLAGS 类似
CMAKE_CURRENT_SOURCE_DIR # 当前CMakeLists.txt所在的目录,主要用来定位某文件
CMAKE_CURRENT_BINARY_DIR # 当前CMakeLists.txt对应的编译时的目录
cross compile

  2019/5/17更新

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_SYSROOT /home/X/hisi3531d/v600_toolchains/arm-hisiv600-linux/target)
set(CMAKE_STAGING_PREFIX /home/X/libwebsockets/_install) set(tools /home/X/hisi3531d/v600_toolchains/arm-hisiv600-linux/target)
set(CMAKE_C_COMPILER ${tools}/bin/arm-hisiv600-linux-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/arm-hisiv600-linux-g++) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
XXXConfig.cmake文件(cmake模块文件)编写以及引用

  yLibConfig.cmake


find_path(yLib_INCLUDE_DIR NAMES ylib.h PATHS @CMAKE_INSTALL_PREFIX@/include) find_library(yLib_LIBRARY NAMES ylib PATHS @CMAKE_INSTALL_PREFIX@/lib)
#find_library 会到@CMAKE_INSTALL_PREFIX@/lib目录查询libylib.so set(yLib_FOUND TRUE)
set(yLib_INCLUDE_DIRS ${yLib_INCLUDE_DIR})
set(yLib_LIBS ${yLib_LIBRARY}) mark_as_advanced(yLib_INCLUDE_DIRS yLib_LIBS )
  • XXX_INCLUDE_DIR
  • XXX_LIBRARY
  • XXX_FOUND
  • XXX_INCLUDE_DIRS
  • XXX_LIBS

  以上变量最好都定义了,不然find_package可能会报错

  .cmake 文件就是定义了相关include变量和lib变量,没有什么其他的东西

  调用:

set(yLib_DIR "@CMAKE_INSTALL_PREFIX@/cmake")
#设置.cmake 的目录所在
find_package(yLib REQUIRED)
#find_package会导入.cmake 中的相关变量,完成相关模块的导入
一个关于install()指令的深坑
INSTALL(TARGETS  ylib ylib_s
#RUNTIME DESTINATION xxx
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
#对于RUNTIME 和 LIBRARY 两种目标,在安装时候,cmake会默认给你移除掉目标文件中的gcc的Wl,rpath的值,导致某些库找不到的错误。
以下变量会影响此坑,更详细的信息去查查别的资料,我这里就不详细说明了。
#set(CMAKE_SKIP_BUILD_RPATH FALSE)
#set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
#set(CMAKE_INSTALL_RPATH "")
#set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
#set(CMAKE_SKIP_INSTALL_RPATH TRUE)
#set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") #set(CMAKE_SKIP_RPATH TRUE)
#set(CMAKE_SKIP_INSTALL_RPATH TRUE)

注意:cmake会直接修改你的二进制文件替换掉rpath的相关信息。默认替换的值是一个空值,也就是说移除掉了你设置的rpath的值

以上只是介绍了cmake中常见的内容,而且很多内容只涉及到一般的使用方法,某些指令还有很多其他的操作,我这里没有介绍。如果需要了解更加详细的信息,我推荐各位去看cmake 的doc。

后记


  无

参考文献


打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

CMakeLists.txt 编写要点 && 一个关于install()的深坑的更多相关文章

  1. CMake之CMakeLists.txt编写入门

    自定义变量 主要有隐式定义和显式定义两种. 隐式定义的一个例子是PROJECT指令,它会隐式的定义< projectname >_BINARY_DIR和< projectname & ...

  2. CMakeLists.txt编写常用命令

    目录 1. 设置cmake最小版本 2. 设置项目名称 3. 设置编译目标类型 4. 指定编译包含的源文件 1. 明确指明包含的源文件 2. 搜索指定目录的所有的cpp文件 3. 自定义搜索规则 4. ...

  3. CMAKE 生成VS2008静态库工程 与 CMAKE使用,CMakeLists.txt编写总结

    cmake -G"Visual Studio 9 2008 Win64" 以上命令得用cd命令切换到顶层CMakeLists.txt的当前目录,才能生效 以下是CMakeLists ...

  4. ubuntu下opencv CMakeLists.txt编写

    # 声明要求的 cmake 最低版本 cmake_minimum_required( VERSION 2.8 ) # 声明一个 cmake 工程 project( pro ) # 设置编译模式 set ...

  5. CMakeList.txt(2):CMakeLists.txt编写规则

    #project namePROJECT(test_math)    指定生成的工程名为test_math #head file path     INCLUDE_DIRECTORIES(includ ...

  6. Linux c++ vim环境搭建系列(6)——CMakeLists.txt多文档多目录组织方法和编写示例

    CMakeLists.txt学习 1. 概要 主要是关于cmakelists.txt的编写模板,和多文档多目录的组织方法详解, 涉及第三方库的添加使用方法. 这里主要介绍cmakelists.txt的 ...

  7. 用CMakeLists.txt组织工程

    1 一个工程会有多个CMakeLists.txt,如何组织这些CMakeLists.txt来构建一个工程? 1.1  最外层一个CMakeLists.txt,是总的CMakeList.txt,在这个里 ...

  8. ROS学习笔记三:编写第一个ROS节点程序

    在编写第一个ROS节点程序之前需要创建工作空间(workspace)和功能包(package).   1 创建工作空间(workspace) 创建一个catkin_ws: #注意:如果使用sudo一次 ...

  9. CMakeLists.txt使用

    背景:C++代码在编译的过程中需要进行文件的包含,该文主要介绍CMakeLists.txt相关语法 CMake之CMakeLists.txt编写入门

  10. ubuntu 16.04上源码编译和安装cgal并编写CMakeLists.txt | compile and install cgal on ubuntu 16.04

    本文首发于个人博客https://kezunlin.me/post/39ab7ed9/,欢迎阅读最新内容! compile and install cgal on ubuntu 16.04 Guide ...

随机推荐

  1. ElasticSearch7.3学习(十)----采用restful风格对索引的增删改查

    1. 为什么需要手动创建索引 直接put数据 PUT index/_doc/1,es会自动生成索引,并建立动态映射dynamic mapping.这样的话很大可能与实际的需求不服,在实际的应用上,我们 ...

  2. C#/.NET该如何自学入门?

    前言 随着DotNetGuide技术社区交流群的不断壮大(目前4个群都已经满500人,已开5群现已有180多个小伙伴),越来越多应届生和其他领域的小伙伴加入了我们这个大家庭.在此期间我在个人微信.公众 ...

  3. NC16681 [NOIP2003]加分二叉树

    题目链接 题目 题目描述 ​ 设一个n个节点的二叉树tree的中序遍历为(l,2,3,-,n),其中数字1,2,3,-,n为节点编号.每个节点都有一个分数(均为正整数),记第j个节点的分数为di,tr ...

  4. NC207781 迁徙过程中的河流

    题目链接 题目 题目描述 牛市的幸存的先民在流星雨之后就忍痛离开了这片土地,选择迁徙,在迁徙的途中,他们需要渡过一条河.因为牛市的树木在流星雨中被严重破坏,所以他们只造出了一艘小船,船太小了,一次只能 ...

  5. Typora 使用和自定义设置

    版本 新的版本都已经收费, 因此继续使用原来的beta版本, 当前使用的是0.9.92 修改字体 默认的字体偏大 File -> Preference -> Appearance, Ope ...

  6. SpringBoot整合ip2region实现使用ip监控用户访问地域来源

    举个栗子 最*,多*台都上线了展示*期发帖所在地功能,比如抖音.微博.百度,像下面那样: 那么这个功能都是如何实现的呢? 一般有两个方法:GPS 定位的信息和用户 IP 地址. 由于每个手机都不一定会 ...

  7. 使用SecScanC2构建P2P去中心化网络实现反溯源

    个人博客: xzajyjs.cn 前言 这款工具是为了帮助安全研究人员在渗透测试过程中防止扫描被封禁.保护自己免溯源的一种新思路.其利用到了区块链中的p2p点对点去中心化技术构建以来构建代理池. 工具 ...

  8. 硬件开发笔记(十一):Altium Designer软件介绍、安装过程和打开pcb工程测试

    前言   前面做高速电路,选择是阿li狗,外围电路由于读者熟悉AD,使用使用ad比较顺手,非高速电路就使用AD了,其实AD也可以做高速电路,由于笔者从13年开始做硬是从AD9开始的,所以开始切入AD做 ...

  9. python开发接口时,使用jsonschema模块对数据进行校验

    import jsonschema schema = { "type": "object", # 先声明每个键都是对象 "properties&quo ...

  10. maven配置全局私服地址和阿里云仓库

    直接上配置代码 <?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apa ...