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

发布于 2024-07-08 02:32:12 字数 215 浏览 3 评论 0原文

我正在使用海湾合作委员会; __FILE__ 返回当前源文件的完整路径和名称:/path/to/file.cpp。 有没有办法在编译时只获取文件名 file.cpp (不带路径)? 是否有可能以便携的方式做到这一点? 模板元编程可以应用于字符串吗?

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

I'm using GCC; __FILE__ returns the current source file's entire path and name: /path/to/file.cpp. Is there a way to get just the file's name file.cpp (without its path) at compile time? Is it possible to do this in a portable way? Can template meta programming be applied to strings?

I am using this in an error logging macro. I really do not want my source's full path making its way into the executable.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

策马西风 2024-07-15 02:32:12

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

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

为:

file.o: src/file.c
    gcc "-DMYFILE=\"`basename 
lt;`\"" -c -o file.o src/file.c

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

使用源文件 $<basename 意味着您可以在 .co 等通用规则中使用它。 下面的代码说明了它是如何工作的。 首先是 makefile

mainprog: main.o makefile
    gcc -o mainprog main.o

main.o: src/main.c makefile
    gcc "-DMYFILE=\"`basename 
lt;`\"" -c -o main.o src/main.c

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

#include <stdio.h>

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

最后是显示其运行情况的记录:

pax:~$ mainprog
file = main.c

注意 file = > 行包含文件的基本名称,而不包含目录名称。

If you're using a make program, you should be able to munge the filename beforehand and pass it as a macro to gcc to be used in your program. For example, in your makefile, change the line:

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

to:

file.o: src/file.c
    gcc "-DMYFILE=\"`basename 
lt;`\"" -c -o file.o src/file.c

This will allow you to use MYFILE in your code instead of __FILE__.

The use of basename of the source file $< means you can use it in generalized rules such as .c.o. The following code illustrates how it works. First, a makefile:

mainprog: main.o makefile
    gcc -o mainprog main.o

main.o: src/main.c makefile
    gcc "-DMYFILE=\"`basename 
