cmake的基本参数和用法

cmake的基本参数和用法

亚古兽要进化

于 2018-10-23 11:00:58 发布

31444
收藏 120
分类专栏: 配置 文章标签: cmake
版权

配置
专栏收录该内容
11 篇文章2 订阅
订阅专栏
1.CMake编译原理
CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多。CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库(so(shared object))。因此CMake的编译基本就两个步骤:

1. cmake
2. make
cmake 指向CMakeLists.txt所在的目录,例如cmake .. 表示CMakeLists.txt在当前目录的上一级目录。cmake后会生成很多编译的中间文件以及makefile文件,所以一般建议新建一个新的目录,专门用来编译,例如

mkdir build
cd build
cmake ..
make
make根据生成makefile文件,编译程序。

这里提供一份cmake专栏写的特别好的链接

2.使用Cmake编译程序
我们编写一个关于开平方的C/C++程序项目,即b= sqrt(a),以此理解整个CMake编译的过程。

a.准备程序文件

文件目录结构如下:

.
├── build
├── CMakeLists.txt
├── include
│ └── b.h
└── src
├── b.c
└── main.
头文件b.h,如下所示:

#ifndef B_FILE_HEADER_INC
#define B_FIEL_HEADER_INC

#include<math.h>

double cal_sqrt(double value);

#endif
头文件b.c,如下所示:

#include "../include/b.h"

double cal_sqrt(double value)
{
return sqrt(value);
}
main.c主函数,如下所示:

#include "../include/b.h"
#include <stdio.h>
int main(int argc, char** argv)
{
double a = 49.0;
double b = 0.0;

printf("input a:%f\n",a);
b = cal_sqrt(a);
printf("sqrt result:%f\n",b);
return 0;
}
b.编写CMakeLists.txt

接下来编写CMakeLists.txt文件,该文件放在和src,include的同级目录,实际放在哪里都可以,只要里面编写的路径能够正确指向就好了。其语法支持大小写混编,如:

cmake_minimum_required
CMAKE_MINIMUM_REQUIRED
cmake_MINUMUM_required
CMakeLists.txt文件,如下所示:

1 #1.cmake verson,指定cmake版本
2 cmake_minimum_required(VERSION 3.2)
3
4 #2.project name,指定项目的名称,一般和项目的文件夹名称对应
5 PROJECT(test_sqrt)
6
7 #3.head file path,头文件目录
8 INCLUDE_DIRECTORIES(
9 include
10 )
11
12 #4.source directory,源文件目录
13 AUX_SOURCE_DIRECTORY(src DIR_SRCS)
14
15 #5.set environment variable,设置环境变量,编译用到的源文件全部都要放到这里,否则编译能够通过,但是执行的时候会出现各种问题,比如"symbol lookup error xxxxx , undefined symbol"
16 SET(TEST_MATH
17 ${DIR_SRCS}
18 )
19
20 #6.add executable file,添加要编译的可执行文件
21 ADD_EXECUTABLE(${PROJECT_NAME} ${TEST_MATH})
22
23 #7.add link library,添加可执行文件所需要的库,比如我们用到了libm.so(命名规则:lib+name+.so),就添加该库的名称
24 TARGET_LINK_LIBRARIES(${PROJECT_NAME} m)
CMakeLists.txt主要包含以上的7个步骤,为了方便还可以添加很多预定义变量.

文章引用: https://blog.csdn.net/wzzfeitian/article/details/40963457?utm_source=blogxgwz13

更简单版本:

只一个main2.cpp文件

cmake_minimum_required (VERSION 2.6)
project (test)
add_executable(test main2.cpp)


从这个更简单的版本可以看出,一个cmake文件至少有这三行组成

常碰到的问题可以参考这里:https://blog.csdn.net/whahu1989/article/details/82078563

cmake中一些预定义变量
cmake中一些预定义变量
PROJECT_SOURCE_DIR 工程的根目录
PROJECT_BINARY_DIR 运行cmake命令的目录,通常是${PROJECT_SOURCE_DIR}/build
CMAKE_INCLUDE_PATH 环境变量,非cmake变量
CMAKE_LIBRARY_PATH 环境变量
CMAKE_CURRENT_SOURCE_DIR 当前处理的CMakeLists.txt所在的路径
CMAKE_CURRENT_BINARY_DIR target编译目录
使用ADD_SURDIRECTORY(src bin)可以更改此变量的值
SET(EXECUTABLE_OUTPUT_PATH <新路径>)并不会对此变量有影响,只是改变了最终目标文件的存储路径
CMAKE_CURRENT_LIST_FILE 输出调用这个变量的CMakeLists.txt的完整路径
CMAKE_CURRENT_LIST_LINE 输出这个变量所在的行
CMAKE_MODULE_PATH 定义自己的cmake模块所在的路径
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块
EXECUTABLE_OUTPUT_PATH 重新定义目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH 重新定义目标链接库文件的存放位置
PROJECT_NAME 返回通过PROJECT指令定义的项目名称
CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS 用来控制IF ELSE语句的书写方式
系统信息

