Google Benchmark 平台特定构建指南GCC、MSVC、Intel 与 Solaris 的链接与配置全解【免费下载链接】benchmarkA microbenchmark support library项目地址: https://gitcode.com/GitHub_Trending/benchmark3/benchmark本指南以仓库文档 platform_specific_build_instructions.md 为骨架系统讲解 Google BenchmarkC 微基准测试库在不同编译器与操作系统上的构建差异GCC 下的 pthread 链接、Windows Visual Studio 下的shlwapi与静态库宏、Intel 编译器切换、Solaris 下的 kstat 依赖等。读完本文你将能针对目标平台正确配置链接选项与 CMake 参数避免编译通过却运行报错这类棘手问题并可结合源码理解每一条链接规则背后的真实原因。为什么 Google Benchmark 需要平台特定的构建说明Google Benchmark 是一个 C11 可用的微基准测试库底层依赖操作系统提供的线程、时钟与 CPU 信息查询能力。由于各平台的运行时库和系统 API 差异巨大例如 Windows 用注册表记录 CPU 频率、Solaris 依赖 kstat、QNX 把 pthread 内置于 libc构建时往往需要显式链接不同的系统库。从源码结构看这种平台差异被封装在 internal_macros.h 中通过一组编译期宏BENCHMARK_OS_WINDOWS、BENCHMARK_OS_SOLARIS、BENCHMARK_OS_QNX、BENCHMARK_OS_LINUX等在头文件层面区分操作系统并在 src/CMakeLists.txt 中按CMAKE_SYSTEM_NAME自动追加对应的系统库# We need extra libraries on Windows if(${CMAKE_SYSTEM_NAME} MATCHES Windows) target_link_libraries(benchmark PRIVATE shlwapi) endif() # We need extra libraries on Solaris if(${CMAKE_SYSTEM_NAME} MATCHES SunOS) target_link_libraries(benchmark PRIVATE kstat) endif()也就是说当你使用 CMake 构建并链接benchmark::benchmark目标时这些系统库大多会自动带上本文的链接指令主要面向手工编译直接调用 g/cl或需要理解构建产物依赖的场景。使用 GCC 构建必须链接 pthread当使用 GCC 构建 Google Benchmark 并编译自己的基准程序时必须在链接阶段加上-pthread。为什么必须加-pthread原因在于 GCC 对std::thread的实现方式GCC 的 libstdc 将std::thread映射到 POSIX 线程pthread之上因此最终可执行文件必须链接 pthread 库。值得警惕的是缺少 pthread 链接通常不会在链接期报错而是表现为运行期异常除非你使用 libc。这种链接成功、运行崩溃的隐蔽行为正是平台构建说明中最容易踩的坑详见上游 issue #67。在顶层 CMakeLists.txt 中可以看到项目自身构建时也统一走find_package(Threads REQUIRED)并设置THREADS_PREFER_PTHREAD_FLAG ON优先使用-pthread形式的编译/链接标志# Ensure we have pthreads set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED)手工链接示例参考 README 中的用法手工编译基准程序时应在链接命令中加入-pthread# 假设 benchmark 源码与 build 目录位于当前目录下 $ g mybenchmark.cc -stdc11 -isystem benchmark/include \ -Lbenchmark/build/src -lbenchmark -pthread -o mybenchmark注意也可以使用-lpthread代替-pthread但官方明确提示-lpthread存在命令行参数顺序问题链接库必须出现在引用它的源文件/目标文件之后因此推荐始终使用-pthread这一编译器统一处理的标志。QNX 特例pthread 内置于 libc在 QNX 系统上情况有所不同pthread 库是 libc 的一部分通常会随 libc 自动包含因此不存在单独的 pthread 库需要链接。从实现上看QNX 分支也沿用了这一假设——顶层 CMakeLists.txt 对实时库rt的检测同样显式针对 QNX 关闭# Check for rt library, but explicitly disable for QNX if(QNXNTO) set(HAVE_LIB_RT FALSE) else() check_library_exists(rt shm_open HAVE_LIB_RT) endif()类似的思路也体现在源码层QNX 分支下 sysinfo.cc 直接通过SYSPAGE_ENTRY(cpuinfo)-speed读取 CPU 频率无需额外链接系统库。使用 Visual Studio2015 / 2017 / 2022构建shlwapi 与静态库宏在 Windows 上使用 Visual Studio 构建时核心要点有两个shlwapi库的链接以及静态库场景下的BENCHMARK_STATIC_DEFINE宏。为什么需要shlwapishlwapiShell Lightweight Utility Library是 Windows 的系统库Google Benchmark 用它支撑CPUInfo中读取注册表的调用。在 sysinfo.cc 中可以找到实际调用程序通过SHGetValueA从注册表键HARDWARE\DESCRIPTION\System\CentralProcessor\0读取~MHz值以此获得 CPU 主频用于元数据输出// In NT, read MHz from the registry. DWORD data, data_size sizeof(data); if (IsWindowsXPOrGreater() SUCCEEDED( SHGetValueA(HKEY_LOCAL_MACHINE, HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0, ~MHz, nullptr, data, data_size))) { return static_castdouble(static_castint64_t(data) * static_castint64_t(1000 * 1000)); // was mhz }源码顶部也直接包含了shlwapi.h见 sysinfo.cc。当你用 CMake 构建时src/CMakeLists.txt 会自动为benchmark目标私有链接shlwapi而手工在 Visual Studio 工程中集成时则需要自行添加。手工添加 shlwapi 的两种方式方式一在 Visual Studio 的[配置属性 链接器 输入]Configuration Properties Linker Input中添加shlwapi.lib。方式二在源码中通过#pragma comment让链接器自动附加库。首先在[配置属性 链接器 常规 附加库目录]中填入生成库文件包含benchmark.lib所在目录然后在代码中加入#ifdef _WIN32 #pragma comment ( lib, Shlwapi.lib ) #ifdef _DEBUG #pragma comment ( lib, benchmark.lib ) #else #pragma comment ( lib, benchmark.lib ) #endif #endif使用静态库必须定义 BENCHMARK_STATIC_DEFINE当链接静态版本的 benchmark 库时必须在[配置属性 C/C 预处理器 预处理器定义]中添加BENCHMARK_STATIC_DEFINE。这一要求的根源在 export.hWindows 下默认使用__declspec(dllexport)/__declspec(dllimport)管理符号导入导出。若未定义BENCHMARK_STATIC_DEFINE消费方会把BENCHMARK_EXPORT展开为__declspec(dllimport)导致静态链接时符号解析异常而一旦定义该宏BENCHMARK_EXPORT会被置空#ifdef BENCHMARK_STATIC_DEFINE #define BENCHMARK_EXPORT #define BENCHMARK_NO_EXPORT #else // BENCHMARK_STATIC_DEFINE ... #endif // BENCHMARK_STATIC_DEFINECMake 侧的逻辑与之对应当BUILD_SHARED_LIBS未开启时src/CMakeLists.txt 会向benchmark目标公开传播-DBENCHMARK_STATIC_DEFINE所以通过benchmark::benchmark目标消费时无需手工处理。使用 CMake GUI 构建的完整步骤除命令行外也可以使用 CMake 的图形界面打开CMake GUI。在Where to build the binaries构建二进制目录中填入源码路径加上build例如D:\...\benchmark\build。在CMAKE_INSTALL_PREFIX中填入源码路径加上install。依次点击Configure配置、Generate生成、Open Project打开工程。如果构建失败可以先删除整个构建目录重新开始或取消勾选部分构建选项减少构建范围后再试。Debug 与 Release 的配置注意点需要留意构建配置与运行时的一致性README 建议在生成构建系统文件时指定-DCMAKE_BUILD_TYPERelease并在构建命令中使用--config Release多配置生成器如 Visual Studio 需要--config指定配置。此外Windows 下静态/共享库的选择遵循 CMake 的BUILD_SHARED_LIBS设置应保证 benchmark 库与被链接目标使用相同的运行库配置。使用 Intel 编译器构建基于 Visual Studio 工程切换对于 Intel 2015 Update 1 或 Intel System Studio Update 4构建流程完全复用上述 Visual Studio 的步骤先按 Visual Studio 一节完成配置与生成包括shlwapi链接与BENCHMARK_STATIC_DEFINE设置。构建完成后在 Visual Studio 中右键点击解决方案将构建工具切换为 Intel即把平台工具集改为 Intel C Compiler 对应的选项。即先生成 VS 工程再切换编译器的两步法不需要单独维护一套 Intel 专用配置。在 Solaris 上构建与运行链接 kstat如果要在 Solaris 上运行基准测试需要额外链接 kstat 库在链接命令中追加-lkstat。kstat 是 Solaris 的内核统计接口Google Benchmark 通过它获取 CPU 主频信息。在 sysinfo.cc 中可以找到完整的调用链kstat_open()打开/dev/kstatkstat_lookup()查找cpu_info模块的cpu_info0实例kstat_read()读取数据后再从current_clock_Hz字段取得时钟频率#elif defined(BENCHMARK_OS_SOLARIS) kstat_ctl_t* kc kstat_open(); if (!kc) { std::cerr failed to open /dev/kstat\n; return -1; } kstat_t* ksp kstat_lookup(kc, const_castchar*(cpu_info), -1, const_castchar*(cpu_info0)); ... kstat_named_t* knp (kstat_named_t*)kstat_data_lookup( ksp, const_castchar*(current_clock_Hz)); ...因此缺少-lkstat时CPU 频率读取会失败并打印 failed to open /dev/kstat 之类的错误信息进而退化到估算路径sysinfo.cc 中基于循环计数的粗略估算。同样地通过 CMake 构建时该依赖已由 src/CMakeLists.txt 自动处理仅手工编译时需要显式添加-lkstat。延伸其他隐藏的平台相关构建细节围绕同一主题仓库中还有几个与平台构建强相关的细节值得一并掌握rt实时库非 QNX 平台会检测rt库shm_open存在时私有链接rt见 src/CMakeLists.txt用于提供 POSIX 实时扩展符号。pthread 亲和性cxx_feature_check(PTHREAD_AFFINITY)检测线程亲和性支持通过BENCHMARK_HAS_PTHREAD_AFFINITY宏控制ThreadAffinityGuard等实现见 CMakeLists.txt 与 src/CMakeLists.txt。静态/共享库符号导出非 Windows 平台使用__attribute__((visibility(default)))控制符号可见性见 export.hWindows 平台则依赖__declspec与benchmark_EXPORTS宏的组合。更多平台支持矩阵除了本文涉及的 GCC/MSVC/Intel/Solaris/QNXinternal_macros.h还识别 FreeBSD、NetBSD、OpenBSD、DragonFly、macOS/iOS、Android、Fuchsia、z/OS、QuRT 等系统对应不同的 CPU 频率读取分支sysctl、kstat、SYSPAGE 等可据此推断各平台的链接需求。总结平台特定构建问题的本质是 Google Benchmark 需要访问各操作系统独有的线程与 CPU 信息接口GCC 下std::thread依赖 pthread-pthreadQNX 例外Windows 下CPUInfo通过shlwapi读取注册表静态库还需BENCHMARK_STATIC_DEFINESolaris 下通过-lkstat获取 CPU 频率Intel 编译器则复用 Visual Studio 工程再切换工具集。理解这些规则背后的源码实现就能在手工编译或工程集成时少走弯路——而绝大多数情况下直接使用 CMake 提供的benchmark::benchmark目标会自动处理上述所有平台差异。【免费下载链接】benchmarkA microbenchmark support library项目地址: https://gitcode.com/GitHub_Trending/benchmark3/benchmark创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
