cmake入门到入土
介绍
CMakeLists.txt 的语法比较简单,由命令、注释和空格组成,其中命令是不区分大小写的。符号 # 后面的内容被认为是注释。命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔。
最简单的例程
单个源文件
假设我们的项目中只有一个源文件,且该源文件是一个指数幂函数的实现和运用。
/*************************************************************************
> File Name: main.c
> Author:
> Mail:
> Created Time: Mon 28 Aug 2023 11:16:11 AM CST
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
double power(double base, int exponent) {
int result = base;
if (exponent == 0) {
return 1;
}
for (int 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.txt
编写CMakeLists.txt文件,并保存在与main.c源文件同个目录下:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo1)
# 指定生成目标
add_executable(Demo main.c)
这个CMakeLists.txt文件,依次出现了几个命令:
1.cmake_minimum_required: 指运行此配置文件所需的CMake的最低版本;
2.project:参数值是Demo1,表示项目的名称是Demo1;
3.add_executable: 将main.c的源文件编译成一个名称为Demo的可执行文件.
编译项目
在当前目录执行cmake .
,得到Makefile后再使用make
命令编译得到Demo1可执行文件.
ydqun@ydqhost 01 % cmake . [0]
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ydqun/workspace/study/cppnetwork/cmake/01
ydqun@ydqhost 01 % make [0]
Scanning dependencies of target Demo
[ 50%] Building C object CMakeFiles/Demo.dir/main.c.o
[100%] Linking C executable Demo
[100%] Built target Demo
多个源文件
多个源文件在同一目录
加入我们把pow
函数单独写进一个名为MathFunctions.c
的源文件里,使得这个工程变成如下的形式:
.
├── CMakeLists.txt
├── main.c
├── MathFunctions.c
└── MathFunctions.h
main函数所在源文件代码
#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;
}
MathFunctions.c和MathFunctions.h。
/*************************************************************************
> File Name: MathFunctions.c
> Author:
> Mail:
> Created Time: Mon 28 Aug 2023 11:30:03 AM CST
************************************************************************/
#include <stdio.h>
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;
}
/*************************************************************************
> File Name: MathFunctions.h
> Author:
> Mail:
> Created Time: Mon 28 Aug 2023 11:32:16 AM CST
************************************************************************/
#ifndef _MATHFUNCTIONS_H
#define _MATHFUNCTIONS_H
double power(double base, int exponent);
#endif
这时候,CMakeLists.txt可以改成如下的形式:
ydqun@ydqhost 02 % cat CMakeLists.txt [0]
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 指定生成目标
add_executable (Demo ${DIR_SRCS})
唯一的改动只是在add_executable
命令中增加了一个MathFunctions.c
源文件。这样写没什么问题,但是如果源文件的数量很多,把所有源文件的
名字都加进去将是一件很烦人的工作。更省事的方式是使用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})
aux_source_directory(. DIR_SRCS)
会将当前目录所有源文件的文件名赋值给变量DIR_SRCS
,再指示变量DIR_SRCS
中的源文件需要编译成一个
名称为Demo的可执行文件。
多个目录,多个源文件
现在进一步将MathFunctions.h
和MathFunctions.c
文件移动到math目录下:
ydqun@ydqhost 03 % tree [0]
.
├── CMakeLists.txt
├── main.c
└── math
├── CMakeLists.txt
├── MathFunctions.c
└── MathFunctions.h
1 directory, 5 files
对于这种情况,需要分别在项目根目录Demo3和math目录各编写一个CMakeLists.txt
文件。为了方便,我们可以先将math目录里的文件编译成静态库
再有main函数调用。根目录中的CMakeList.txt:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo3)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 添加 math 子目录
add_subdirectory(math)
# 指定生成目标
add_executable(Demo main.c)
# 添加链接库
target_link_libraries(Demo MathFunctions)
在CMakeLists.txt中,使用命令add_subdirectory
指明本项目包含一个子目录math,这样math目录下的CMakeLists.txt文件和源代码也会被处理。
第6行,使用命令target_link_libraries
指明可执行文件main需要连接一个名为MathFunctions的链接库。子目录中的CMakeLists.txt:
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})
在子目录中使用命令add_library
将src目录中的源文件编译为静态链接库。
自定义编译选项
CMake允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。例如,可以将MathFunctions库设为一个可选的库,如果该选项
为on
,就使用该库定义的数据函数来进来运算。否则就调用标准库中的数学函数库。其工程结构为:
ydqun@ydqhost 04 % tree [0]
.
├── CMakeLists.txt
├── config.h
├── config.h.in
├── main.c
└── math
├── CMakeLists.txt
├── MathFunctions.c
└── MathFunctions.h
1 directory, 7 files
修改CMakeLists文件
我们要做的第一步是在顶层的CMakeLists.txt文件中添加该选项:
# CMake 最低版本号要求
cmake_minumum_required (VERSION 2.8)
# 项目信息
project (Demo4)
# 加入一个配置文件,用于处理CMake对源码的设置
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# 是否使用自已的MathFunctions 库
option (USE_MYMATH
"Use provided math implementation" ON)
# 是否加入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.option
命令添加了一个USE_MYMATH
选项,并默认值为ON
。
3.根据USE_MYMATH
变量的值来决定是否使用我们编写的MathFunctions库。
修改main.c文件
修改main.c文件,让其根据USE_MYMATH
的预定义来决定是否调用标准库还是MathFunctions库:
/*************************************************************************
> File Name: main.c
> Author:
> Mail:
> Created Time: Tue 29 Aug 2023 04:06:23 PM CST
************************************************************************/
#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.c引用了一个config.h文件,这个文件预定义了USE_MYMATH
的值。但我们并不直接编写这个文件,为了方便从CMakeLists.txt中导入编制,我们
编写一个config.h.in文件,内容如下:
#cmakedefine USE_MYMATH
有了config.h.in文件后,cmake会自动根据CMakeLists.txt编制文件中的设置自动生成config.h文件。
编译项目
为了便于交互式的选择该变量的值,我们可以使用ccmake
命令。
ccmake
1.安装ccmake
我使用的操作系统是ubuntu20.04.3 LTS,安装ccmake使用的是apt命令安装,安装过程如下:
ydqun@ydqhost 04 % sudo apt search ccmake [100]
Sorting... Done
Full Text Search... Done
cmake-curses-gui/focal-updates 3.16.3-1ubuntu1.20.04.1 amd64
curses based user interface for CMake (ccmake)
ydqun@ydqhost 04 % sudo apt install cmake-curses-gui/focal-updates [130]
Reading package lists... Done
Building dependency tree
Reading state information... Done
Selected version '3.16.3-1ubuntu1.20.04.1' (Ubuntu:20.04/focal-updates [amd64]) for 'cmake-curses-gui'
Selected version '3.16.3-1ubuntu1.20.04.1' (Ubuntu:20.04/focal-updates [amd64]) for 'cmake' because of 'cmake-curses-gui'
The following additional packages will be installed:
cmake cmake-data
Suggested packages:
cmake-doc ninja-build
The following NEW packages will be installed:
cmake-curses-gui
The following packages will be upgraded:
cmake cmake-data
2 upgraded, 1 newly installed, 0 to remove and 293 not upgraded.
Need to get 1,768 kB/7,049 kB of archives.
After this operation, 5,597 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://mirrors.cloud.aliyuncs.com/ubuntu focal-updates/universe amd64 cmake-curses-gui amd64 3.16.3-1ubuntu1.20.04.1 [1,768 kB]
Fetched 1,768 kB in 0s (10.8 MB/s)
(Reading database ... 122942 files and directories currently installed.)
Preparing to unpack .../cmake_3.16.3-1ubuntu1.20.04.1_amd64.deb ...
Unpacking cmake (3.16.3-1ubuntu1.20.04.1) over (3.16.3-1ubuntu1) ...
Preparing to unpack .../cmake-data_3.16.3-1ubuntu1.20.04.1_all.deb ...
Unpacking cmake-data (3.16.3-1ubuntu1.20.04.1) over (3.16.3-1ubuntu1) ...
Selecting previously unselected package cmake-curses-gui.
Preparing to unpack .../cmake-curses-gui_3.16.3-1ubuntu1.20.04.1_amd64.deb ...
Unpacking cmake-curses-gui (3.16.3-1ubuntu1.20.04.1) ...
Setting up cmake-data (3.16.3-1ubuntu1.20.04.1) ...
Setting up cmake (3.16.3-1ubuntu1.20.04.1) ...
Setting up cmake-curses-gui (3.16.3-1ubuntu1.20.04.1) ...
Processing triggers for man-db (2.9.1-1) ...
ydqun@ydqhost 04 %
使用ccmake
安装完成后,在工程项目的目录下(主CMakeLists.txt)使用ccmake .
打开会话式的交互配置界面,
在CMake的交互式配置界面中,我们可以找到CMakeLists.txt定义的USE_MYMATH
选项,通过使用上下方向键在不同的配置项上跳转,在选中配置项后
按下enter
按键后可以修改该选项,修改完成后可以按下c
按键完成配置,之后再按下g
按键确认生成Makefile文件并退出。在这里我们可以尝试
分别将USE_MYMATH
设置为ON
和OFF
进行测试:
USE_MYMATH为ON
编译并运行:
ydqun@ydqhost 04 % make [0]
[ 50%] Built target MathFunctions
[100%] Built target Demo
ydqun@ydqhost 04 % ./Demo 2 4 [0]
Now we use our own Math library.
2 ^ 4 is 16
ydqun@ydqhost 04 %
此时config.h的内容为:
ydqun@ydqhost 04 % cat config.h [0]
#define USE_MYMATH
ydqun@ydqhost 04 %
USE_MYMATH为OFF
ydqun@ydqhost 04 % make [0]
Scanning dependencies of target Demo
[ 50%] Building C object CMakeFiles/Demo.dir/main.c.o
[100%] Linking C executable Demo
[100%] Built target Demo
ydqun@ydqhost 04 % ./Demo 2 4 [0]
Now we use the standard library.
2 ^ 4 is 16
ydqun@ydqhost 04 %
此时config.h的内容为:
ydqun@ydqhost 04 % cat config.h [0]
/* #undef USE_MYMATH */
ydqun@ydqhost 04 %
安装和测试
CMake也可以指定安装规则,以及添加测试。这两个功能分别可以通过在产生Makefile后使用make install
和make test
来执行。在以前的GNU
Makefile里,你可能需要为此编写install
和test
两个伪目标和相应的规则,但在CMake里,这样的工作同样只需要简单的调用几条命令。
工程目录如下:
ydqun@ydqhost 05 % tree [0]
.
├── install
│ ├── CMakeLists.txt
│ ├── config.h.in
│ ├── main.c
│ └── math
│ ├── CMakeLists.txt
│ ├── MathFunctions.c
│ └── MathFunctions.h
└── test
├── CMakeLists.txt
├── config.h.in
├── main.c
└── math
├── CMakeLists.txt
├── MathFunctions.c
└── MathFunctions.h
4 directories, 12 files
定制安装规则
首先在math/CMakeLists.txt文件里添加下面两行:
# 指定MathFunctions 库的安装路径
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)
这样完整的math/CMakeLists.txt文件代码如下:
ydqun@ydqhost install % cat math/CMakeLists.txt [0]
# 查找当前目录下的所有源文件
# 并将名称报春到DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})
# 指定MathFunctions 库的安装路径
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)
整个工程的主CMakeLists.txt如下
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo5)
set (CMAKE_INCLUDE_CURRENT_DIR ON)
# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
"Use provided math implementation" ON)
# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# 是否加入 MathFunctions 库
if (USE_MYMATH)
# 将math添加到include路径中
# 这样cmake在编译过程中就能直接找到math中的头文件
# 编写main的时候就不需要include相对路径了
include_directories ("${PROJECT_SOURCE_DIR}/math")
# 将 EXTRA_LIBS 的值与字符串 "MathFunctions" 连接,重新复制给EXTRA_LIBS
add_subdirectory (math)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
else()
# 不链接math库会报错,因为linux中默认没有math库
LINK_LIBRARIES(m)
endif (USE_MYMATH)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})
target_link_libraries (Demo ${EXTRA_LIBS})
# 指定安装路径
install (TARGETS Demo DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"
DESTINATION include)
ydqun@ydqhost install % cat math/CMakeLists.txt [0]
# 查找当前目录下的所有源文件
# 并将名称报春到DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})
# 指定MathFunctions 库的安装路径
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)
编译和安装。
ydqun@ydqhost install % cmake . [0]
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ydqun/workspace/study/cppnetwork/cmake/05/install
ydqun@ydqhost install % sudo make install [0]
[sudo] password for ydqun:
Scanning dependencies of target MathFunctions
[ 25%] Building C object math/CMakeFiles/MathFunctions.dir/MathFunctions.c.o
[ 50%] Linking C static library libMathFunctions.a
[ 50%] Built target MathFunctions
Scanning dependencies of target Demo
[ 75%] Building C object CMakeFiles/Demo.dir/main.c.o
[100%] Linking C executable Demo
[100%] Built target Demo
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/bin/Demo
-- Installing: /usr/local/include/config.h
-- Installing: /usr/local/bin/libMathFunctions.a
-- Installing: /usr/local/include/MathFunctions.h
通过上面的定制,生成的Demo文件和MathFunctions函数库libMathFunctions.o文件将会被赋值到/usr/local/bin
中,而MathFunctions.h和
生成的config.h文件则会被复制到/usr/local/include
中。我们可以验证一下(顺带一提的是,这里的/usr/local
是默认安装的根目录,可以
过修改CMAKE_INTALL_PREFIX
变量的值来指定这些文件应该拷贝到哪个根目录,修改方式可以通过之前讲的ccmake进行修改):
为工程添加测试
在CMake里添加测试也同样很简单,它提供了一个称为CTest的测试工具,我们只需在项目根目录的CMakeLists.txt文件中调用一系列的add_test
命令即可以添加测试。
# 启用测试
enable_testing()
# 测试程序是否成功运行
add_test (test_run Demo 5 2)
# 测试帮助信息是否可以正常提示
add_test (test_usage Demo)
set_tests_properties (test_usage
PROPERTIES PASS_REGULAR_EXPRESSION "Usage: .* base exponent")
# 测试 5 的平方
add_test (test_5_2 Demo 5 2)
set_tests_properties (test_5_2
PROPERTIES PASS_REGULAR_EXPRESSION "is 25")
# 测试 10 的 5 次方
add_test (test_10_5 Demo 10 5)
set_tests_properties (test_10_5
PROPERTIES PASS_REGULAR_EXPRESSION "is 100000")
# 测试 2 的 10 次方
add_test (test_2_10 Demo 2 10)
set_tests_properties (test_2_10
PROPERTIES PASS_REGULAR_EXPRESSION "is 1024")
上述代码包含了四个测试。第一个测试test_run
用来测试程序是否成功运行并返回0值。其余三个分别用来测试5的平方、10的5次方、2的10次方
是否都能得到正确的结果。其中PASS_REGULAR_EXPRESSION
用来测试输出是否包含后面跟着的字符串。测试结果如下:
ydqun@ydqhost test % cmake . [0]
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ydqun/workspace/study/cppnetwork/cmake/05/test
ydqun@ydqhost test % make test [0]
Running tests...
Test project /home/ydqun/workspace/study/cppnetwork/cmake/05/test
Start 1: test_run
1/5 Test #1: test_run ......................... Passed 0.00 sec
Start 2: test_usage
2/5 Test #2: test_usage ....................... Passed 0.00 sec
Start 3: test_5_2
3/5 Test #3: test_5_2 ......................... Passed 0.00 sec
Start 4: test_10_5
4/5 Test #4: test_10_5 ........................ Passed 0.00 sec
Start 5: test_2_10
5/5 Test #5: test_2_10 ........................ Passed 0.00 sec
100% tests passed, 0 tests failed out of 5
Total Test time (real) = 0.01 sec
但是如果要测试更多的输入数据,向上面这种一个个写测试用例太繁琐,这时候可以通过编写宏来实现:
# 启用测试
enable_testing()
macro (do_test arg1 arg2 result)
add_test (test_${arg1}_${arg2} Demo ${arg1} ${arg2})
set_tests_properties (test_${arg1}_${arg2})
PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro (do_test)
# 使用该宏进行一系列的数据测试
do_test (5 2 "is 25")
do_test (10 5 "is 100000")
do_test (2 10 "is 1024")
如果CTest的其他详细用法可以通过man 1 ctest
参考CTest的文档。
支持gdb
CMake支持gdb,只需要在指定Debug
模式下开启-g
选项:
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
工程目录如下:
ydqun@ydqhost debug % tree [0]
.
├── CMakeLists.txt
├── config.h.in
├── main.c
└── math
├── CMakeLists.txt
├── MathFunctions.c
└── MathFunctions.h
1 directory, 6 files
工程主CMakeLists.txt
ydqun@ydqhost debug % cat CMakeLists.txt [0]
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo4)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 指定Debug模式,并开启gdb
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
# 是否使用自己的MathFunctions 库
option (USE_MYMATH
"Use provided math 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)
else()
# 不连接math库会报错,因为Linux中默认没有math库
LINK_LIBRARIES(m)
endif(USE_MYMATH)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})
target_link_libraries (Demo ${EXTRA_LIBS})
通过上述CMakeLists.txt编译出来的可执行程序即可进行gdb调试。
添加版本号
本节对应的源代码结构如下:
ydqun@ydqhost 07 % tree [0]
.
├── CMakeLists.txt
├── config.h.in
├── main.c
└── math
├── CMakeLists.txt
├── MathFunctions.c
└── MathFunctions.h
1 directory, 6 files
给项目添加和维护版本号是一个好习惯,这样有利于用户了解每个版本的维护情况,并及时了解当前所用的版本是否过时,或是否可能出现不兼容的
情况。首先修改顶层CMakeLists文件,在project
命令之后加入如下两行:
set (Demo_VERSION_MAJOR 1)
set (Demo_VERSION_MINOR 0)
分别指定当前的项目的主版本号和副版本号。之后,为了可以在代码中获取版本信息,我们可以修改config.h.in文件,添加两个预定义变量:
// the configured options and settings for Tutorial
#define Demo_VERSION_MAJOR @Demo_VERSION_MAJOR@
#define Demo_VERSION_MINOR @Demo_VERSION_MINOR@
此时,主目录的CMakeLists.txt如下:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo4)
set (Demo_VERSION_MAJOR 1)
set (Demo_VERSION_MINOR 0)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
"Use provided math implementation" ON)
# 是否使用自己的MathFunctions 库
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# 是否加入 MathFunctions 库
if(USE_MYMATH)
# 将math添加到include路径中
# 这样cmake在编译过程中就能直接找到math中的头文件
# 编写main的时候就不需要include相对路径了
include_directories("${PROJECT_SOURCE_DIR}/math")
add_subdirectory(math)
# 将 EXTRA_LIBS 的值与字符串 "MathFunctions" 连接,重新复制给EXTRA_LIBS
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})
这样就可以直接在代码中打印版本信息了:
/*************************************************************************
> File Name: main.c
> Author:
> Mail:
> Created Time: Tue 29 Aug 2023 04:06:23 PM CST
************************************************************************/
#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("%s Version %d.%d\n",
argv[0],
Demo_VERSION_MAJOR,
Demo_VERSION_MINOR);
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;
}