CMAKE_MAJOR_VERSION cmake主版本号,如2.8.6中的2
CMAKE_MINOR_VERSION cmake次版本号,如2.8.6中的8
CMAKE_PATCH_VERSION cmake补丁等级,如2.8.6中的6
CMAKE_SYSTEM 系统名称,例如Linux-2.6.22
CAMKE_SYSTEM_NAME 不包含版本的系统名,如Linux
CMAKE_SYSTEM_VERSION 系统版本,如2.6.22
CMAKE_SYSTEM_PROCESSOR 处理器名称,如i686
UNIX 在所有的类UNIX平台为TRUE,包括OS X和cygwin
WIN32 在所有的win32平台为TRUE,包括cygwin
开关选项

BUILD_SHARED_LIBS 控制默认的库编译方式。如果未进行设置,使用ADD_LIBRARY时又没有指定库类型,默认编译生成的库都是静态库 (可在t3中稍加修改进行验证)

CMAKE_BUILD_TYPE 设置模式是Debug还是Release模式

SET(CMAKE_BUILD_TYPE "Debug”)
or
SET(CMAKE_BUILD_TYPE "Release")
也可以在执行cmake命令式在外部执行:

cmake -DCMAKE_BUILD_TYPE=Release ..
CMAKE_C_FLAGS 设置C编译选项
CMAKE_CXX_FLAGS 设置C++编译选项

编译选项具体说明:

在CMakeLists.txt中可能会看到这样的命令设置C或者C++的编译选项:

#SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -O0 -Wall -g -ggdb")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3 -Wall")
后面跟随的-O3 -Wall的是什么意思?这个参数是gcc或者g++进行编译时设置的参数;

gcc中常用的编译选项有:

-c 只编译并生成目标文件:将汇编代码编译成目标文件,即二进制代码。-c 可以直接把 C/C++ 代码编译成机器代码,注意此时并没有链接生成可执行文件这样的步骤,因此,对于链接中的错误是无法发现的。

-g 生成调试信息。GNU 调试器可利用该信息。

-S 只是编译不汇编,生成汇编代码

-shared 生成共享目标文件。通常用在建立共享库时。
-W 开启所有 gcc 能提供的警告。
-w 不生成任何警告信息。
-Wall 生成所有警告信息。

-O0 -O1 -O2 -O3 四级优化选项:
-O0 不进行优化处理: 不做任何优化,这是默认的编译选项
-O 或 -O1 优化生成代码。 优化会消耗少多的编译时间,它主要对代码的分支,常量以及表达式等进行优化
-O2 进一步优化。会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间

-Os 相对语-O2.5。相当于-O2.5。是使用了所有-O2的优化选项,但又不缩减代码尺寸的方法。
-O3 比 -O2 更进一步优化,包括 inline 函数。在O2的基础上进行更多的优化


CMake常用命令
1)project 命令

命令语法:project(<projectname> [languageName1 languageName2 … ] )

命令简述:用于指定项目的名称

使用范例:project(Main)

2)cmake_minimum_required命令

命令语法:cmake_minimum_required(VERSION major[.minor[.patch[.tweak]]][FATAL_ERROR])

命令简述:用于指定需要的 CMake 的最低版本

使用范例:cmake_minimum_required(VERSION 2.8)

3)aux_source_directory命令

命令语法:aux_source_directory(<dir> <variable>)

命令简述:用于将 dir 目录下的所有源文件的名字保存在变量 variable 中

使用范例:aux_source_directory(. DIR_SRCS),将当前目录下的所有源文件加入到DIR_SRCS,如果多个源文件,则DIR_SRCS试一个list。

4)add_executable 命令

命令语法:add_executable(<name> [WIN32] [MACOSX_BUNDLE][EXCLUDE_FROM_ALL] source1 source2 … sourceN)

命令简述:用于指定从一组源文件 source1 source2 … sourceN 编译出一个可执行文件且命名为 name

使用范例:add_executable(Main ${DIR_SRCS})

5)add_library 命令

命令语法:add_library([STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1source2 … sourceN)

命令简述:用于指定从一组源文件 source1 source2 … sourceN 编译出一个库文件且命名为 name

使用范例:add_library(Lib ${DIR_SRCS}),和add_executable相比,这里是成的库,而add_executable是生成可执行文件。因此,这里的STATIC、SHARED分别表示在生成的是静态库还是动态库。

6)add_dependencies 命令

