CMAKE学习笔记

1 CMakeLists.txt基础模板

1.1 最小项目

CMakeLists.txt

# 指定使用 CMake 的最低版本号
cmake_minimum_required (VERSION 2.6)
# 指定项目名称
project (Tutorial)
# 添加可执行文件
add_executable(Tutorial tutorial.cxx)

tutorial.cxx

#include <cmath>
#include <cstdlib>
#include <iostream>
#include <string>

int main(int argc, char* argv[])
{
    if (argc < 2) {
        std::cout << "Usage: " << argv[0] << " number" << std::endl;
        return 1;
    }

    // convert input to double
    const double inputValue = atof(argv[1]);

    // calculate square root
    const double outputValue = sqrt(inputValue);
    std::cout << "The square root of " << inputValue
              << " is " << outputValue
              << std::endl;
    return 0;
}

1.2 构建、编译和运行

安装CMake、MinGW64并配置环境变量。终端进入到CMakeLists.txt目录,输入:

mkdir build
cd build
# 构建
cmake -G"MinGW Makefiles" ..
# 编译链接
cmake --build .
# 运行
.\Tutorial.exe 25
  • cmake -G<编译器名称> <CMakeLists.txt路径>
  • cmake --build <编译生成文件存放路径>

2 CMakeLists.txt优化

2.1 set 与 PROJECT_NAME

cmake_minimum_required(VERSION 2.6)
project(Tutorial)

## SET(<变量名> <变量值>)
SET(SRC_LIST tutorial.cxx)

# ${变量名}: 获取变量的值
add_executable(${PROJECT_NAME} ${SRC_LIST})

2.2 添加版本号和配置头文件

cmake_minimum_required (VERSION 2.6)
# 指定项目名及其版本号
project(Tutorial VERSION 1.0)
# 版本号也可以通过下面方式指定
## project(Tutorial)
## set (Tutorial_VERSION_MAJOR 1)
## set (Tutorial_VERSION_MINOR 0)
SET(SRC_LIST tutorial.cxx)

# 配置一个头文件,通过它向源代码中传递一些CMake设置。TutorialConfig.h.in需要我们编写,TutorialConfig.h自动生成
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"	# TutorialConfig.h.in在源文件目录下
  "${PROJECT_BINARY_DIR}/TutorialConfig.h"		# TutorialConfig.h在生成的二进制文件树目录下
  )
# 将二进制文件树添加到包含文件的搜索路径中,这样我们可以找到TutorialConfig.h
include_directories("${PROJECT_BINARY_DIR}")
# 添加可执行文件
add_executable(${PROJECT_NAME} ${SRC_LIST})

TutorialConfig.h.in

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

自动生成的TutorialConfig.h

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 0

修改tutorial.cxx

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"
#include <iostream>

int main (int argc, char *argv[]) {
      if (argc < 2) {
      // report version
      std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "." << Tutorial_VERSION_MINOR << std::endl;
      std::cout << "Usage: " << argv[0] << " number" << std::endl;
      return 1;
    }
  double inputValue = atof(argv[1]);
  double outputValue = sqrt(inputValue);
  fprintf(stdout,"The square root of %g is %g\n", inputValue, outputValue);
  return 0;
}

运行结果如下:

PS D:\CMAKE_Learn\build> .\Tutorial.exe
D:\CMAKE_Learn\build\Tutorial.exe Version 1.0
Usage: D:\CMAKE_Learn\build\Tutorial.exe number
PS D:\CMAKE_Learn\build>

2.3 指定 C++ 标准

# 指定C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

3 添加库

一般我们将库的源码放在项目源文件目录下的MathFunctions子目录中,并在该子目录(该目录下包含头文件MathFunctions.h和相关源文件mysqrt.cxx)下新建一个CMakeLists.txt,添加如下内容:

# 添加一个叫 MathFunctions 的库文件
add_library(MathFunctions mysqrt.cxx)

此时项目文件结构如下:

CMAKE_Learn/
    build/
    MathFunctions/
        CMakeLists.txt
        MathFunctions.h
        mysqrt.cxx
    CMakeLists.txt
    tutorial.cxx
    TutorialConfig.h.in

再在顶层目录下的CMakeLists.txt文件中添加如下内容:

