CMake 使用札记

本篇记录在使用 CMake 中遇到的一些问题及解决办法

参考资料:

Q : shared library for Visual Studio,只生成了 .dll, 没有生成 .lib

1
2
3
4
5
6
if(MSVC_VERSION)
set_target_properties(${PROJECT_NAME} PROPERTIES
LINK_FLAGS " /INCREMENTAL:NO /MANIFEST /NOLOGO"
#COMPILE_FLAGS "-DHELLO_EXPORTS" #ajouté in last a verif demin
)
endif(MSVC_VERSION)

Q : 如何获取文件夹下所有文件

使用 file 命令 及 GLOBGLOB_RECURSE flag, GLOB 可以根据 globbing expressions 类正则表达式 生成匹配的文件的列表。它经常用于获取文件夹下的所有源文件。需要注意的是,这个表达式只是类似正则表达式(similar to regular expressions),它和正则表达式是有区别的
GLOB_RECURSE 则可以递遍历指定路径下的所有文件:

1
2
3
*.cxx      - match all files with extension cxx
*.vt? - match all files with extension vta,…,vtz
f[3-5].txt - match files f3.txt, f4.txt, f5.txt

例:

1
2
3
4
5
6
7
8
file(GLOB SRC_FILES
"*.cpp"
"subdir/*.cpp"
)

file(GLOB_RECURSE SRC_FILES #递归
"*.cpp"
)

Q : 如何在 Visual Studio 中保持源文件目录结构

使用 source_group 来对 VS 的源文件进行分组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function(assign_source_group)
foreach(_source IN ITEMS ${ARGN})
if (IS_ABSOLUTE "${_source}")
file(RELATIVE_PATH _source_rel "${CMAKE_CURRENT_SOURCE_DIR}" "${_source}")
else()
set(_source_rel "${_source}")
endif()
get_filename_component(_source_path "${_source_rel}" PATH)
string(REPLACE "/" "\\" _source_path_msvc "${_source_path}")
source_group("${_source_path_msvc}" FILES "${_source}")
endforeach()
endfunction(assign_source_group)

function(my_add_executable)
foreach(_source IN ITEMS ${ARGN})
assign_source_group(${_source})
endforeach()
add_executable(${PROJECT_NAME} ${ARGN})
endfunction(my_add_executable)

function(my_add_shared)
foreach(_source IN ITEMS ${ARGN})
assign_source_group(${_source})
endforeach()
add_library(${PROJECT_NAME} SHARED ${ARGN})
endfunction(my_add_shared)

my_add_shared(${SRC_FILES})

Q : 如何从源文件列表中删除某个文件

可以使用 list 命令 及 REMOVE_ITEM flag。
例子:从源文件列表中删除文件 c.h, c.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cmake_minimum_required(VERSION 3.9)
file(GLOB SRC_FILES
"*.h"
"*.cpp"
"subdir/*.h"
"subdir/*.cpp"
)

message(${SRC_FILES})

foreach(_src IN ITEMS ${SRC_FILES})
if(${_src} MATCHES "c\.(h|cpp)$")
message("file to remove ${_src}")
list(APPEND RMV_FILES ${_src})
#set(RMV_FILES "${RMV_FILES};${_src}") #the same
endif()
endforeach(_src IN ITEMS ${SRC_FILES})

foreach(_f IN ITEMS ${RMV_FILES})
message("remove file ${_f}")
list(REMOVE_ITEM SRC_FILES ${_f})
endforeach(_f IN ITEMS ${RMV_FILES})

message(${SRC_FILES})

Q : 如何修改生成文件的路径

1
2
3
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${you_path})    #static
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${you_path}) #shared
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${you_path}) #exec