lt;`\"" -c -o main.o src/main.c

Then a file in a subdirectory, src/main.c:

#include <stdio.h>

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

Finally, a transcript showing it running:

pax:~$ mainprog
file = main.c

Note the file = line which contains only the base name of the file, not the directory name as well.

半世蒼涼 2024-07-15 02:32:12

我不知道有什么直接的方法。 您可以

#line 1 "filename.c"

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

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

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

I don't know of a direct way. You could use:

#line 1 "filename.c"

at the top of the source file to set the value of __FILE__, but I'm not sure that that's much better than hard coding it. or just using a #define to create your own macro.

Another option might be to pass the name from your Makefile using -D and $(shell basename $<)

Edit: If you use a #define or the -D option, you should create your own new name and not try to redefine __FILE__.

生生漫 2024-07-15 02:32:12

由于您标记了 CMake,因此有一个巧妙的解决方案可以添加到您的 CMakeLists.txt 中:
(复制自 http://www.cmake.org/pipermail/cmake/ 2011-12 月/048281.html)。 (注意:有些编译器不支持每个文件 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}\"")

Since you tagged CMake, here's a neat solution to add to your CMakeLists.txt:
(copied from http://www.cmake.org/pipermail/cmake/2011-December/048281.html ). (Note : some compilers don't support per-file COMPILE_DEFINITIONS ! but it works with 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})

Note : For my application I needed to escape the filename string like this:

COMPILE_DEFINITIONS "MYSRCNAME=\"${b}\"")
暖心男生 2024-07-15 02:32:12

考虑这个简单的源代码:

#include <stdio.h>
int main(void)
{
    puts(__FILE__);
    return(0);
}

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

gcc -o x x.c && ./x

输出为 'xc' 如果我使用以下方式编译它:

gcc -o x $PWD/x.c && ./x

那么 __FILE__ 映射到完整路径 ('<代码>/work1/jleffler/tmp/xc')。 如果我使用以下命令编译它:

gcc -o x ../tmp/x.c && ./x

那么 __FILE__ 映射到 '../tmp/xc'。

所以,基本上, __FILE__ 是源文件的路径名。 如果您使用您希望在对象中看到的名称进行构建,那么一切都很好。

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

Consider this simple source code:

#include <stdio.h>
int main(void)
{
    puts(__FILE__);
    return(0);
}

On Solaris, with GCC 4.3.1, if I compile this using:

gcc -o x x.c && ./x

the output is 'x.c' If I compile it using:

gcc -o x $PWD/x.c && ./x

then __FILE__ maps to the full path ('/work1/jleffler/tmp/x.c'). If I compile it using:

gcc -o x ../tmp/x.c && ./x

then __FILE__ maps to '../tmp/x.c'.

So, basically, __FILE__ is the pathname of the source file. If you build with the name you want to see in the object, all is well.

If that is impossible (for whatever reason), then you will have to get into the fixes suggested by other people.

夏至、离别 2024-07-15 02:32:12

你的错误记录宏有什么作用? 我假设在某个时候宏最终会调用某种函数来进行日志记录,为什么不让被调用的函数在运行时剥离路径组件呢?

#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
}

What does your error logging macro do? I would presume at some point the macro eventually calls a function of some kind in order to do the logging, why not have the called function strip off the path component at runtime?

#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
}
撩起发的微风 2024-07-15 02:32:12

您也许可以使用模板元编程来做到这一点,但没有内置的方法可以做到这一点。

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

You might be able to do it with template metaprogramming, but there's no built-in way to do it.

EDIT: Hm, correction. According to one page I just saw, GCC uses the path that it's given for the file. If it's given the full name, it'll embed it; if it's only given a relative one, it'll only embed that. I haven't tried it myself though.

可爱暴击 2024-07-15 02:32:12

这个问题已经有 12 年历史了,早在 2008 年,这个解决方案还不可用,但从

GCC 8 和 CLANG 10 开始,可以使用选项 -fmacro-prefix-map
根据海湾合作委员会手册:

-fmacro-prefix-map=旧=新
当预处理驻留在目录 'old' 中的文件时,展开
__FILE____BASE_FILE__ 宏,就好像文件驻留在
目录'new'代替。 这可用于更改绝对路径
使用 '.' 表示 new 的相对路径,这可能会导致更多
与位置无关的可复制构建。 这个选项也
在编译期间影响__builtin_FILE()。 也可以看看
'-ffile-prefix-map'。

例如,我的 IDE (Eclipse) 中的 makefile 对于某些文件包含以下 GCC 参数:-fmacro-prefix-map="../Sources/"=.
因此,我的调试日志始终仅显示文件名,而不显示路径。

注:GCC 8.1 和 Clang 10 分别于 2018 年 5 月和 2020 年 3 月发布。 因此,目前,到 2020 年 9 月,只有我的部分环境支持 -fmacro-prefix-map。

The question is already 12 years old and back in 2008 this solution wasn't available, but

Starting with GCC 8 and CLANG 10, one can use the option -fmacro-prefix-map.
Acording to GCC Manual:

-fmacro-prefix-map=old=new
When preprocessing files residing in directory ‘old’, expand the
__FILE__ and __BASE_FILE__ macros as if the files resided in
directory ‘new’ instead. This can be used to change an absolute path to
a relative path by using ‘.’ for new which can result in more
reproducible builds that are location independent. This option also
affects __builtin_FILE() during compilation. See also
‘-ffile-prefix-map’.

For instance, the makefile in my IDE (Eclipse) includes the following parameter for GCC for some files: -fmacro-prefix-map="../Sources/"=.
Thus, my debug logs always show only the filenames, without the paths.

Note: GCC 8.1 and Clang 10 were released in May 2018 and March 2020, respectively. So, currently, in September of 2020, only some of my environments support -fmacro-prefix-map.

风追烟花雨 2024-07-15 02:32:12

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

源文件 xc

#line 1 MY_FILE_NAME
#include <stdio.h>

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

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

gcc -DMY_FILE_NAME='"abcd.c"' -o x x.c

输出为 'abcd.c'。

Taking the idea from Glomek, it can be automated like this:

Source file x.c

#line 1 MY_FILE_NAME
#include <stdio.h>

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

Compilation line (beware the single quotes outside the double quotes):

gcc -DMY_FILE_NAME='"abcd.c"' -o x x.c

The output is 'abcd.c'.

迷荒 2024-07-15 02:32:12

用cmake很容易。

DefineRelativeFilePaths.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 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 不会提供大量错误。

It is easy with cmake.

DefineRelativeFilePaths.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 ()

Somewhere in 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

That's it. Now you can make pretty log messages.

#define ..._LOG_HEADER(target) \
  fprintf(target, "%s %s:%u - ", __func__, __RELATIVE_FILE_PATH__, __LINE__);

func src/main.c:22 - my error

PS It is better to declear in config.h.in -> config.h

#ifndef __RELATIVE_FILE_PATH__
#define __RELATIVE_FILE_PATH__ __FILE__
#endif

So your linter wan't provide rain of errors.

つ可否回来 2024-07-15 02:32:12

您可以将 __FILE__ 分配给一个字符串,然后调用 _splitpath() 将其拆分出来。 这可能是一个仅限 Windows/MSVC 的解决方案,老实说我不知道​​。

我知道您正在寻找编译时解决方案,这是一个运行时解决方案,但我认为由于您使用文件名来进行(大概是运行时)错误日志记录,这可能是一种简单直接的方法来帮助您你需要什么。

You can assign __FILE__ to a string, and then call _splitpath() to rip the pieces out of it. This might be a Windows/MSVC-only solution, honestly I don't know.

I know you were looking for a compile-time solution and this is a run-time solution, but I figured since you were using the filename to do (presumably run-time) error logging, this could be a simple straightforward way to get you what you need.

巨坚强 2024-07-15 02:32:12

您可以获取 __FILE__ 并去掉您不需要的路径部分(以编程方式)。 如果 basedir 满足您的需求,那就没问题了。 否则,从构建系统获取源目录根目录,其余的应该是可行的。

You can take __FILE__ and the strip off the part of path you don't want (programatically). If basedir satisfies your needs, then fine. Otherwise, get source dir root from your build system, and the rest should be doable.

违心° 2024-07-15 02:32:12

刚刚遇到同样的问题; 找到了不同的分辨率,只是想分享它:

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

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

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

Just got the same issue; found a different resolution, just thought I'd share it:

In a header file included in all my other files:

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

Hope this is useful to someone else as well :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文