# 向当前工程添加存放源文件的子目录,指定库所在的子目录
add_subdirectory(MathFunctions)
#生成可执行文件
add_executable(${PROJECT_NAME} tutorial.cpp)
# 指定将MathFunctions库链接到项目Tutorial的可执行文件
target_link_libraries(${PROJECT_NAME} PUBLIC MathFunctions)
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(${PROJECT_NAME} PUBLIC
                           ${PROJECT_BINARY_DIR}	# CMake生成的TutorialConfig.h存放目录
                           ${PROJECT_SOURCE_DIR}/MathFunctions	# 库的头文件存放目录
                           )

CMake中target_xxx关键字指定编译给定目标时相关内容,在上面命令中即指定Tutorial这个项目编译过程中包含的头文件目录和库文件目录。

4 将库设置为可选项

第一步是向顶级 CMakeLists.txt 文件添加一个选项。

option(USE_MYMATH "Use tutorial provided math implementation" ON)

option 表示提供用户可以选择的选项。命令格式为:option(<variable> "description [initial value])USE_MYMATH 选项的缺省值为 ON

下一步创建if语句,

if(USE_MYMATH)
  add_subdirectory(MathFunctions)
  list(APPEND EXTRA_LIBS MathFunctions)
  list(APPEND EXTRA_INCLUDES ${PROJECT_SOURCE_DIR}/MathFunctions)
endif()

add_executable(${PROJECT_NAME} tutorial.cpp)
target_link_libraries(${PROJECT_NAME} PUBLIC ${EXTRA_LIBS})
target_include_directories(${PROJECT_NAME} PUBLIC
                           ${PROJECT_BINARY_DIR}
                           ${EXTRA_INCLUDES}
                           )

APPEND表示将元素MathFunctions追加到列表EXTRA_LIBS中,将元素 ${PROJECT_SOURCE_DIR}/MathFunctions 追加到列表EXTRA_INCLUDES中。EXTRA_LIBS 存储 MathFunctions 库,EXTRA_INCLUDES 存储 MathFunctions 头文件。因此在target_link_librariestarget_include_directories中用${EXTRA_LIBS}${EXTRA_INCLUDES}分别获取库文件和头文件目录。

当然也可以通过TutorialConfig.h.in配置文件实现上述效果,修改tutorial.cxx如下:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"

#ifdef USE_MYMATH
#include "MathFunctions.h"
#endif

int main (int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stdout,"%s Version %d.%d\n", argv[0],
            Tutorial_VERSION_MAJOR,
            Tutorial_VERSION_MINOR);
        fprintf(stdout,"Usage: %s number\n",argv[0]);
        return 1;
    }
    double inputValue = atof(argv[1]);
    
#ifdef USE_MYMATH
    double outputValue = mysqrt(inputValue);
#else
    double outputValue = sqrt(inputValue);
#endif

    fprintf(stdout,"The square root of %g is %g\n", inputValue, outputValue);
    return 0;
}

TutorialConfig.h.in中添加一行,添加宏USE_MYMATH

#cmakedefine USE_MYMATH

在构建项目时可以选择性地使用库:

# 在构建项目时不使用库
cmake -DUSE_MYMATH=OFF ..

5 添加库的使用要求

库的使用要求有三个:

  • INTERFACE:表示用户需要,开发者不需要;
  • PRIVATE:表示用户不需要,开发者需要;
  • PUBLIC:表示用户和开发者都需要。

6 动态库和静态库构建

add_library(<name> [STATIC | SHARED | MODULE]
              [EXCLUDE_FROM_ALL]
              source1 source2 ... sourceN)

添加一个名为<name>的库文件,该库文件将会根据调用的命令里列出的源文件来创建。STATIC为静态库,SHARED为动态库。

静态库和动态库的区别

  • 静态库的扩展名一般为“.a”或“.lib”;动态库的扩展名一般为“.so”或“.dll”;
  • 静态库在编译链接阶段会直接整合到目标程序中,编译链接成功的可执行文件可独立运行;
  • 动态库在编译时不会放到链接的目标程序中,而是在运行阶段加载,即可执行文件无法单独运行。

7 包含第三方库

 find_package(<package> [version] [EXACT] [QUIET]
               [[REQUIRED|COMPONENTS] [components...]]
               [NO_POLICY_SCOPE])

查找并加载第三方库。该命令会设置<package>_FOUND变量,用来指示要找的包是否被找到了。REQUIRED选项表示如果报没有找到的话,cmake的过程会终止,并输出警告信息。[version]参数为第三方库的最低版本。COMPONENTS选项后面可以列出要查找的库列表(components list)。

参考

[1] https://zhuanlan.zhihu.com/p/500002865

[2] CMake Tutorial — CMake 3.25.1 Documentation

[3] https://blog.csdn.net/qq_44074143/article/details/123244847

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值