命令语法:add_dependencies(target-name depend-target1 depend-target2 …)

命令简述:用于指定某个目标(可执行文件或者库文件)依赖于其他的目标。这里的目标必须是 add_executable、add_library、add_custom_target 命令创建的目标

7)add_subdirectory 命令

命令语法:add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

命令简述:用于添加一个需要进行构建的子目录,意味着该目录下也有个CMakeLists.txt 文件

使用范例:add_subdirectory(Lib)

8)target_link_libraries与link_libraries命令

两则关系: link_libraries用在add_executable之前,target_link_libraries用在add_executable之后; link_libraries用来链接静态库,target_link_libraries用来链接导入库,即按照header file + .lib + .dll方式隐式调用动态库的.lib库

命令语法:target_link_libraries(<target> [item1 [item2 […]]][[debug|optimized|general] ] …)

命令简述:用于指定 target 需要链接 item1 item2 …。这里 target 必须已经被创建,链接的 item 可以是已经存在的 target(依赖关系会自动添加)

使用范例:target_link_libraries(Main Lib);link_libraries(/home/myproject/libs)

解释:为Main项目(可以为执行文件,也可以为库)添加依赖库Lib。Lib可以为多个。比如:动态库所在目录为/home/myproject/libs,那么在add_executable之前使用link_libraries(/home/myproject/libs)指明动态库位置,在add_executable之后,只需给出动态链接库的库名字就行。target_link_libraries(Main -lcurl)

9)set 命令

命令语法:set(<variable> <value> [[CACHE <type><docstring> [FORCE]] | PARENT_SCOPE])

命令简述:用于设定变量 variable 的值为 value。如果指定了 CACHE 变量将被放入 Cache(缓存)中。

使用范例1:set(ProjectName Main);

使用范例2:set(var a;b;c) <=> set(var a b c) #定义变量var并赋值为a;b;c这样一个string list

10)unset 命令

命令语法:unset(<variable> [CACHE])

命令简述:用于移除变量 variable。如果指定了 CACHE 变量将被从 Cache 中移除。

使用范例:unset(VAR CACHE)

11)message 命令

命令语法:message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] “message todisplay”…)

命令简述:用于输出信息,STATUS表示正常提示,WARNING就是警告 提示,FATAL_ERROR重大错误提示...

使用范例:message(STATUS “Hello World”),STATUS可以不添加。

12)include_directories 命令

命令语法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)

命令简述:用于设定目录,这些设定的目录将被编译器用来查找 include 文件

使用范例:include_directories(${PROJECT_SOURCE_DIR}/lib),添加在工程目录下的lib子文件夹目录

13)find_path 命令

命令语法:find_path(<VAR> name1 [path1 path2 …])

命令简述:用于查找包含文件 name1 的路径,如果找到则将路径保存在 VAR 中(此路径为一个绝对路径),如果没有找到则结果为 <VAR>-NOTFOUND。默认的情况下,VAR 会被保存在 Cache 中,这时候我们需要清除 VAR 才可以进行下一次查询(使用 unset 命令)。

使用范例:

find_path(LUA_INCLUDE_PATH lua.h${LUA_INCLUDE_FIND_PATH})

if(NOT LUA_INCLUDE_PATH)

message(SEND_ERROR "Header file lua.h not found")

endif()

14)find_library 命令

命令语法:find_library(<VAR> name1 [path1 path2 …])

命令简述:用于查找库文件 name1 的路径,如果找到则将路径保存在 VAR 中(此路径为一个绝对路径),如果没有找到则结果为 <VAR>-NOTFOUND。一个类似的命令 link_directories 已经不太建议使用了

15)add_definitions 命令

命令语法:add_definitions(-DFOO -DBAR …)

命令简述:用于添加编译器命令行标志(选项),通常的情况下我们使用其来添加预处理器定义

使用范例:add_definitions(-D_UNICODE -DUNICODE), 使用细节参考这里

16)execute_process 命令

命令语法:

execute_process(COMMAND <cmd1>[args1...]]

[COMMAND <cmd2>[args2...] [...]]

[WORKING_DIRECTORY<directory>]

[TIMEOUT <seconds>]

[RESULT_VARIABLE<variable>]

[OUTPUT_VARIABLE<variable>]

[ERROR_VARIABLE<variable>]

[INPUT_FILE <file>]

[OUTPUT_FILE <file>]

[ERROR_FILE <file>]

[OUTPUT_QUIET]

[ERROR_QUIET]

[OUTPUT_STRIP_TRAILING_WHITESPACE]

[ERROR_STRIP_TRAILING_WHITESPACE])

