CMake简单入门——写出最基础的CMakeList.txt

What is CMake?

不同的平台有不同的编译器,例如 GNU Make , qmake , MS nmake等,如果想要软件跨平台编译就得写不同的makefile文件。
CMake让开发者编写 CMakeList.txt 文件(无关平台),用来规定整个编译的流程,然后再根据平台进一步生成所需的本地化 Makefile 和工程文件。

How to CMake?

使用vscode比较方便,只需将CMakeList.txt与源文件和头文件放入同一文件夹下,即可编译。

在这里插入图片描述
linux环境下,在命令行中进入所在目录,输入一下命令亦可:

cmake .  # 会有信息提示,无误之后才可make
make

编译可执行文件

单文件

main.c

#include <stdio.h>

int main()
{
    printf("Hello World !");
    return 0;
}

CMakeLists.txt

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo1)

# 指定生成目标
add_executable(Demo1 main.c)

#号后面跟的是注释

多个文件

同一目录:

Demo2-----
 |---main.c
 |---test.c
 |---test.h

CMakeLists.txt

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo2)

# 指定生成目标
add_executable(Demo main.c test.c)

如果源文件比较多,那么最后一行添加的文件也会比较繁琐,所以采用如下格式:

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo2)

# 将当前目录所有源文件的文件名赋值给变量 DIR_SRCS
aux_source_directory(. DIR_SRCS)

# 指定生成目标
add_executable(Demo2 ${DIR_SRCS})

aux_source_directory命令,语法如下:

aux_source_directory(<dir> <variable>)

不同目录:

Demo3------
 |---main.c
 |---Test------
 	   |---test.h
 	   |---test.c

Demo3 / CMakeLists.txt

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo3)

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)

# 添加 math 子目录
add_subdirectory(Test)

# 指定生成目标 
add_executable(Demo main.c)

# 添加链接库
target_link_libraries(Demo TEST)

Demo3 / Test / CMakeLists.txt

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)

# 生成静态链接库
add_library (TEST ${DIR_LIB_SRCS})

编译库文件(动态库、静态库)

目录结构:

|---CMakeLists.txt
|---include
	  |---hello.h
|---src
	  |---hello.cpp

CMakeLists.txt:

cmake_minimum_required(VERSION 3.1)

project(libhello)

set(libhello_src src/hello.cxx)                       # 指定库的目录变量
include_directories("${PROJECT_SOURCE_DIR}/include")  # 指定头文件搜索路径

add_library( hello SHARED ${libhello_src})          # 动态库
add_library( hello_static STATIC ${libhello_src})   # 静态库

如果想要将”hello_static“输出为hello,可以进行如下设置:

SET_TARGET_PROPERTIES (hello_static PROPERTIES OUTPUT_NAME "hello")

cmake在构建一个新的target时,会尝试清理掉同名库。(即在构建libhello.a时,就会清理掉libhello.so,或者反之)。
为了回避这个问题,可以再次使用SET_TARGET_PROPERTIES定义 CLEAN_DIRECT_OUTPUT属性

SET_TARGET_PROPERTIES (hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES (hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)

动态库应该包含一个版本号

SET_TARGET_PROPERTIES (hello PROPERTIES VERSION 1.2 SOVERSION 1)
  • VERSION指代动态库版本
  • SOVERSION指代API版本

链接指令的比较(link_directories、target_link_libraries)

link_directoriestarget_link_libraries
指定库路径只需给出动态链接库的名字
find_package、find_library可得到库的绝对路径/
用在add_executable之前用在add_executable之后

自定义编译

CMake 可以为项目增加编译选项,例如,可以将 TEST库设为一个可选的库,如果该选项为 ON ,就调用。
类似于C语言中的预定义功能

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo4)

# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
  "${PROJECT_SOURCE_DIR}/config.h.in"
  "${PROJECT_BINARY_DIR}/config.h"
  )

# 是否使用自己的 MathFunctions 库
option (USE_MYLIB "Use provided lib" ON)

# 是否加入TEST库
if (USE_MYLIB)
  include_directories ("${PROJECT_SOURCE_DIR}/Test")
  add_subdirectory (math)  
  set (EXTRA_LIBS ${EXTRA_LIBS} Test)
endif (USE_MYLIB)

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)

# 指定生成目标
add_executable(Demo4 ${DIR_SRCS})
target_link_libraries (Demo4  ${EXTRA_LIBS})
  • configure_file 命令加入一个配置头文件 config.h (由 CMake 从 config.h.in 生成)
  • option 命令添加一个 USE_MYLIB 选项,并默认为 ON(类似于C++中设置变量为true)
  • if (USE_MYLIB) 对其进行判断,是否使用TEST库

编写config.h.in 文件

#cmakedefine USE_MYLIB

编写main.c文件:

#include <stdio.h>
#include "config.h"

#ifdef USE_MYMATH
  #include "Test/test.h"
