现代CMake高级教程 - 第 4 章:对象的属性

双笙子佯谬老师的【公开课】现代CMake高级教程课程笔记

第 4 章:对象的属性

除了 POSITION_INDEPENDENT_CODE 还有哪些这样的属性?

add_executable(main main.cpp)

set_property(TARGET main PROPERTY CXX_STANDARD 17)				# 采用 C++17 标准进行编译(默认 11)
set_property(TARGET main PROPERTY CXX_STANDARD_REQUIRED ON)  	# 如果编译器不支持 C++17,则直接报错(默认 OFF)
set_property(TARGET main PROPERTY WIN32_EXECUTABLE ON)       # 在 Windows 系统中,运行时不启动控制台窗口,只有 GUI 界面(默认 OFF)
set_property(TARGET main PROPERTY LINK_WHAT_YOU_USE ON)      # 告诉编译器不要自动剔除没有引用符号的链接库(默认 OFF)
set_property(TARGET main PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)   # 设置动态链接库的输出路径(默认 ${CMAKE_BINARY_DIR})
set_property(TARGET main PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)   # 设置静态链接库的输出路径(默认 ${CMAKE_BINARY_DIR})
set_property(TARGET main PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)   # 设置可执行文件的输出路径(默认 ${CMAKE_BINARY_DIR})

set_target_properties 批量设置多个属性

add_executable(main main.cpp)

set_target_properties(main PROPERTIES
	CXX_STANDARD 17	# 采用 C++17 标准进行编译(默认 11)
	CXX_STANDARD_REQUIRED ON	# 如果编译器不支持 C++17,则直接报错(默认 OFF)
	WIN32_EXECUTABLE ON	# 在 Windows 系统中,运行时不启动控制台窗口,只有 GUI 界面(默认 OFF)
	LINK_WHAT_YOU_USE	# 告诉编译器不要自动剔除没有引用符号的链接库(默认 OFF)
	LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib	# 设置动态链接库的输出路径(默认 ${CMAKE_BINARY_DIR})
	ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib	# 设置静态链接库的输出路径(默认 ${CMAKE_BINARY_DIR})
	RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin	# 设置可执行文件的输出路径(默认 ${CMAKE_BINARY_DIR})
	)

通过全局的变量,让之后创建的所有对象都享有同样的属性

相当于改变了各个属性的初始默认值。要注意此时 set(CMAKE_xxx) 必须在 add_executable 之前才有效

set(CMAKE_CXX_STANDARD 17)				# 采用 C++17 标准进行编译(默认 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)  	# 如果编译器不支持 C++17,则直接报错(默认 OFF)
set(CMAKE_WIN32_EXECUTABLE ON)       # 在 Windows 系统中,运行时不启动控制台窗口,只有 GUI 界面(默认 OFF)
set(CMAKE_LINK_WHAT_YOU_USE ON)      # 告诉编译器不要自动剔除没有引用符号的链接库(默认 OFF)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)   # 设置动态链接库的输出路径(默认 ${CMAKE_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)   # 设置静态链接库的输出路径(默认 ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)   # 设置可执行文件的输出路径(默认 ${CMAKE_BINARY_DIR})

add_executable(main main.cpp)

不要使用编译器限定关键字

如果你从百度学的 CMake,你可能会犯如下的错误

对于 CXX_STANDARD 这种 CMake 本就提供了变量来设置的东西,就不要自己去设置 -std=c++17 选项,会和 CMake 自己设置好的冲突,导致出错。请始终用 CXX_STANDARD 或是全局变量 CMAKE_CXX_STANDARD 来设置 -std=c++17 这个 flag,CMake 会在配置阶段检测编译器是否支持 C++17。CUDA 的 -arch=sm_75 也是同理,请使用 CUDA_ARCHITECTURES 属性。

再说了 -std=c++17 只是 GCC 编译器的选项,无法跨平台用于 MSVC 编译器。

使用动态链接库

假如你一定要用动态链接库(Windows 对动态链接很不友好)

mylib/mylib.cpp

#include <cstdio>

#ifdef _MSC_VER
__declspec(dllexport)
#endif
void say_hello()
{
	printf("Hello, world!\n");
}

mylib/mylib.h

#pragma once

#ifdef _MSC_VER
__declspec(dllexport)
#endif
void say_hello();

mylib/CMakeLists.txt

add_library(mylib SHARED mylib.cpp mylib.h)

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)

add_subdirectory(mylib)

add_executable(main main.cpp)
target_link_libraries(main PUBLIC mylib)

常见问题:链接了自己的 dll,但是为什么运行时会找不到?

这是因为你的 dll 和 exe 不在同一目录。Windows 比较蠢,他只会找当前 exe 所在目录,然后查找 PATH,找不到就报错。而你的 dll 在其他目录,因此 Windows 会找不到 dll。
解决1:把 dll 所在位置加到你的 PATH 环境变量里去,一劳永逸。
解决2:把这个 dll,以及这个 dll 所依赖的其他 dll,全部拷贝到和 exe 文件同一目录下。

手动拷贝 dll 好麻烦,能不能让 CMake 把 dll 自动生成在 exe 同一目录?

归根到底还是因为 CMake 把定义在顶层模块里的 main 放在 build/main.exe。而 mylib 因为是定义在 mylib 这个子模块里的,因此被放到了 build/mylib/mylib.dll。

解决 1:设置 mylib 对象的 xx_OUTPUT_DIRECTORY 系列属性

所以,可以设置 mylib 的这些属性,让 mylib.dll 文件输出到 PROJECT_BINARY_DIR,也就是项目根目录(main 所在的位置)。这样 main.exe 在运行时就能找到 mylib.dll 了。
是的,为了伺候这睿智的 Wendous 系统,需要设置全部 6 个属性,是不是非常繁琐?

mylib/CMakeLists.txt

add_library(mylib SHARED mylib.cpp mylib.h)
set_property(TARGET mylib PROPERTY RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set_property(TARGET mylib PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set_property(TARGET mylib PROPERTY LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set_property(TARGET mylib PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR})
set_property(TARGET mylib PROPERTY ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR})
set_property(TARGET mylib PROPERTY LIBRARY_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR})
set_property(TARGET mylib PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR})
set_property(TARGET mylib PROPERTY ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR})
set_property(TARGET mylib PROPERTY LIBRARY_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR})

而 Linux 系统支持 RPATH,CMake 会让生成出来可执行文件的 RPATH 字段指向他链接了的 .so 文件所在目录,运行时会优先从 RPATH 里找链接库,所以即使不在同目录也能找到。

所以还有第三种解决方案:微软,我卸卸你全家(指卸载)。然后安装 Arch Linux 系统。

需要手动修改或查看一个 ELF 文件的 RPATH,可以用 chrpath 或 patchelf 命令。

❯ chrpath -l build/main
build/main: RUNPATH=/mnt/h/Code/lessonCode/CMakeLession/build
❯ ldd build/main
        linux-vdso.so.1 (0x00007ffebc63c000)
        libmylib.so => /mnt/h/Code/lessonCode/CMakeLession/build/libmylib.so (0x00007fa063d5b000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa063b29000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fa063d67000)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值