何为一个 C++ 项目

TODO

待整理,但是最近发现了一些有趣的东西,先记一下

CMAKE_MSVC_RUNTIME_LIBRARY

用于在 CMakeLists 里指定 MSVC 使用的运行时库。

  • MultiThreaded 对应 MT
  • MultiThreadedDebug 对应 MTd
  • MultiThreadedDLL 对应 MD
  • MultiThreadedDebugDLL 对应 MDd

注意这项功能仅在 CMake 3.15 之后被支持,至少需要 cmake_minimum_required(VERSION 3.15)

用法

1
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

$<$<CONFIG:Debug>:Debug> 为生成器表达式,意为“如果当前为 Debug,返回 Debug,否则返回空字符串”。
要放在 project 之前才会生效。

在 3.15 以下的版本中要实现相同的功能需要类似于:

1
2
3
4
5
6
7
8
9
10
11
set(CompilerFlags
CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_RELEASE
CMAKE_C_FLAGS
CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_RELEASE
)
foreach(CompilerFlag ${CompilerFlags})
string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
endforeach()

详见:
Compile with /MT instead of /MD using CMake

参考

CMAKE_MSVC_RUNTIME_LIBRARY
在 CMake 中设置 MSVC 运行库

使用 dumpbin 查看静态库的依赖

在安装 VS2017 或以上的版本时会自动安装 dumpbin.exe,我的路径在:

1
"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\bin\Hostx64\x64\dumpbin.exe"

将其加入环境变量即可在任意位置调用 dumpbin

用法

1
dumpbin /directives <path>

directives
其中 MT_StaticReleasdLIBCMT 都代表该文件使用的运行时库为 MT
剩余对应详见 C 运行时 .lib 文件
directives

其他

dumpbin 看起来还有很多功能,可惜官方文档写的也不是很清楚:
DUMPBIN 选项

使用 depends 查看动态库的依赖

一个开源的 dll 依赖分析软件:
https://github.com/lucasg/Dependencies
打开 GUI 将对应 dll 拖入:

  • msvcp<version>.dll 对应 /MD
  • msvcp<version>d.dll 对应 /MDd
    自 VS2017 以后这个 version 应该是 140。

MD:
MD
MT:
MT

ABI

C++ ABI总结

  • 体现在跨编译器的 link 大概率是失败的,因为 C++ 编译器会对符号进行一个“名称重整”的行为以满足 C++ 中的多态,而不同编译器名称重整的逻辑完全不同。不过好像 clang 之类的是能够提供对其他编译器的兼容的。
  • 另一个方面是混合了同一个编译器不同版本的编译流程,比如 MSVC 自 VS2015 之后说,新的连接器可以混合链接旧版 MSVC 编译出来的库文件。C++ binary compatibility between Visual Studio versions
  • 还有就是第三方库只要能保持 ABI 兼容,即可只更新 dll 文件而不用重新编译最终的运行文件。
  • 对虚函数表的重排序,添加删除成员变量等都会使 ABI 兼容失效,因为内存排布不一样了,然后有个保持 ABI 兼容的技巧叫做 Pointer to implementation。PImpl