#else
  // do something  
#endif


int main()
{   
#ifdef USE_MYLIB
    printf("Use our own library. \n");
    // do something
#else
    printf("Not use our own library. \n");
    // do something
#endif

    printf("Hello World !");
    return 0;
}

安装——install

定制安装规则
在 Test/CMakeLists.txt 里添加如下内容:

# 指定 TEST 库的安装路径
install (TARGETS TEST DESTINATION bin)
install (FILES test.h DESTINATION include)

根目录的CMakeList.txt末尾添加如下内容:

# 指定安装路径
install (TARGETS Demo DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"
         DESTINATION include)
  • 生成的 Demo 文件和TEST库 libTEST.o 文件将会被复制到 /usr/local/bin 中
  • test.h 和生成的 config.h 文件会被复制到 /usr/local/include 中
  • 可以修改 CMAKE_INSTALL_PREFIX 变量的值来指定这些文件拷贝的目录

测试——add_test

CMake 提供了一个测试工具CTest,只需要在根目录的 CMakeLists 文件中调用一系列的 add_test 命令。

# 启用测试
enable_testing()

# 测试程序是否成功运行
add_test (test_run Demo)

# 测试帮助信息是否可以正常提示
add_test (test_usage Demo)
set_tests_properties (test_usage
  PROPERTIES PASS_REGULAR_EXPRESSION "Usage: .* base exponent")

# 测试 2 的 10 次方  
# DomeX为一个计算数字的程序 2和10为输入的参数
add_test (test_2_10 DemoX 2 10)

set_tests_properties (test_2_10
 PROPERTIES PASS_REGULAR_EXPRESSION "1024")
  • test_run 测试程序是否成功运行并返回 0
  • PASS_REGULAR_EXPRESSION 用来测试结果是否包含后面的字符串

如果要测试更多的输入数据可以通过编写宏来实现(此处仍然调用数字计算程序DemoX):

# 定义一个宏,用来简化测试工作
macro (do_test arg1 arg2 result)
  add_test (test_${arg1}_${arg2} DemoX ${arg1} ${arg2})
  set_tests_properties (test_${arg1}_${arg2}
    PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro (do_test)
 
# 使用该宏测试
do_test (5 2 "25")       # 测试 5 的 2 次方 是否输出为25
do_test (10 5 "100000")  # 测试 10 的 5 次方 是否输出为100000
do_test (2 10 "1024")    # 测试 2 的 10 次方 是否输出为1024

设置支持gdb

只需要指定 Debug 模式下开启 -g 选项:

set(CMAKE_BUILD_TYPE "Debug")                                   #设为debug模式
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")  # debug设置
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")         # release设置
  • CMAKE_C_FLAGS代表c文件,CFLAGS代表c的编译器参数
  • $ENV{CXXFLAGS} 表示用于c++的编译器选项

环境检查

在最上层 CMakeLists 中添加宏 CheckFunctionExists.cmake ,并使用命令 check_function_exists 测试链接器是否能够在链接阶段找到对应的Mypow函数

config.h.in 文件修改如下:

#cmakedefine HAVE_POW

顶层CMakeLists(需要在configure_file 命令前编写):

# 检查系统是否支持 pow 函数
include (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)
check_function_exists (Mypow HAVE_POW)

main.c调用大致如下:

#ifdef HAVE_POW
    // find the function
    // do something
#else
    // not find the function
    // do something
#endif

版本号

顶层 CMakeLists(project 命令之后):

set (Demo_VERSION_MAJOR 1)   # 主版本号
set (Demo_VERSION_MINOR 0)   # 副版本号

config.h.in 文件添加如下命令:

#define Demo_VERSION_MAJOR @Demo_VERSION_MAJOR@
#define Demo_VERSION_MINOR @Demo_VERSION_MINOR@

代码中打印版本信息:

printf("Version %d.%d\n", Demo_VERSION_MAJOR, Demo_VERSION_MINOR);

安装包——CPack

首先在顶层的 CMakeLists.txt 文件尾部添加下面几行:

# 构建一个 CPack 安装包
include (InstallRequiredSystemLibraries)   # 导入InstallRequiredSystemLibraries 模块
set (CPACK_RESOURCE_FILE_LICENSE
  "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set (CPACK_PACKAGE_VERSION_MAJOR "${Demo_VERSION_MAJOR}")
set (CPACK_PACKAGE_VERSION_MINOR "${Demo_VERSION_MINOR}")
include (CPack)  # 导入CPack模块
  • 导入InstallRequiredSystemLibraries 模块,以便之后导入 CPack 模块

生成二进制安装包

cpack -C CPackConfig.cmake   

会生成3 个不同格式的二进制包文件(内容一样),任选一个执行就会出现一个由 CPack 自动生成的交互式安装界面。

生成源码安装包

cpack -C CPackSourceConfig.cmake  
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值