You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将CMake的CMAKE_SOURCE_DIR传入C++源码以缩短日志路径?

解决CMake传递CMAKE_SOURCE_DIR到C++代码并缩短std::source_location路径的问题

1. 修复编译定义的错误

你遇到的macro names must be identifiers错误,是因为手动添加-D和引号的写法不符合CMake规范。CMake的add_compile_definitions不需要手动指定-D参数,直接传入宏名和值即可,CMake会自动处理字符串的引号转义。

正确写法(全局生效):

add_compile_definitions(SOURCE_ROOT="${CMAKE_SOURCE_DIR}")

更推荐用target_compile_definitions(仅作用于指定目标,模块化更好):

target_compile_definitions(你的目标名称 PRIVATE SOURCE_ROOT="${CMAKE_SOURCE_DIR}")

2. 更可靠的替代方案:用configure_file生成配置头文件

如果项目路径包含特殊字符(如空格),或者想更清晰管理配置宏,建议使用configure_file:

  1. 创建模板头文件config.h.in:
#pragma once
#define SOURCE_ROOT "@CMAKE_SOURCE_DIR@"
  1. 在CMakeLists.txt中添加配置逻辑:
configure_file(
    ${CMAKE_SOURCE_DIR}/config.h.in
    ${CMAKE_BINARY_DIR}/generated/config.h
    @ONLY
)

# 将生成头文件的目录添加到目标的包含路径
target_include_directories(你的目标名称 PRIVATE ${CMAKE_BINARY_DIR}/generated)

之后在C++代码中直接包含#include <config.h>即可获取SOURCE_ROOT宏。

3. 在C++中实现路径缩短逻辑

拿到SOURCE_ROOT后,编写工具函数处理std::source_location返回的绝对路径:

#include <source_location>
#include <string_view>
#include <string>

// 缩短路径:去掉CMAKE_SOURCE_DIR前缀
std::string shorten_source_path(std::string_view full_path) {
    constexpr std::string_view root = SOURCE_ROOT;
    // C++20及以上支持starts_with
    if (full_path.starts_with(root)) {
        size_t skip_len = root.size();
        // 跳过根路径后的路径分隔符(如果存在)
        if (skip_len < full_path.size() && (full_path[skip_len] == '/' || full_path[skip_len] == '\\')) {
            ++skip_len;
        }
        return std::string(full_path.substr(skip_len));
    }
    return std::string(full_path);
}

// 日志示例函数
void log(const std::string& msg, const std::source_location& loc = std::source_location::current()) {
    auto short_path = shorten_source_path(loc.file_name());
    printf("[%s:%d] %s\n", short_path.c_str(), loc.line(), msg.c_str());
}

如果使用C++17及更早标准,替换starts_with为find实现:

size_t pos = full_path.find(root);
if (pos == 0) {
    size_t skip_len = root.size();
    if (skip_len < full_path.size() && (full_path[skip_len] == '/' || full_path[skip_len] == '\\')) {
        ++skip_len;
    }
    return std::string(full_path.substr(skip_len));
}

4. 跨平台兼容处理

  • 路径分隔符:Windows下路径用\,可以在CMake中先统一转换为/:
file(TO_CMAKE_PATH "${CMAKE_SOURCE_DIR}" CMAKE_SOURCE_DIR_CLEAN)
target_compile_definitions(你的目标名称 PRIVATE SOURCE_ROOT="${CMAKE_SOURCE_DIR_CLEAN}")

file(TO_CMAKE_PATH)会将路径转换为CMake统一的/分隔符,避免C++代码中处理两种分隔符。

  • 编译器兼容性:上述代码在GCC、Clang、MSVC下均能正常工作,需确保项目启用C20及以上标准(std::source_location依赖C20)。

内容的提问来源于stack exchange,提问作者Benjamin Buch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 12:17:29