案例四:自定义编译选项
1). 源文件结构
.
├── CmakeLists.txt
├── config.h.in
├── main.cpp
└── students
├── CmakeLists.txt
├── student_pub.cpp
└── student_pub.h
2) .编写 CMakeLists.txt
#cmake mini ~ver
cmake_minimum_required(VERSION 2.8)
#project info
project(Studdent3)
message(STATUS "PROJECT_SOURCE_DIR " ${PROJECT_SOURCE_DIR})
message(STATUS "PROJECT_BINARY_DIR " ${PROJECT_BINARY_DIR})
set (STUDENT_VERSION_MAJOR "2.0.3" CACHE STRING [FORCE])
set (STUDENT_VERSION_MINOR "1.2.1")
message(STATUS "STUDENT_VERSION_MAJOR " ${STUDENT_VERSION_MAJOR})
message(STATUS "STUDENT_VERSION_MINOR " ${STUDENT_VERSION_MINOR})
set(LIB_ENABLE 1)
if(LIB_ENABLE)
message(STATUS "define LIB_ENABLE 1")
else()
message(STATUS "define LIB_ENABLE 0")
endif()
if(CODE_MODE_DEBUG MATCHES ON)
message("*********Debug build***********")
endif()
# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file(
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# 默认的该宏打开还是关闭 可以在ccmake . gui界面中进行配置 初始化的操作
option(USE_MYSTUDENT "Use provided StudentFuncsLib implementation" ON)
option(CODE_MODE_DEBUG "Use CODE_MODE_DEBUG" OFF)
if(CODE_MODE_DEBUG)
message(STATUS "define CODE_MODE_DEBUG on")
else()
message(STATUS "define CODE_MODE_DEBUG off")
endif()
if(USE_MYSTUDENT)
message(STATUS "define USE_MYSTUDENT on")
else()
message(STATUS "define USE_MYSTUDENT off")
endif()
#头文件引入
include_directories("${PROJECT_SOURCE_DIR}/students/")
# 是否加入 StudentFuncsLib 库
if(USE_MYSTUDENT)
add_subdirectory(students)
set(EXTRA_LIBS ${EXTRA_LIBS} StudentFuncsLib)
endif(USE_MYSTUDENT)
#将当前路径下的源文件保存到变量DIR_SRCS中
aux_source_directory(. DIR_SRCS)
#添加student 目录
#add_subdirectory(students)
#先生成目标文件Student
add_executable(Studdent ${DIR_SRCS})
#添加链接库
target_link_libraries(Studdent ${EXTRA_LIBS})
3), 编写config.h.in文件
/**
* This is the configure demo
* - CMAKEDEFINE_VAR1 = @CMAKEDEFINE_VAR1@
* - CMAKEDEFINE_VAR2 = @CMAKEDEFINE_VAR2@
* - DEFINE_VAR1 = @DEFINE_VAR1@
* - DEFINE_VAR2 = @DEFINE_VAR2@
*/
/**
* cmakedefine 会根据变量的值是否为真(类似 if)来变换为 #define VAR ... 或 #undef VAR
*/
#cmakedefine CMAKEDEFINE_VAR1 @CMAKEDEFINE_VAR1@
#cmakedefine LIB_ENABLE @LIB_ENABLE
/**
* define 会直接根据规则来替换
*/
#define DEFINE_VAR1 @DEFINE_VAR1@
#define DEFINE_VAR2 ${DEFINE_VAR2}
#cmakedefine USE_MYSTUDENT
//#cmakedefine CODE_MODE_DEBUG
4).cmake接口
message(STATUS "PROJECT_SOURCE_DIR " ${PROJECT_SOURCE_DIR})
message(STATUS "PROJECT_BINARY_DIR " ${PROJECT_BINARY_DIR})
解释:
message :为用户显示一条消息。
message([] “message to display” …)
mode的选项可以是:
(none) = Important information
STATUS = Incidental information
WARNING = CMake Warning, continue processing
AUTHOR_WARNING = CMake Warning (dev), continue processing
SEND_ERROR = CMake Error, continue processing,
but skip generation
FATAL_ERROR = CMake Error, stop processing and generation
DEPRECATION = CMake Deprecation Error or Warning if variable
CMAKE_ERROR_DEPRECATED or CMAKE_WARN_DEPRECATED
is enabled, respectively, else no message.
(无) = 重要消息;
STATUS = 非重要消息;
WARNING = CMake 警告, 会继续执行;
AUTHOR_WARNING = CMake 警告 (dev), 会继续执行;
SEND_ERROR = CMake 错误, 继续执行,但是会跳过生成的步骤;
FATAL_ERROR = CMake 错误, 终止所有处理过程;
CMake命令行工具在stdout上显示状态消息,在stderr上显示所有其他消息类型。CMake GUI显示其日志区域中的所有消息。交互式对话框(ccmake和CMakeSetup)每次在状态行上显示一条状态消息,并在交互式弹出框中显示其他消息。CMake警告和错误消息文本使用简单的标记语言显示。非缩进文本的格式是用换行符分隔的行包装的段落。缩进文本被认为是预格式化的。
configure_file(
“
P
R
O
J
E
C
T
S
O
U
R
C
E
D
I
R
/
c
o
n
f
i
g
.
h
.
i
n
"
"
{PROJECT_SOURCE_DIR}/config.h.in" "
PROJECTSOURCEDIR/config.h.in""{PROJECT_BINARY_DIR}/config.h”
)
解释:
拷贝一个文件到另一个文件,格式为:
configure_file(
[COPYONLY] [ESCAPE_QUOTES] [@ONLY]
[NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
将一个文件复制到file ,并替换文件内容中引用的变量值。
如果是一个相对路径,则相对于当前source 求值。
必须是一个文件,而不是一个目录。
如果是一个相对路径,则相对于当前binary 目录求值。
如果命名一个现有目录,则输入文件将放置在该目录中,并使用其原始名称。
如果文件被修改,构建系统将重新运行CMake来重新配置文件并再次生成构建系统。
此命令将输入文件中引用为
V
A
R
或
@
V
A
R
@
的
任
何
变
量
替
换
为
C
M
a
k
e
(
C
m
a
k
e
L
i
s
t
s
中
设
置
的
值
)
确
定
的
值
。
如
果
一
个
变
量
没
有
定
义
,
它
将
被
替
换
为
n
o
t
h
i
n
g
。
浅
显
一
点
:
c
o
n
f
i
g
u
r
e
f
i
l
e
,
复
制
一
份
输
入
文
件
到
输
出
文
件
,
替
换
输
入
文
件
中
被
@
V
A
R
@
或
者
{VAR}或@VAR@的任何变量替换为CMake(CmakeLists 中设置的值)确定的值。如果一个变量没有定义,它将被替换为nothing。 浅显一点: configure_file,复制一份输入文件到输出文件,替换输入文件中被@VAR@或者
VAR或@VAR@的任何变量替换为CMake(CmakeLists中设置的值)确定的值。如果一个变量没有定义,它将被替换为nothing。浅显一点:configurefile,复制一份输入文件到输出文件,替换输入文件中被@VAR@或者{VAR}引用的变量值。也就是说,让普通文件,也能使用CMake中的变量。例如:
在CMakeLists.txt中定义了如下的变量:
set(USE_MYSTUDENT 1)
输入文件中为:
#cmakedefine LIB_ENABLE @LIB_ENABLE@
那么,在输出文件中就会被转化为:
#define LIB_ENABLE 1
或:
在CMakeLists.txt中定义了如下的变量:
option(CODE_MODE_DEBUG “Use CODE_MODE_DEBUG” ON)
输入文件中为:
#cmakedefine CODE_MODE_DEBUG
那么,在输出文件中就会被转化为:
#define CODE_MODE_DEBUG 1
Config.h.in文件中配置如下:
#cmakedefine USE_MYSTUDENT
#cmakedefine LIB_ENABLE @LIB_ENABLE@
#cmakedefine CODE_MODE_DEBUG
configure_file的其他选项:
COPYONLY:只拷贝文件,不进行任何的变量替换。这个选项在指定了NEWLINE_STYLE选项时不能使用(无效)。
ESCAPE_QUOTES:躲过任何的反斜杠(C风格)转义。
@ONLY:限制变量替换,让其只替换被@VAR@引用的变量(那么
V
A
R
格
式
的
变
量
将
不
会
被
替
换
)
。
这
在
配
置
{VAR}格式的变量将不会被替换)。这在配置
VAR格式的变量将不会被替换)。这在配置{VAR}语法的脚本时是非常有用的。
NEWLINE_STYLE style:指定输出文件中的新行格式。UNIX和LF的新行是\n,DOS和WIN32和CRLF的新行格式是\r\n。这个选项在指定了COPYONLY选项时不能使用(无效)。
通常情况下,输入文件以.h.in为后缀,输出文件以.h为后缀。
如果指定了COPYONLY,则不会发生变量展开。
如果指定了ESCAPE_QUOTES,那么任何替换的引号都将是c风格的转义。该文件将配置为CMake变量的当前值。
如果指定了@ONLY,则只会替换形式@VAR@的变量,而忽略
V
A
R
。
这
对
于
配
置
使
用
{VAR}。这对于配置使用
VAR。这对于配置使用{VAR}的脚本非常有用。
根据if()命令在CMake中是否将VAR设置为任何不被认为是错误常量的值,“#cmakedefine VAR…”形式的输入文件行将被替换为“#define VAR…”或/* #undef VAR */。
(“…”的内容,如有,按上文处理。)
类似地,“#cmakedefine01 VAR”形式的输入文件行将被“#define VAR 1”或“#define VAR 0”替换。
option(USE_MYSTUDENT “Use provided StudentFuncsLib implementation” ON)
解释:
提供用户可以选择的选项。为用户提供一个 ON或OFF选项。如果没有提供初始值,则使用OFF。
默认的该宏打开还是关闭,可以在ccmake . gui界面中进行配置,这里是初始化的操作,当没有定义时默认的值就是在这里配置,每次清除build文件重新cmake时,就会使用该默认值,可以在cmake时进行带参数编译,这样可以将值传进去。
可以使用ccmake … 进行GUI 界面的设置,先按enter设置,再按g更改保存文件构建系统。
执行后对照config.h 和config.h.in 两个文件进行对比。
include_directories("${PROJECT_SOURCE_DIR}/students")
引入头文件路径,这样在编译的时候就可以找到头文件了。而且在项目源文件中就不用像:
#include"./students/student_pub.h"
这样声明了,可以直接声明为:
#include"student_pub.h"
但是这样做容易让别人不清楚头文件路径,所以如果头文件不多的话尽量少用,尽量使用绝对路径在头文件中包含,像上面一样使用。
set(EXTRA_LIBS KaTeX parse error: Expected 'EOF', got '#' at position 137: …) config.h.in中 #̲cmakedefine STU…{STUDENT_VERSION_MINOR}"
则生成的config.h中:
#define STUDENT_VERSION_MAJOR 0.3
#define STUDENT_VERSION_MINOR “1.2.1”
就可以在main函数使用该宏了
官网参考; https://cmake.org/cmake/help/latest/command/set.html?highlight=set