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

C++ 在编译时获取源文件的基名称,c++,c,makefile,macros,compiler-construction,C++,C,Makefile,Macros,Compiler Construction,我正在使用GCC__返回当前源文件的完整路径和名称:/path/to/FILE.cpp。有没有办法在编译时只获取文件名file.cpp(不带路径)?是否可以以便携方式进行此操作?模板元编程可以应用于字符串吗 我在一个错误日志宏中使用它。我真的不希望我的源代码的完整路径进入可执行文件。您可以使用模板元编程来完成,但没有内置的方法来完成 编辑:嗯,更正。根据,GCC使用为文件指定的路径。如果给出了全名,它将嵌入它;如果只给它一个相对的,它只会嵌入它。不过我自己还没有试过。我不知道直接的方法。您可以使

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


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

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


编辑:嗯,更正。根据,GCC使用为文件指定的路径。如果给出了全名,它将嵌入它;如果只给它一个相对的,它只会嵌入它。不过我自己还没有试过。

我不知道直接的方法。您可以使用:

#line 1 "filename.c"
bool IsDebugBuild()
{
    return !NDEBUG;
}
在源文件的顶部设置
\uuuuu file\uuuu
的值,但我不确定这比硬编码好多少。或者只是使用#define创建自己的宏

另一个选项可能是使用-D和$(shell basename$从Makefile传递名称,您可以使用:

#line 1 "filename.c"
bool IsDebugBuild()
{
    return !NDEBUG;
}

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

错误记录宏的作用是什么?我想在某个时候,宏最终会调用某种函数来进行记录,为什么不在运行时将被调用的函数从路径组件中剥离

#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
}
#定义日志(消息)(文件)(消息)
无效日志(文件、消息)
{
#ifndef调试
strippath(file);//以某种合适的方式
#恩迪夫

cerr如果您使用的是
make
程序,您应该能够预先将文件名作为宏传递给
gcc
,以便在程序中使用。例如,在
makefile
中,更改行:

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

然后是子目录中的文件,
src/main.c

#include <stdio.h>

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

请注意
file=
行,该行仅包含文件的基本名称,不包含目录名称。

您可以获取\uuuu file\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。如果basedir满足您的需要,则可以。否则,请从生成系统中获取source dir根目录,其余的都应该是可行的。

考虑以下简单的源代码:

#include <stdio.h>
int main(void)
{
    puts(__FILE__);
    return(0);
}
如果使用以下方法编译,则输出为“
x.c
”:

gcc -o x $PWD/x.c && ./x
gcc -o x ../tmp/x.c && ./x
然后uuu文件映射到完整路径(“
/work1/jleffler/tmp/x.c
”)。如果我使用以下方法编译它:

gcc -o x $PWD/x.c && ./x
gcc -o x ../tmp/x.c && ./x
然后,文件映射到“
。/tmp/x.c

因此,基本上,_FILE__是源文件的路径名。如果使用希望在对象中看到的名称进行构建,则一切正常


如果这是不可能的(无论出于何种原因),那么您将不得不使用其他人建议的修复方法。

接受Glomek的想法,它可以自动执行,如下所示:

源文件x.c

#line 1 MY_FILE_NAME
#include <stdio.h>

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

输出为“
abcd.c
”。

只能通过编程方式完成

也许这是有用的

filename = __FILE__
len  = strlen(filename)

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

您可以将
\uuuu FILE\uuuu
分配给一个字符串,然后调用splitpath()将其拆分。老实说,这可能是Windows/MSVC唯一的解决方案,我不知道


我知道您正在寻找编译时解决方案,这是一个运行时解决方案,但我认为,由于您使用文件名进行(可能是运行时的)错误记录,这可能是一种简单直接的方法,可以满足您的需要。

只是遇到了同样的问题;找到了不同的解决方案,我想与您分享一下:

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

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

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

既然您标记了CMake,下面有一个简洁的解决方案可以添加到您的CMakeLists.txt中: (复制自)。(注意:某些编译器不支持每文件编译定义!但它可以与gcc一起使用)

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

COMPILE_DEFINITIONS "MYSRCNAME=\"${b}\"")
使用cmake很容易

definererelativefilepaths.cmake

function (cmake_define_relative_file_paths SOURCES)
  foreach (SOURCE IN LISTS SOURCES)
    file (
      RELATIVE_PATH RELATIVE_SOURCE_PATH
      ${PROJECT_SOURCE_DIR} ${SOURCE}
    )

    set_source_files_properties (
      ${SOURCE} PROPERTIES
      COMPILE_DEFINITIONS __RELATIVE_FILE_PATH__="${RELATIVE_SOURCE_PATH}"
    )
  endforeach ()
endfunction ()
CMakeLists.txt中的某个地方

set (SOURCES ${SOURCES}
  "${CMAKE_CURRENT_SOURCE_DIR}/common.c"
  "${CMAKE_CURRENT_SOURCE_DIR}/main.c"
)

include (DefineRelativeFilePaths)
cmake_define_relative_file_paths ("${SOURCES}")
cmake..&&make clean&&make VERBOSE=1

cc ... -D__RELATIVE_FILE_PATH__="src/main.c" ... -c src/main.c
就这样。现在你可以制作漂亮的日志消息了

#define ..._LOG_HEADER(target) \
  fprintf(target, "%s %s:%u - ", __func__, __RELATIVE_FILE_PATH__, __LINE__);
func src/main.c:22-我的错误

PS最好在
config.h.in
->
config.h

#ifndef __RELATIVE_FILE_PATH__
#define __RELATIVE_FILE_PATH__ __FILE__
#endif

因此,您的linter wan不会提供大量错误。

这个问题已经存在了18年,早在2008年,这个解决方案就不可用了,但是

从GCC 8和CLANG 10开始,可以使用-fmacro前缀映射选项。
根据GCC手册:

-fmacro prefix map=old=new
预处理驻留在目录“old”中的文件时,展开
\uuuuuuuuuuuu文件
\uuuuuu基本文件
宏,就像文件位于 改为“新建”目录。这可用于将绝对路径更改为 使用“.”表示新的相对路径,这可能会导致 独立于位置的可复制构建。此选项也 编译期间影响
\u内置文件()
。另请参阅 “-ffile前缀映射”

例如,my IDE(Eclipse)中的makefile为某些文件的GCC包含以下参数:
-fmacro prefix map=“../Sources/”=。

因此,我的调试日志总是只显示文件名,而不显示路径


注意:GCC 8.1和Clang 10分别于2018年5月和2020年3月发布。因此,目前,在2020年9月,只有我的一些环境支持-fmacro前缀映射。

文件名是给编译器的名称。我的源代码有一个目录结构,所以我不能只将文件名传递给编译器。此外,我正在使用CMake这个问题似乎总是给出完整的路径。我认为这个问题应该保留C++标签,因为模板元编程可能是一个有效的答案。也许@ BeNTalpPFA的复制品更像是一个复制的。
#define ..._LOG_HEADER(target) \
  fprintf(target, "%s %s:%u - ", __func__, __RELATIVE_FILE_PATH__, __LINE__);
#ifndef __RELATIVE_FILE_PATH__
#define __RELATIVE_FILE_PATH__ __FILE__
#endif