如何使用 __FILE__ 配置 MSVC 以显示头文件的相对路径?

How do I configure MSVC to show relative path for header files using __FILE__?

提问人:tinman 提问时间:1/10/2017 最后编辑:tinman 更新时间:12/20/2022 访问量:1233

问:

我最近发现,在MSVC(特别是2013)中使用预定义的宏时,默认情况下它将打印源文件的相对路径和头文件的绝对路径。__FILE__

例如,我有一个包含以下内容的 VS 项目:

Solution
    Project
        Headers
            foo.h
        Sources
            main.cpp

main.cpp 和 foo.h 在磁盘上的同一目录中。

main.cpp:

#include <iostream>
#include <string>

#include "foo.h"

int main(int, char*[])
{
    std::cout << __FILE__ << std::endl;
    foo::bar();

    std::cout << "Press enter to exit";
    std::string str;
    std::getline(std::cin, str);

    return 0;
}

foo.h:

#ifndef FOO_H
#define FOO_H

#include <iosfwd>

class foo
{
public:
    static void bar()
    {
        std::cout << __FILE__ << std::endl;
    }
};

#endif

当我运行应用程序时(在发布模式下,使用默认设置 - 编译时未定义),则输出为:/Zi/FC

main.cpp
c:\users\<user>\documents\dev\solution\project\foo.h
Press enter to exit

我知道我可能会传入一个基本路径并在运行时将其剥离,但我想知道是否有任何方法可以在编译时更改此行为?显然,定义会产生相反的结果,我在 MSVC 手册中看不到任何其他内容来控制标头路径的显示。我认为这可能是一种硬编码行为,因此,如果编译器能够从不同的包含路径中获取两个名为 foo.h 的文件,您仍然可以区分它们,或者因为可能有一个与源基础无关的包含路径,并且显示为相对会很混乱。/FC

C 可视化 C++ C 预处理器

评论

1赞 sb9 1/10/2017
调用编译器时,包含路径(/I 参数)是指定为绝对路径还是相对路径?如果是绝对的,那么如果你通过一个相对路径,行为会改变吗?
1赞 sb9 1/10/2017
另请查看 stackoverflow.com/questions/8487986/file-macro-shows-full-path
0赞 tinman 1/12/2017
@sb9:感谢您链接其他 Q。 IDE 未设置 include 路径,因为标头与源位于同一路径中。从命令行生成并尝试将 /I 参数设置为绝对值或相对值没有区别 - 它始终打印绝对路径。
1赞 phuclv 12/13/2022
duplicates:__FILE__和 PDB 的相对路径,如何使用 FILE 配置 MSVC 以显示头文件的相对路径?。但是由于这是 C++,因此只需创建一个 constexpr 函数来解析路径即可解决
2赞 Sedenion 12/15/2022
对于 VS2022,行为仍然相同。developercommunity 上有一个相关的功能请求。此外,C++20 的行为与 相同。所以我想唯一的解决方案是通过在编译时对__FILE__进行后处理来提取文件名。std::source_location::current().file_name()__FILE__

答:

0赞 user541686 12/16/2022 #1

我将发布我自己的解决方案,该解决方案并不完美,但这是我所知道的最接近的解决方法。

此代码包含在其中的每个文件都将从调用时去除前缀,因此二进制文件将不包含该前缀。PROJECT_DIR__FILE__assert

更好的解决方案可能希望根据需要添加前缀,处理,并可能保留不同卷上的任何绝对路径,但我在这里不做任何这些。..\/

// Add this to your .vcxproj:
// <PreprocessorDefinitions>PROJECT_DIR="$(ProjectDir.Replace('\', '\\').TrimEnd('\'))";%(PreprocessorDefinitions)</PreprocessorDefinitions>

#include <cassert>
#include <type_traits>

#ifdef PROJECT_DIR
template<class Char1, class Char2>
constexpr size_t path_imismatch(Char1 const a[], Char2 const b[])
{
    size_t r = 0;
    size_t i = 0;
    for (;;)
    {
        Char1 ch1 = a[i];
        Char2 ch2 = b[i];
        bool const finished = ch1 == Char1() || ch2 == Char2() || !(ch1 == ch2);
        if (ch2 == Char2()) { ch2 = '\\'; }
        bool const isdirsep = ch1 == '\\' && ch1 == ch2;
        if (isdirsep && ch1 == ch2) { r = i + 1; }
        if (finished) { break; }
        ++i;
    }
    return r;
}
#define FILENAME(File, Root) ([]() { typedef std::decay_t<decltype(*(File))> _FileNameChar; constexpr _FileNameChar const f[] = File; enum : size_t { O = path_imismatch(f, Root), N = sizeof(f) / sizeof(*f) - O }; constexpr std::array<_FileNameChar, N> const result = []() { std::array<_FileNameChar, N> r = {}; for (size_t i = 0; i < N; ++i) { r[i] = f[O + i]; } return r; }(); return std::integral_constant<std::remove_const_t<decltype(result)>, result>(); }().value.data())
#define _wassert(Source, File, Line) (_wassert)(Source, FILENAME(File, _CRT_WIDE(PROJECT_DIR)), Line)
#endif