cmake如何在一个项目中选择部分模块进行编译?
有几十个静态库,我需要根据系统的不同以及设备的不同选择不同的静态库进行编译,BUILD.gn中可以使用projects进行选择,但cmake中该如何去做?
在使用 CMake 构建项目时,可以通过条件判断和变量控制来选择部分模块进行编译。以下是一种常见的方法:
1.定义变量:在 CMakeLists.txt 文件中,定义一个变量来表示系统和设备的选择。例如,可以定义一个名为 "SYSTEM" 的变量来表示系统选择,以及一个名为 "DEVICE" 的变量来表示设备选择。
set(SYSTEM "system1" CACHE STRING "System selection")
set(DEVICE "device1" CACHE STRING "Device selection")
2.使用条件判断:在 CMakeLists.txt 文件中,使用条件判断来根据变量的值选择需要编译的模块。例如,可以使用 if 语句和等于(EQUAL)运算符来判断变量的值,并在满足条件时添加需要编译的模块。
if(SYSTEM STREQUAL "system1")
if(DEVICE STREQUAL "device1")
add_subdirectory(module1)
elseif(DEVICE STREQUAL "device2")
add_subdirectory(module2)
endif()
elseif(SYSTEM STREQUAL "system2")
add_subdirectory(module3)
endif()
在上述示例中,根据系统和设备的选择,选择不同的模块进行编译。您可以根据实际情况,根据需要添加或修改条件判断部分的代码。
3.运行 CMake:运行 cmake 命令来生成构建系统所需的 Makefile 或其他构建文件。
4.构建项目:运行构建系统的命令(如 make 或 ninja),编译选择的模块。
请注意,上述示例中的代码只是一种常见的方法,具体的实现方式可能因项目的结构和需求而有所不同。您可以根据您的项目需求,灵活调整和扩展条件判断部分的代码,以实现您的选择需求。
SET(SRC_LIST main.c util.c reactor.c))
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] “message to display” …)
- SEND_ERROR, 产生错误,生成过程被跳过
- STATUS, 输出前缀为—的信息
- FATAL_ERROR, 立即终止所有cmake过程
ADD_LIBRARY(libname [SHARED | STATIC | MODULE] [EXCLUDE_FROM_ALL] SRC_LIST) #生成动态、静态库,module等同于shared
# EXCLUDE_FROM_ALL表示该库不会被默认构建
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")#生成的库名字
# 设置动态库的版本号,这里设置了两个版本号
SET_TARGET_PROPERTIES(hello_shared PROPERTIES VERSION 1.2 SOVERSION 1)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
ADD_SUBDIRECTORY:向当前工程添加存放源文件的子目录
SUBDIRS:deprecated,不再推荐使用
INCLUDE_DIRECTORIES:向工程添加多个特定的头文件搜索路径
LINK_DIRECTORIES:添加非标准的共享库搜索路径
TARGET_LINK_LIBRARIES:为target添加需要链接的共享库
ADD_DEFINITIONS:向C/C++编译器添加-D定义
ADD_DEPENDENCIES:定义target依赖的其他target
AUX_SOURCE_DIRECTORY:发现一个目录下所有的源代码文件并将列表存储在一个变量中
EXEC_PROGRAM:用于在指定目录运行某个程序(默认为当前CMakeLists.txt所在目录)
INCLUDE:载入CmakeList.txt文件或者预定义的cmake模块
INCLUDE(file [OPTIONAL]) #用来载入CMakeLists.txt文件
INCLUDE(module [OPTIONAL])#用来载入预定义的cmake模块
- FIND_FILE( name path1 path2 …)
VAR变量代表找到的文件全路径,包含文件名
- FIND_LIBRARY( name path1 path2 …)
VAR变量代表找到的库全路径,包含库文件名
FIND_LIBRARY(libX X11 /usr/lib)
IF (NOT libx)
MESSAGE(FATAL_ERROR "libX not found")
ENDIF(NOT libX)
- FIND_PATH( name path1 path2 …)
VAR变量代表包含这个文件的路径
- FIND_PROGRAM( name path1 path2 …)
VAR变量代表包含这个程序的全路径
- FIND_PACKAGE( [major.minor] [QUIET] [NO_MODULE] [[REQUIRED | COMPONENTS] [componets …]])
用来调用预定义在CMAKE_MODULE_PATH下的Find.cmake模块,你也可以自己定义Find
模块,通过SET(CMAKE_MODULE_PATH dir)将其放入工程的某个目录供工程使用
IF (expression)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ELSE (expression)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDIF (expression) # 一定要有ENDIF与IF对应
IF (expression), #expression不为:空,0,N,NO,OFF,FALSE,NOTFOUND或<var>_NOTFOUND,为真
IF (not exp), #与上面相反
IF (var1 AND var2)
IF (var1 OR var2)
IF (COMMAND cmd) #如果cmd确实是命令并可调用,为真
IF (EXISTS dir) #如果目录,为真
IF (EXISTS file) #如果文件存在,为真
IF (file1 IS_NEWER_THAN file2),#当file1比file2新,或file1/file2中有一个不存在时为真,文件名需使用全路径
IF (IS_DIRECTORY dir) #当dir是目录时,为真
IF (DEFINED var) #如果变量被定义,为真
IF (var MATCHES regex) #此处var可以用var名,也可以用${var}
IF (string MATCHES regex)
#当给定的变量或者字符串能够匹配正则表达式regex时为真。比如:
IF ("hello" MATCHES "ell")
MESSAGE("true")
ENDIF ("hello" MATCHES "ell")
数字比较表达式:
IF (variable LESS number)
IF (string LESS number)
IF (variable GREATER number)
IF (string GREATER number)
IF (variable EQUAL number)
IF (string EQUAL number)
按照字母表顺序进行比较:
IF (variable STRLESS string)
IF (string STRLESS string)
IF (variable STRGREATER string)
IF (string STRGREATER string)
IF (variable STREQUAL string)
IF (string STREQUAL string)
#一个小例子,用来判断平台差异:
IF (WIN32)
MESSAGE(STATUS “This is windows.”)
ELSE (WIN32)
MESSAGE(STATUS “This is not windows”)
ENDIF (WIN32)
#上述代码用来控制在不同的平台进行不同的控制,但是,阅读起来却并不是那么舒服,ELSE(WIN32)之类的语句很容易引起歧义。
#可以SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
#这时候就可以写成:
IF (WIN32)
ELSE ()
ENDIF ()
#配合ELSEIF使用,可能的写法是这样:
IF (WIN32)
#do something related to WIN32
ELSEIF (UNIX)
#do something related to UNIX
ELSEIF(APPLE)
#do something related to APPLE
ENDIF (WIN32)
WHILE(condition)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDWHILE(condition)
形式一:列表
FOREACH(loop_var arg1 arg2 ...)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDFOREACH(loop_var)
示例:
AUX_SOURCE_DIRECTORY(. SRC_LIST)
FOREACH(F ${SRC_LIST})
MESSAGE(${F})
ENDFOREACH(F)
形式二:范围
FOREACH(loop_var RANGE total)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDFOREACH(loop_var)
#从0到total以1为步进
FOREACH(VAR RANGE 10)
MESSAGE(${VAR})
ENDFOREACH(VAR)
#输出:
012345678910
形式三:范围和步进
FOREACH(loop_var RANGE start stop [step])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDFOREACH(loop_var)
从start开始到stop结束,以step为步进。**注意:**直到遇到ENDFOREACH指令,整个语句块才会得到真正的执行。
FOREACH(A RANGE 5 15 3)
MESSAGE(${A})
ENDFOREACH(A)
输出:
581114