命令简述:用于执行一个或者多个外部命令。每一个命令的标准输出通过管道转为下一个命令的标准输入。WORKING_DIRECTORY 用于指定外部命令的工作目录,RESULT_VARIABLE 用于指定一个变量保存外部命令执行的结果,这个结果可能是最后一个执行的外部命令的退出码或者是一个描述错误条件的字符串,OUTPUT_VARIABLE 或者 ERROR_VARIABLE 用于指定一个变量保存标准输出或者标准错误,OUTPUT_QUIET 或者 ERROR_QUIET 用于忽略标准输出和标准错误。

使用范例:execute_process(COMMAND ls)

18)file 命令

命令简述:此命令提供了丰富的文件和目录的相关操作(这里仅说一下比较常用的)

使用范例:

# 目录的遍历

# GLOB 用于产生一个文件(目录)路径列表并保存在variable 中

# 文件路径列表中的每个文件的文件名都能匹配globbing expressions(非正则表达式,但是类似)

# 如果指定了 RELATIVE 路径,那么返回的文件路径列表中的路径为相对于 RELATIVE 的路径

# file(GLOB variable [RELATIVE path][globbing expressions]...)

 

# 获取当前目录下的所有的文件(目录)的路径并保存到 ALL_FILE_PATH 变量中

file(GLOB ALL_FILE_PATH ./*)

# 获取当前目录下的 .h 文件的文件名并保存到ALL_H_FILE 变量中,*表示所有文件,*.cpp表示所有.cpp文件

# 这里的变量CMAKE_CURRENT_LIST_DIR 表示正在处理的 CMakeLists.txt 文件的所在的目录的绝对路径(2.8.3 以及以后版本才支持)

file(GLOB ALL_H_FILE RELATIVE${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/*.h)

19) function

function 的正确写法如下:

function(<name> [arg1 [arg2 [arg3 ...]]])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
function(<name>)
其中name为函数名,后面的arg为参数。我们除了可以用${arg1}来引用变量以外,系统为我们提供了一些特殊的变量:

变量 说明
ARGV# #是一个下标,0指向第一个参数,累加
ARGV 所有的定义时要求传入的参数
ARGN 定义时要求传入的参数以外的参数,比如定义宏(函数)时,要求输入1个,实际输入了3个,则剩下的两个会以数组形式存储在ARGN中
ARGC
传入的实际参数的个数,也就是调用函数是传入的参数个数

function(BAR arg1)
message(STATUS "this is arg1:${arg1},ARGV0=${ARGV0}")
message(STATUS "this is argn:${ARGN}")
if(arg1 STREQUAL first)
message(STATUS "this is first")
endif()
set(arg1 ten)
message(STATUS "after set arg1=${arg1}")
endfunction(BAR arg1)

set(p6 first)
set(p7 second)
BAR(${p6} ${p7})
message(STATUS "after bar p6=${p6}")


打印结果:

-- this is arg1:first,ARGV0=first
-- this is argn:second
-- this is first
-- after set arg1=ten
-- after bar p6=first

20)find_package:

把整个依赖包的头文件包含路径、库路径、库名字、版本号等情况都获取到,比如opencv的相关信息:

cmake_minimum_required (VERSION 2.6)
project (ImageBlend)
add_definitions(-std=c++11)
find_package(OpenCV 3.2.0 REQUIRED )
# find_package(OpenCV 4.1.0 REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable(ImageBlend main2.cpp)
target_link_libraries( ImageBlend ${OpenCV_LIBS} )
find_package(OpenCV 3.2.0 REQUIRED ),其中的3.2.0是制定版本。如果系统中版本过多,不加此版本号,就按照相应的搜索规则进行,那么就可能面临版本号不对应出现的问题。具体用法可以参考这里:文献一,文献二

cmake2.8的命令可以在此查询:

http://www.cmake.org/cmake/help/v2.8.8/cmake.html#section_Commands

大神翻译版本:

https://www.cnblogs.com/coderfenghc/tag/cmake/

make的常用命令

在cmake 编译了相关文件后,还需要make一下,相当于编译文件。make还有一些其他命令如下:

make all:编译程序、库、文档等(等同于make)

make install:安装已经编译好的程序。复制文件树中到文件到指定的位置

make unistall:卸载已经安装的程序。

make clean:删除由make命令产生的文件

make distclean:删除由./configure产生的文件

make check:测试刚刚编译的软件(某些程序可能不支持)

make installcheck:检查安装的库和程序(某些程序可能不支持)

make dist:重新打包成packname-version.tar.gz
————————————————
版权声明:本文为CSDN博主「亚古兽要进化」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq26983255/article/details/83303606

posted on 2022-10-20 20:59  zxddesk  阅读(869)  评论(0编辑  收藏  举报

导航