有了更进一步,就有更进二步,这篇主要介绍一些 windows 下我的一些习惯
windows的GUI应用
add_executable(${PROJECT_NAME} WIN32
${SRC_FILES}
)
WIN32
参数告诉CMake
将应用程序配置为 Windows GUI 应用。MACOSX_BUNDLE
参数配置 macOS 捆绑包应用程序EXCLUDE_FROM_ALL
参数的程序在默认编译的时候,不会被编译,如果要编译它们,需要手动编译, 比如make test
指定编译名为test
- 不指定任何选项,就是配置为控制台应用程序
windows控制台程序不显示控制台黑框
有的时候想让应用在后台执行,不想有弹窗,可以windows下可以如下设置
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:mainCRTStartup")
或者下面这样
set_target_properties(${PROJECT_NAME} PROPERTIES
LINK_FLAGS "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup"
)
windows下生成sln文件
windows下开发,IDE
大概率离不开 VS
,所以我一般使用脚本生成 sln
文件,VS
里直接打开生成的 sln
文件后进行项目开发。可以看一下下面的脚本示例:
cmake -S . ^
-B build_win ^
-G "Visual Studio 16" ^
-A Win32 ^
-DCMAKE_GENERATOR_TOOLSET=v142 ^
-DCMAKE_SYSTEM_VERSION=8.1 ^
-DPROJECT_ARCH=x86 ^
-DBUILD_DEMO=ON
-S .
:指定源代码目录。.
表示当前目录,即脚本所在的目录。-B build_win
:指定构建目录。build_win
表示构建目录的路径。-G "Visual Studio 16"
:指定生成器。"Visual Studio 16"
表示使用Visual Studio 2019作为生成器。-A Win32
:指定目标平台的体系结构。Win32
表示32位Windows平台。-DCMAKE_GENERATOR_TOOLSET=v142
:这个参数用于指定构建所使用的工具集版本。-DCMAKE_SYSTEM_VERSION=8.1
:这个参数用于指定目标平台的系统版本。-DPROJECT_ARCH=x86
:定义名为PROJECT_ARCH
的CMake
变量,并将其值设置为x86
。这个在上一篇跨平台里面提到了。-DBUILD_DEMO=ON
:定义名为BUILD_DEMO
的CMake
变量,并将其值设置为ON
。
补充一下
- 如果不指定
-G
参数,CMake 将尝试根据当前系统的默认配置选择合适的生成器。通常情况下,它会选择与操作系统和系统版本匹配的默认生成器。 - 如果不指定
-DCMAKE_GENERATOR_TOOLSET
参数,CMake 将使用默认的生成器工具集。这意味着将使用与所选生成器和构建目标平台相关联的默认工具集。 - 如果不指定
-DCMAKE_SYSTEM_VERSION
参数,CMake 将使用默认的系统版本。这可能会导致在使用一些特定系统功能或API时发生问题,因为 CMake 无法区分目标系统的确切版本。
如果省略这些参数,CMake 将根据环境的默认配置来进行构建,这可能导致在不同的环境中产生不同的行为和结果。因此,为了确保构建的一致性和可重复性,最好根据所需的配置明确地指定这些参数。
实际项目我更偏向使用脚本直接固定编译参数,一般项目编译参数都是固定的,可以通过若干个脚本更傻瓜更不容易出错。
自定义CMake变量
接前面的脚本,可以看一下脚本如何传参给 CMake,项目中这一块用的也比较多。
# 开关 ON/OFF 类型
option(BUILD_DEMO "Build the demo" OFF)
# 直接 if 判断
if (BUILD_DEMO)
add_subdirectory(example)
endif()
# 字符串类型的
if(PROJECT_ARCH STREQUAL "x86_64")
add_compile_options(-m64 -march=x86-64)
add_link_options(-m64)
elseif(PROJECT_ARCH STREQUAL "x86")
add_compile_options(-m32)
add_link_options(-m32)
endif()
超好用的自定义操作
只要你想通过 CMake 实现构建自动化,那么我不允许还有人不知道 add_custom_command
命令,它主要是用于将自定义的构建命令添加到项目中。用的比较多的是下面这种语法,先看官方说明:
add_custom_command(TARGET target_name
[PRE_BUILD | PRE_LINK | POST_BUILD]
COMMAND command...
[ARGS arguments...]
[WORKING_DIRECTORY dir]
[COMMENT comment...]
[DEPENDEES dependees...]
[BYPRODUCTS files...]
[IMPLICIT_DEPENDS language depend_list...]
[COMMAND_EXPAND_LISTS]
[VERBATIM]
[APPEND]
[USES_TERMINAL]
[OUTPUT output_files...])
这是一些常用的参数和选项的解释:
TARGET target_name
:指定需要执行自定义命令的目标(可执行文件、库等)。PRE_BUILD | PRE_LINK | POST_BUILD
:指定自定义命令是在预构建阶段、预链接阶段还是后构建阶段执行。COMMAND command...
:指定要执行的命令。可以是 Shell 命令、外部工具或脚本。ARGS arguments...
:指定命令的参数。WORKING_DIRECTORY dir
:指定命令执行的工作目录。COMMENT comment...
:为自定义命令添加注释。DEPENDEES dependees...
:指定依赖的目标,当依赖的目标发生变化时,自定义命令会被重新执行。BYPRODUCTS files...
:指定自定义命令生成的文件。IMPLICIT_DEPENDS language depend_list...
:指定依赖的隐式依赖项,这些依赖项通常由生成器产生。COMMAND_EXPAND_LISTS
:展开参数列表中的变量引用。VERBATIM
:以原样执行命令,不进行任何转义。APPEND
:将自定义命令附加到目标的现有命令中。USES_TERMINAL
:指示命令需要终端支持,以便查看输出。OUTPUT output_files...
:指定自定义命令生成的输出文件。
使用 add_custom_command
可以灵活地在构建过程中添加自定义的命令,例如执行脚本、生成文件、复制文件等。这些命令可以与 CMake 的目标(target)和依赖(dependees)机制结合使用,实现更高级的构建自动化。
我来挑一些经常用到命令举例
内置命令(拷贝、删除等)
拷贝 A
模块的产物到当前模块的输出路径下
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
$<TARGET_FILE_DIR:A>
$<TARGET_FILE_DIR:${PROJECT_NAME}>
)
CMAKE_COMMAND -E
后面可以携带多个内置命令。下面是一些常用的内置命令及其解释:
copy
:复制文件或目录。例如:copy <source> <destination>
remove
:删除文件或目录。例如:remove <file>
make_directory
:创建目录。例如:make_directory <directory>
remove_directory
:删除目录。例如:remove_directory <directory>
rename
:重命名文件或目录。例如:rename <oldname> <newname>
echo
:输出文本消息。例如:echo <message>
- …
这里建议去 CMake 官网看详细的支持参数,以及这些参数需要的最低 CMake 版本
https://cmake.org/cmake/help/latest/manual/cmake.1.html#cmdoption-cmake-E
其中还有平台独有的命令,比如 windows 下 write_regv
写入注册表
执行命令
linux 可能直接调用命令更简单, 如下:
add_custom_command(TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND mkdir -p
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/config/"
)
windows 下不用一般是因为执行命令会有路径
/
的问题
生成文件
生成文件这一块用的不多,以下是一个简单的例子:
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/output.txt
COMMAND echo "Hello, CMake!" > output.txt
COMMENT "Generating output.txt"
VERBATIM
)
# 导入所有的文件
add_executable(${PROJECT_NAME}
${SRC_FILES}
output.txt
)
这里有个需要注意的地方就是,生成的文件一定要被用上,不然
add_custom_command
不会执行
make install
make install
命令在构建系统中常用于将构建生成的文件安装到指定目录中。默认情况下,该命令不会自动执行,除非显式地调用它。
在 CMake 中,可以使用 install
命令来定义安装规则。这个命令告诉 CMake 在构建过程中安装特定的文件、目录或目标。例如,可以安装生成的二进制文件、库文件、头文件、配置文件等。
使用 install
命令后,通过运行 make install
(在 Unix 系统中)或者 cmake --build . --target install(构建后直接install)
或者 cmake -DBUILD_TYPE=Debug -P build/cmake_install.cmake(BUILD_TYPE根据实际写,这里仅仅install)
(在 Windows 系统中)来执行安装动作。这将使得构建生成的文件按照定义的规则被拷贝到指定的安装目录中。
举个简单的例子
# 产物拷贝到项目根目录的产物名称文件夹里
install(TARGETS ${PROJECT_NAME} DESTINATION ${PROJECT_ROOT_PATH}/${PROJECT_NAME})
# 项目根目录的config文件夹拷贝到项目根目录的产物名称文件夹里
install(DIRECTORY "${PROJECT_ROOT_PATH}/config/" DESTINATION ${PROJECT_ROOT_PATH}/${PROJECT_NAME})
# 项目根目录README.md文件拷贝到项目根目录的产物名称文件夹里
install(FIELS "${PROJECT_ROOT_PATH}/README.md" DESTINATION ${PROJECT_ROOT_PATH}/${PROJECT_NAME})
如果是构建机构建出产物,其实有了 add_custom_command
已经够用了~