CMakeLists实战学习

本文详细介绍了CMakeLists的使用,包括重要指令如`cmake_minimum_required`, `project`, `set`, `include_directories`, `link_directories`等。讨论了构建方式,如内部构建和外部构建,并列举了常用变量。此外,还展示了如何处理单个源文件和多个源文件的项目,以及如何添加自定义编译选项和管理子目录。" 122058737,11592676,Java继承应用:老师与学生的实例,"['后端开发', 'Java', '面向对象']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

重要指令

  • cmake_minimum_required 指定CMAKE的最小版本
    • 语法cmake_minimum_required(VERSION versionNumber [FATAL_ERROR])
# CMake最小版本要求为2.8.3
cmake_minimum_required(VERSION 2.8.3)
  • project- 定义工程名称,并可指定工程支持的语言
    • 语法:project(projectname [CXX] [C] [Java])
# 指定工程名为demo
project(demo)
  • set- 显式的定义变量
    • 语法:set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
# 定义SRC变量,其值为sayhello.cpp hello.cpp
set(SRC sayhello.cpp hello.cpp)
  • include_directories - 向工程添加多个特定的头文件搜索路径 —>相当于指定g++编译器的-I参数
    • 语法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)
# 将/usr/include/myincludefolder 和 ./include 添加到头文件搜索路径
include_directories(/usr/include/myincludefolder ./include)
  • ink_directories- 向工程添加多个特定的库文件搜索路径 —>相当于指定g++编译器的-L参数
    • 语法:link_directories(dir1 dir2 …)
# 将/usr/lib/mylibfolder 和 ./lib 添加到库文件搜索路径
link_directories(/usr/lib/mylibfolder ./lib)
  • add_compile_options - 添加编译参数
# 添加编译参数 -Wall -std=c++11 -O2
add_compile_options(-Wall -std=c++11 -O2)
  • add_executable- 生成可执行文件
    • add_executable(exe_name source1 source 2)
# 编译main.cpp生成可执行文件main
add_executable(main main.cpp)
  • target_link_libraries- 为 target 添加需要链接的共享库—>相同于指定g++编译器-l参数
    • 语法:target_link_libraries(target library1<debug | optimized> library2…)
# 将hello动态库文件链接到可执行文件main
target_link_libraries(main hello)
  • add_subdirectory - 向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置
    • 语法: add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
# 添加src子目录,src中需有一个CMakeLists.txt
add_subdirectory(src)
  • aux_source_directory - 发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表
    • 语法:aux_source_directory(dir VARIABLE)
# 定义SRC变量,其值为当前目录下所有的源代码文件
aux_source_directory(. SRC)
# 编译SRC变量所代表的源代码文件,生成main可执行文件
add_executable(main ${SRC})

构建方式

  • 内部构建(in-source build):和源码在一起build,会显得杂乱无章
# 在当前目录下,编译本目录的CMakeLists.txt,生成Makefile和其他文件
cmake .
# 执行make命令,生成target
make
  • 外部构建(out-of-source build):将编译输出文件与源文件放到不同目录中
# 1. 在当前目录下,创建build文件夹
mkdir build 
# 2. 进入到build文件夹
cd build
# 3. 编译上级目录的CMakeLists.txt,生成Makefile和其他文件
cmake ..
# 4. 执行make命令,生成target
make

常用变量

  • CMAKE_CXX_FLAGS g++编译选项
# 在CMAKE_CXX_FLAGS编译选项后追加-std=c++11
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
  • CMAKE_BUILD_TYPE编译类型(Debug, Release)
# 设定编译类型为debug,调试时需要选择debug
set(CMAKE_BUILD_TYPE Debug)
 # 设定编译类型为release,发布时需要选择release
 set(CMAKE_BUILD_TYPE Release) 
  • CMAKE_BINARY_DIR, PROJECT_BINARY_DIR, _BINARY_DIR

    • 这三个变量指代的内容是一致的。
    • 如果是 in source build,指的是工程顶层目录
    • 如果是 out-of-source 编译,值得是工程编译发生目录(build)
  • CMAKE_BINARY_DIR, PROJECT_BINARY_DIR, _BINARY_DIR

    • 这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程顶层目录
  • EXECUTABLE_OUTPUT_PATH:可执行文件输出的存放路径

  • LIBRARY_OUTPUT_PATH:库文件输出的存放路径

  • CMAKE_CXX_COMPILER:指定C++编译器

单个源文件

这时的源文件

#include <stdio.h>
#include <stdlib.h>

/**
 * power - Calculate the power of number.
 * @param base: Base value.
 * @param exponent: Exponent value.
 *
 * @return base raised to the power exponent.
 */
double power(double base, int exponent)
{
    int result = base;
    int i;
    
    if (exponent == 0) {
        return 1;
    }
    
    for(i = 1; i < exponent; ++i){
        result = result * base;
    }

    return result;
}

int main(int argc, char *argv[])
{
    if (argc < 3){
        printf("Usage: %s base exponent \n", argv[0]);
        return 1;
    }
    double base = atof(argv[1]);
    int exponent = atoi(argv[2]);
    double result = power(base, exponent);
    printf("%g ^ %d is %g\n", base, exponent, result);
    return 0;
}

