在编译时获取源文件的基本名称

我正在使用GCC; __FILE__返回当前源文件的完整路径和名称: /path/to/file.cpp 。 有没有办法在编译时获取文件的名称file.cpp (没有它的路径)? 是否可以以便携方式执行此操作? 模板元编程可以应用于字符串吗?

我在错误记录宏中使用它。 我真的不希望我的源代码完整路径进入可执行文件。

如果您正在使用make程序,您应该能够事先处理文件名并将其作为宏传递给gcc以在程序中使用。

在makefile中,更改行:

 file.o: file.c gcc -c -o file.o src/file.c 

至:

 file.o: src/file.c gcc "-D__MYFILE__=\"`basename $<`\"" -c -o file.o src/file.c 

这将允许您在代码中使用__MYFILE__而不是__FILE__

使用源文件的基名($ <)意味着您可以在通用规则中使用它,例如“.co”。

以下代码说明了它的工作原理。

文件makefile:

 mainprog: main.o makefile gcc -o mainprog main.o main.o: src/main.c makefile gcc "-D__MYFILE__=\"`basename $<`\"" -c -o main.o src/main.c 

文件src / main.c:

 #include  int main (int argc, char *argv[]) { printf ("file = %s\n", __MYFILE__); return 0; } 

从shell运行:

 pax@pax-desktop:~$ mainprog file = main.c pax@pax-desktop:~$ 

注意“file =”行只包含文件的基名,而不是dirname。

考虑这个简单的源代码:

 #include  int main(void) { puts(__FILE__); return(0); } 

在Solaris上,使用GCC 4.3.1,如果我使用以下命令编译它:

 gcc -ox xc && ./x 

输出是’ xc ‘如果我使用以下方法编译它:

 gcc -ox $PWD/xc && ./x 

然后__FILE__映射到完整路径(’ /work1/jleffler/tmp/xc ‘)。 如果我用以下方法编译它:

 gcc -ox ../tmp/xc && ./x 

然后__FILE__映射到’ ../tmp/xc ‘。

所以,基本上,__ FILE__是源文件的路径名。 如果使用要在对象中看到的名称构建,一切都很好。

如果这是不可能的(无论出于何种原因),那么你将不得不进入其他人建议的修复。

您的错误记录宏有什么作用? 我想在某些时候宏最终会调用某种函数来进行日志记录,为什么不在运行时将被调用的函数条带关闭路径组件?

 #define LOG(message) _log(__FILE__, message) void _log(file, message) { #ifndef DEBUG strippath(file); // in some suitable way #endif cerr << "Log: " << file << ": " << message; // or whatever } 

您可以使用模板元编程来完成它,但是没有内置的方法来完成它。

编辑:嗯,纠正。 根据我刚看到的一个页面 ,GCC使用它为文件指定的路径。 如果给它全名,它会嵌入它; 如果它只给了一个相对的,它只会嵌入那个。 我自己没有尝试过。

我不知道直接的方式。 你可以使用:

 #line 1 "filename.c" 

在源文件的顶部设置__FILE__的值,但我不确定这比硬编码要好得多。 或者只是使用#define来创建自己的宏。

另一种选择可能是使用-D和$(shell basename $ <)从Makefile传递名称

编辑:如果使用#define或-D选项,则应创建自己的新名称,而不是尝试重新定义__FILE__

从Glomek的想法,它可以像这样自动化:

源文件xc

 #line 1 MY_FILE_NAME #include  int main(void) { puts(__FILE__); return(0); } 

编译行(注意双引号外的单引号):

 gcc -DMY_FILE_NAME='"abcd.c"' -ox xc 

输出是’ abcd.c ‘。

由于您标记了CMake,这里有一个简洁的解决方案可以添加到您的CMakeLists.txt :(复制自http://www.cmake.org/pipermail/cmake/2011-December/048281.html )。 (注意:有些编译器不支持per-file COMPILE_DEFINITIONS!但它适用于gcc)

 set(SRCS a/a.cpp b/b.cpp c/c.cpp d/d.cpp) foreach(f IN LISTS SRCS) get_filename_component(b ${f} NAME) set_source_files_properties(${f} PROPERTIES COMPILE_DEFINITIONS "MYSRCNAME=${b}") endforeach() add_executable(foo ${SRCS}) 

注意:对于我的应用程序,我需要像这样转义文件名字符串:

 COMPILE_DEFINITIONS "MYSRCNAME=\"${b}\"") 

您可以将__FILE__分配给一个字符串,然后调用_splitpath()来从中删除它们。 这可能是一个仅限Windows / MSVC的解决方案,说实话我不知道。

我知道您正在寻找一个编译时解决方案,这是一个运行时解决方案,但我想,因为您使用文件名进行(可能是运行时)错误记录,这可能是一个简单直接的方式来获取你需要什么。

您可以将__FILE__和条带从您不想要的路径中删除(以编程方式)。 如果basedir满足您的需求,那么很好。 否则,从构建系统获取源目录根,其余的应该是可行的。

刚刚遇到同样的问题; 发现了一个不同的分辨率,只是想我会分享它:

在我的所有其他文件中包含的头文件中:

 static char * file_bname = NULL; #define __STRIPPED_FILE__ (file_bname ?: (file_bname = basename(__FILE__))) 

希望这对其他人也有用:)

只能以编程方式完成。

也许这很有用……

 filename = __FILE__ len = strlen(filename) char *temp = &filename[len -1] while(*temp!= filename) if(*temp == '\') break; 

你可以使用:

 bool IsDebugBuild() { return !NDEBUG; } 

或者,您可以在宏中使用NDEBUG来打开/关闭这些文件路径。