如何编写类似于__FILE__的cpp __DIR__宏?

10
__FILE____LINE__宏内置于C预处理器中,通常用于打印带有文件名和行号的调试输出。我需要类似的东西,但只需在路径末尾给出目录名称。例如,如果我的代码位于: /home/davidc/some/path/to/some/code/foo/bar,我需要一个宏,它只会给我"bar";如果代码位于/home/davidc/some/path/to/some/code/foo/bee,则需要它给我"bee"。
有什么想法吗?(顺便说一句,这是一个C++应用程序)。
更新:要明确,我需要一个在编译时就能给我包含目录名称的字符串的宏,我不想在运行时进行任何字符串处理。
5个回答

9

如果您正在使用GNU make构建项目,则可以尝试执行以下操作:

%.o: %.cpp
    $(CC) $(CFLAGS) -D__DIR__="$(strip $(lastword $(subst /, , $(dir $(abspath $<)))))" -c $< -o $@

这可能是我在Makefile中想做的最糟糕的事情。我认为你不会在编译器的限制范围内找到快速或干净的方法来解决这个问题,因此我建议寻找巧妙的方法将信息注入编译过程。

祝好运。


噫,你比我快一分钟——我也在做几乎完全相同的事情。如果最后一个目录有空格,它就不太好用了,但除此之外,这是一个完美的解决方案。相信我——在Makefiles中,我已经看到了更糟糕的怪物 - Adam Rosenfield
@Adam:今晚我不得不进行一些“修复”以解决版本号以零开头的问题。从07.64到08.01给我们带来了很多不必要的烦恼。 - D.Shawley
我正在使用CMake,所以我应该能够做到这一点。谢谢! - David Claridge
@D.Shawley:这只适用于与翻译单元相同目录中的文件。我想唯一的解决方案是替换预处理器或建议使用另一个扩展名。 - user877329

3

没有内建的宏来实现这个功能,但是你可以自己编写一个小的解析程序,用于从给定的全路径文件名中提取目录名。我们称这个函数为:

extern std::string parseLastDir (const char *path);

然后,您可以创建一个如下的宏:
#define __DIR__ parseLastDir (__FILE__)

这个函数将会表现得像你想要的那样(它会给你一个std::string而不是char *,以便清理工作更加明确),并具有相关的语义(其结果取决于调用它的文件,以便始终获取正确的目录)。


1
事实上,我希望“parseLastDir”在编译时发生(没有理由不这样做,因为__FILE__是预定的)。我想也许boost::mpl中的某些东西或者其他一些宏内的hacky模板元编程可以让我做到这一点。这是一个相当性能关键的应用程序,我不想浪费时间在运行时进行不必要的字符串处理。 - David Claridge
糟糕,忘记了Markdown语法 应该是_FILE__,而不是__FILE_ - David Claridge
1
问题在于编译时无法访问字符串字面量 - 目前不可能。不过看起来在 C++1x 中我们将拥有编译时字符串处理的功能。 - Georg Fritzsche
1
好的,但你所要求的内容受到语言本身定义的限制。C++并不包含像你需要的真正的元编程语言(显然LISP可以轻松做到这一点)。人们过去处理这类问题的一种方法是编写自己的预处理器或使用其他现有的预处理器。 - Paul Hsieh
1
我曾经认为C++模板是图灵完备的。因此,C++确实具有真正的元编程能力。 - David Claridge
我认为它在类型和源代码的输入输出方面是图灵完备的。FILE 不是代码或类型,而是特定的文本替换。将 FILE 字节视为 C++ 预处理器“沙盒”之外的内容,就像直接内存在 Java 的沙盒之外一样(在这两种情况下,您都可以在运行时通过代码模拟它,甚至可以通过内部映射方式访问它的实例,但真正的原始内容本身是不可访问的)。 - Paul Hsieh

2

1
接近了,但还差一点。它给出了传递到g++的文件名/路径,因此它截断了路径的一些早期部分,但并没有像我想要的那样只给出最后一个目录(因为我的代码在许多子目录中),所以现在我只得到了foo/bar而不是/home/davidc/some/path/to/some/code/foo/bar,接近了,但仍然存在同样的问题。 - David Claridge
真糟糕,就差一点了。我要继续寻找。 - Robert Massaioli

2

根据您的编译器/软件构建方式,您可以在编译时声明一个宏作为当前路径或任何路径。

 gcc -D__DIR__=/usr/src/test/ test.c

我从未使用过MS编译器,但我知道ICC也有类似的选项。请参考gcc manpage

谢谢,但那不是我想要的。我正在编译一个包含数百个文件的大型项目,每个文件都在不同的目录中,我的想法是让每个文件都可以 #include 这个宏,它将返回与其自身源文件位置对应的目录名称,我不想“硬编码”到任何特定的路径。 - David Claridge
哦,对了,我在Linux上使用g++。 - David Claridge

0
如何更改您的 Makefile/ 构建系统,以便对于 .../bar/file.cc,编译行将包括-D __DIR__ bar。这样应该更容易...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接