因为这时只有一个源文件,所以cmakelists也比较简单.
这里需要讲一下main函数的输入main(int argc, char *argv[])

  • argc 是 argument count的缩写,表示传入main函数的参数个数;
  • argv 是 argument vector的缩写,表示传入main函数的参数序列或指针,并且第一个参数argv[0]一定是程序的名称,并且包含了程序所在的完整路径,所以确切的说需要我们输入的main函数的参数个数应该是argc-1个
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo1)

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

这是最简单的cmakelists, 其包含

  1. cmake_minimum_required: 指定运行此配置文件所需的 CMake 的最低版本
  2. project:参数值是 Demo1,该命令表示项目的名称是 Demo1 。
  3. add_executable: 将名为 main.cc 的源文件编译成一个名称为 Demo 的可执行文件。

将上述文件配置好后,依次执行

cmake .
make
可得到一个可执行文件Demo

在这里插入图片描述

多个源文件

同一个目录

MathFunctions.cc

/**
 * power - Calculate the power of number.
 * @param base: Base value.
 * @param exponent: Exponent value.
 *
 * @return base raised to the power exponent.
 */
double power(double base, int exponent)
{
    int result = base;
    int i;

    if (exponent == 0) {
        return 1;
    }
    
    for(i = 1; i < exponent; ++i){
        result = result * base;
    }

    return result;
}

MathFunctions.h


#ifndef POWER_H
#define POWER_H

extern double power(double base, int exponent);

#endif

main.cc


#include <stdio.h>
#include <stdlib.h>
#include "MathFunctions.h"

int main(int argc, char *argv[])
{
    if (argc < 3){
        printf("Usage: %s base exponent \n", argv[0]);
        return 1;
    }
    double base = atof(argv[1]);
    int exponent = atoi(argv[2]);
    double result = power(base, exponent);
    printf("%g ^ %d is %g\n", base, exponent, result);
    return 0;
}

CMakeLists.txt

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

# 项目信息
project (Demo2)

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

相对于第一个cmakelist。这里仅仅在add_executable里添加了一个MathFunctions.cc
如果文件过多,一个个的添加,太麻烦了
这时我们可以使用aux_source_directory命令
该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名
格式 aux_source_directory(<dir> <variable>) (目录 将所有源文件加入变量名)

新的CMakeLists.txt

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

# 项目信息
project (Demo2)

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

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

不同一个目录

这时由于main和函数不在同一个文件夹中,所以需要对main中的include进行修改

#include "math/MathFunctions.h"

主函数和mathFunction不在一个目录,这时需要在Demo3和math文件夹中各编写一个CMakeLists.txt文件。math文件夹中的cmakelists主要是将文件编译成静态库,再由main函数调用

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

# 项目信息
project (Demo3)

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

# 添加 math 子目录
add_subdirectory(math)

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

# 添加链接库
target_link_libraries(Demo MathFunctions)

add_subdirectory(math) 包含子目录,使子目录的cmakelists也可被处理
target_link_libraries指明main函数需要一个MathFunctions的库

除此之外,我们还需要在math文件夹下添加一个CmakeLists.txt,目的是让其能编译成静态库

add_library (MathFunctions ${DIR_LIB_SRCS}) 将源文件编译成MathFunctions库

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

# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})

自定义编译选项

将自定义的库作为一个可选项
例如,可以将 MathFunctions 库设为一个可选的库,如果该选项为 ON ,就使用该库定义的数学函数来进行运算。否则就调用标准库中的数学函数库。
CMakeLists.txt

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

# 项目信息
project (Demo4)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
	   "Use provided maths implementation" ON)

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

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

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

# 指定生成目标
add_executable (Demo ${DIR_SRCS})
target_link_libraries (Demo  ${EXTRA_LIBS})

  1. configure_file 命令用于加入一个配置头文件 config.h ,这个文件由 CMake 从
    config.h.in 生成,通过这样的机制,将可以通过预定义一些参数和变量来控制代码的生成。
  2. set(CMAKE_INCLUDE_CURRENT_DIR ON) 使得能够包含本地新生成的config.h
  3. option命令添加了一个 USE_MYMATH 选项,并且默认值为 ON 。
  4. 判断句根据USE_MYMATH的值,开决定是否编译库

main也需要修改。根据USE_MYMATH的值决定用哪个库

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

#ifdef USE_MYMATH
  #include "math/MathFunctions.h"
#else
  #include <math.h>
#endif


int main(int argc, char *argv[])
{
    if (argc < 3){
        printf("Usage: %s base exponent \n", argv[0]);
        return 1;
    }
    double base = atof(argv[1]);
    int exponent = atoi(argv[2]);
    
#ifdef USE_MYMATH
    printf("Now we use our own Math library. \n");
    double result = power(base, exponent);
#else
    printf("Now we use the standard library. \n");
    double result = pow(base, exponent);
#endif
    printf("%g ^ %d is %g\n", base, exponent, result);
    return 0;
}

编写 config.h.in 文件
上述main文件include了config.h 文件,这个文件预定义了 USE_MYMATH 的值。但我们并不直接编写这个文件,为了方便从 CMakeLists.txt 中导入配置,我们编写一个 config.h.in 文件,内容如下

#cmakedefine USE_MYMATH

编译项目,这时我们可使用交互式编译方式,编译该项目

# 交互式配置界面
ccmake .
# 完成配置 
c
# 生成Makefile
g

Reference
5. C++ main函数中参数argc和argv含义及用法
6. CMAKE入门实战
7. cmake tutorials

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值