__FILE__ macro shows full path
Solution 1
Try
#include <string.h>
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
For Windows use '\\' instead of '/'.
Solution 2
Here's a tip if you're using cmake. From: http://public.kitware.com/pipermail/cmake/2013-January/053117.html
I'm copying the tip so it's all on this page:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst
${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")
If you're using GNU make, I see no reason you couldn't extend this to your own makefiles. For example, you might have a line like this:
CXX_FLAGS+=-D__FILENAME__='\"$(subst $(SOURCE_PREFIX)/,,$(abspath $<))\"'"
where $(SOURCE_PREFIX)
is the prefix that you want to remove.
Then use __FILENAME__
in place of __FILE__
.
Solution 3
I have just thought of a great solution to this that works with both source and header files, is very efficient and works on compile time in all platforms without compiler-specific extensions. This solution also preserves the relative directory structure of your project, so you know in which folder the file is in, and only relative to the root of your project.
The idea is to get the size of the source directory with your build tool and just add it to the __FILE__
macro, removing the directory entirely and only showing the file name starting at your source directory.
The following example is implemented using CMake, but there's no reason it wouldn't work with any other build tools, because the trick is very simple.
On the CMakeLists.txt file, define a macro that has the length of the path to your project on CMake:
# The additional / is important to remove the last character from the path.
# Note that it does not matter if the OS uses / or \, because we are only
# saving the path size.
string(LENGTH "${CMAKE_SOURCE_DIR}/" SOURCE_PATH_SIZE)
add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}")
On your source code, define a __FILENAME__
macro that just adds the source path size to the __FILE__
macro:
#define __FILENAME__ (__FILE__ + SOURCE_PATH_SIZE)
Then just use this new macro instead of the __FILE__
macro. This works because the __FILE__
path will always start with the path to your CMake source dir. By removing it from the __FILE__
string the preprocessor will take care of specifying the correct file name and it will all be relative to the root of your CMake project.
If you care about the performance, this is as efficient as using __FILE__
, because both __FILE__
and SOURCE_PATH_SIZE
are known compile time constants, so it can be optimized away by the compiler.
The only place where this would fail is if you're using this on generated files and they're on a off-source build folder. Then you'll probably have to create another macro using the CMAKE_BUILD_DIR
variable instead of CMAKE_SOURCE_DIR
.
Solution 4
GCC 8 now has the -fmacro-prefix-map
and -ffile-prefix-map
options:
-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
.
-ffile-prefix-map=old=new
When compiling files residing in directory old, record any references to them in the result of the compilation as if the files resided in directory new instead. Specifying this option is equivalent to specifying all the individual
-f*-prefix-map
options. This can be used to make reproducible builds that are location independent. See also-fmacro-prefix-map
and-fdebug-prefix-map
.
Setting an invalid path for -ffile-prefix-map
(-fdebug-prefix-map
) will break debugging unless you tell your debugger how to map back. (gdb: set substitue-path
, vscode: "sourceFileMap"
).
If your intent is to only clean up __FILE__
just use -fmacro-prefix-map
.
Example:
So for my Jenkins builds I will add -ffile-prefix-map=${WORKSPACE}/=/
, and another to remove the local dev package install prefix.
NOTE Unfortunately the -ffile-prefix-map
and -fmacro-prefix-map
options are only available in GCC 8 onwards. For, say, GCC 5, we only have -fdebug-prefix-map
which does not affect __FILE__
.
Solution 5
At least for gcc, the value of __FILE__
is the file path as specified on the compiler's command line. If you compile file.c
like this:
gcc -c /full/path/to/file.c
the __FILE__
will expand to "/full/path/to/file.c"
. If you instead do this:
cd /full/path/to
gcc -c file.c
then __FILE__
will expand to just "file.c"
.
This may or may not be practical.
The C standard does not require this behavior. All it says about __FILE__
is that it expands to "The presumed name of the current source file (a character string literal)".
An alternative is to use the #line
directive. It overrides the current line number, and optionally the source file name. If you want to override the file name but leave the line number alone, use the __LINE__
macro.
For example, you can add this near the top of file.c
:
#line __LINE__ "file.c"
The only problem with this is that it assigns the specified line number to the following line, and the first argument to #line
has to be a digit-sequence so you can't do something like
#line (__LINE__-1) "file.c" // This is invalid
Ensuring that the file name in the #line
directive matches the actual name of the file is left as an exercise.
At least for gcc, this will also affect the file name reported in diagnostic messages.
Related videos on Youtube
mahmood
Updated on July 15, 2022Comments
-
mahmood almost 2 years
The standard predefined macro
__FILE__
available in C shows the full path to the file. Is there any way to short the path? I mean instead of/full/path/to/file.c
I see
to/file.c
or
file.c
-
cdleonard over 12 yearsIt would be really really great to find a preprocessor-only solution. I'm afraid that the suggestions based on string operations will execute at runtime.
-
Steve Jessop over 12 yearsSince you're using gcc, I think you can change what
__FILE__
contains by changing the filename you pass on the command line. So instead ofgcc /full/path/to/file.c
, trycd /full/path/to; gcc file.c; cd -;
. Of course there's a bit more to it than that if you're relying on gcc's current directory for the include path or output file location. Edit: the gcc docs suggest that it's the full path, not the input file name argument, but that's not what I'm seeing for gcc 4.5.3 on Cygwin. So you may as well try it on Linux and see. -
RBerteig over 11 yearsGCC 4.5.1 (built for arm-none-eabi specifically) uses the exact text of the file name on its command line. In my case it was the IDE's fault for invoking GCC with all file names fully qualified instead of putting the current directory somewhere sensible (location of the project file, perhaps?) or configurable and using relative paths from there. I suspect a lot of IDEs do that (especially on Windows) out of some sort of discomfort related to explaining where the "current" directory really is for a GUI app.
-
Chan Kim over 9 years@SteveJessop - hope you read this comment. I have a situation where I see
__FILE__
printed as../../../../../../../../rtems/c/src/lib/libbsp/sparc/leon2/../../shared/bootcard.c
and I want to know where gcc compiled the file such that this file is relatively located like it is shown. -
Prof. Falken almost 9 yearsThis question is not a dupe of the linked one. For one, the linked one is about C++, and the answers consequently delves into C++ macro esoterica. Second, there is nothing in OP's question which mandates a macro solution. It only solemnly points out a problem and asks an open ended question.
-
Daniel H about 6 yearsI know this ask is years old, but this will be possible to do at compile time in GCC 9 (I don't think that made it onto the 8 branch, but I could be wrong).
-
user3629249 over 5 yearsYou could use the
basename()
function to extract just the current file name for printing -
Andry almost 5 yearsWith at least the
C++11
you can do it at compile time instead of in the preprocessor: stackoverflow.com/questions/8487986/file-macro-shows-full-path/… -
Trevor Boyd Smith almost 5 yearsFYI here is a 4 line
c++11
solution using compile-timeconstexpr
tested with g++ version 4.8.5: stackoverflow.com/a/38237385/52074
-
-
Steve Jessop over 12 years@mahmood:
char file_copy[] = __FILE__; const char *filename = basename(__FILE__);
. The reason for the copy is that basename can modify the input string. You also have to watch out that the result pointer is only good untilbasename
is called again. This means it isn't thread-safe. -
Steve Jessop over 12 yearsthe
strrchr
answer could plausibly be computed at compile-time, although of course still not by the preprocessor. I don't know whether gcc actually does it, I haven't checked, but I'm pretty sure that it does computestrlen
of string literals at compile-time. -
Steve Jessop over 12 years@mahmood:
strrchr
returns a pointer to the/
(or a null pointer if it doesn't find a/
), so+1
means that the resulting pointer is one character further on. Without it, the result string would be/file.c
instead offile.c
. -
Sean over 12 years@Steve - maybe, but that's a big dependency on compiler specific behaviour.
-
Steve Jessop over 12 yearsI don't think it is a big dependency, because I very much doubt that this code is performance-critical. And if it is, move it out of the loop. In cases where this is a huge deal, because you absolutely need a string literal containing just the basename, you could perhaps compute the right string at build time by running some script over the source.
-
mahmood over 12 yearsmakes no difference. I used
__FILE__
and__BASE_FILE__
however they both show full path to file -
Prof. Falken over 12 years@SteveJessop, ah I forgot. True.
-
user1703401 over 12 years
/
is a valid path separator in Windows. -
ziu over 12 yearshow do you invoke the compiler ?
-
Steve Jessop over 12 years@Amigable: to be fair, I suspect that
basename
in fact will not modify the input string that results from__FILE__
, because the input string doesn't have a/
at the end and so there's no need for modification. So you might get away with it, but I figure the first time someone seesbasename
, they should see it with all the restrictions. -
ziu over 12 yearsThen I bet SCONS is calling gcc like this
gcc /absolute/path/to/file.c
. If you find a way to change this behavior (opening another question on SO, lol?), you do not need to modify the string at runtime -
Prof. Falken over 12 years@SteveJessop the BSd man page for basename() mention that legacy version of basename() takes a const char* and does not modify the string. The linux man page mentions nothing about const but mentions that it can return a part of the argument string. So, best be conservative dealing with basename().
-
Prof. Falken over 12 yearsBut I think all of path has to be with forward slashes.
-
RBerteig over 11 years
/
is a valid path separator in file names passed to CreateFile() and so forth. However, that doesn't always mean that you can use/
just anywhere in Windows since there is a tradition (inherited from CPM) of using/
as the argument lead in at the command prompt. But a quality tool would be careful to split file names at both slash and backslash characters to avoid any problems for folks that do manage to use/
. -
RBerteig over 11 years@AmigableClarkKant, no you can mix both separators in the same file name.
-
RBerteig over 11 yearsIt may not be performance critical, but it can easily be seen as privacy critical. There's no real good reason for revealing my per-customer organizational practices in strings frozen into a released EXE file. Worse, for applications created on behalf of a customer, those strings might reveal things my customer might prefer not to, such as not being the author of their own product. Since
__FILE__
is invoked implicitly byassert()
, this leak can occur without any other overt act. -
tchen over 11 years@RBerteig the basename of
__FILE__
itself may also reveal things the customer might prefer not to, so using__FILE__
anywhere at all -- whether it contains the full absolute pathname or just the basename -- has the same issues that you pointed out. In this situation all output will need to be scrutinized and a special API should be introduced for output to customers. The rest of the output should be dumped to /dev/NULL or stdout and stderr should be closed. :-) -
Czarek Tomczak over 11 years
__FILE__
may contain mixed separators, in my case I seec:\phpdesktop\phpdesktop-src\phpdesktop-msie\msie/internet_features.h
. Anyone have a macro for that? -
Keith Thompson almost 11 yearsDefining a macro named
FILE
is a really bad idea if you include<stdio.h>
. -
alexander golks almost 11 yearsgood to know. i just wanted to show Czarek my \\ / solution, so i don't bothered with naming schemes.
-
thegreendroid almost 11 yearsThis is a great idea! Much better than pulling in the standard string library to trim the filename, which isn't really an option on most embedded platforms.
-
JeremyP almost 11 yearsIf your platform supports it
char* fileName = basename(__FILE__);
It's definitely there in Linux and OS X, don't know about Windows though. -
ed9w2in6 over 10 yearsI am afraid then this doesn't work for the FILE referenced in header file.
-
nhed about 10 yearsAgree with @BaiyanHuang but not sure that the comment is clear.
__FILE__
is not a simple preprocessor symbol, it changes to the current file is often used for emitting the name of the current file (header or source module). This__FILENAME__
would only have the outermost source -
Marc Plano-Lesay over 9 yearsHow would you remove the file extension with this? Keeping only basename?
-
Patrick over 9 years@Kernald Try using
$(basename $(abspath $<))
instead of$(abspath $<)
-
Marc Plano-Lesay over 9 yearsWell, that was… unexpectedly simple! Thanks. It works like a charm.
-
Saher Ahwal over 9 yearsI tried that with '\\' for windows and it didn't work , can you please help me see what I am missing stackoverflow.com/questions/27493937/base-file-name-from-file
-
oohtj over 9 yearsGreat idea! That solved my file path too long in log file problem.
-
Colin D Bennett over 9 yearsThis answer's solution is not portable since it uses Bourne shell escapes. Better to use CMake to implement it in a clean and portable way. See define_file_basename_for_sources macro answer here.
-
firegurafiku about 9 years@thegreendroid: there is nothing wrong with using 'strrchr' even on an embedded platform as this function just seeks memory and pretty fast. Furthermore, it's also a part of of both C89 and C99.
-
Julian F. Weinert about 9 yearsThis does work indeed, but unfortunately you'll still find the full path in the executable.
-
Prof. Falken almost 9 years@SteveJessop, hehe, I only now after looking at your comment carefully, after four years, realize that
/
at the end of the string means basename may have a good reason to modify its argument. -
ɲeuroburɳ almost 9 yearsThis could be shortened to
strrchr("/" __FILE__, '/') + 1
. By prepending "/" to__FILE__
, strrchr is be guaranteed to find something, and thus the conditional ?: is no longer needed. -
Quuxplusone over 8 yearsThis answer is 100% wrong.
__BASE_FILE__
(as the docs say, albeit unclearly) produces the name of the file specified on the command line, e.g.test.c
or/tmp/test.c
depending on how you invoked the compiler. That's exactly the same thing as__FILE__
, except if you're inside a header file, in which case__FILE__
produces the name of the current file (e.g.foo.h
) whereas__BASE_FILE__
continues to producetest.c
. -
Oz. over 8 yearsAlso works great if you use
strstr(__FILE__, "my_source_directory")
. With that you can keep the paths within the project. -
Keith Thompson over 8 years
push_macro
andpop_macro
are non-standard. (gcc supports them for compatibility with Microsoft Windows compilers.) In any case, there's no point in pushing and popping the definition of__FILE__
; the restored value won't be used after the end of the source file anyway. A cleaner way to change the value of__FILE__
is#line __LINE__ "foobar.c"
-
Keith Thompson over 8 yearsAnd this causes an internal error in gcc's preprocessor. gcc.gnu.org/bugzilla/show_bug.cgi?id=69665
-
Andrew Henle over 7 years
char* fileName = basename(__FILE__);
is dangerous.basename()
can modify its argument string. Per POSIX: Thebasename()
function may modify the string pointed to bypath
That could result in a SEGV if the string__FILE__
expands to is read-only. Also see man7.org/linux/man-pages/man3/basename.3.html -
Digital Trauma about 7 yearsCool answer. You need to use at least
-O1
to use this to be compile-time. -
ctuffli almost 7 yearsThe GNU Make variant of this is CFLAGS += -D__FILENAME__=\"$(notdir $<)\"
-
RenatoUtsch over 6 yearsThere is a way to do it purely on compile time, you just need to be a little bit smart with the build configuration. See my answer for more details.
-
mrtumnus over 6 yearsIsn't this backwards? You want to find the last occurrence of '/', which means you should start with the
sizeof(s) > 2
check first. Also, this did not work at compile-time for me, at -Os. The full path strings were present in the output binary. -
mrtumnus over 6 years@firegurafiku On embedded platforms, code size is often more of a constraint than speed. If you have debug statements in each file, that can quickly balloon file-size up with full-path strings. I'm dealing with such a platform at the moment, and referencing
__FILE__
everywhere is blowing out of code-space. -
mrtumnus over 6 yearsYou can easily avoid a second call to strrchr with a local variable:
#define __FILENAME__ ({const char * pStr = strrchr(__FILE__, '/'); pStr ? pStr + 1 : __FILE__;})
-
alex about 6 yearsFor those who interested both strrchr and strstr work in compile time in this case, tested with gcc 6.3.0 -O2.
-
Technophile about 6 yearsMay want to check both '/' and '\', depending on platform.
-
lollo about 6 yearsDon't work with cmake + ninja: ninja: error: build.ninja:221: bad $-escape (literal $ must be written as $$)
-
Trevor Boyd Smith almost 6 years@AndrewSelivanov how did you verify that this is done at compile time?
-
alex almost 6 years@TrevorBoydSmith built with --save-temps and inspected generated code
-
Daniel almost 6 yearsI didn't understand this at first. I coded up examples and ran them against gcc and clang and they work. I also experiment with just appending various literal numeric values, and that behaves as I expected. Then it finally dawned on me.
__FILE__
is a pointer to an array of bytes. So adding a numeric literal is just pointer addition. Very clever @RenatoUtsch -
Pietro over 5 yearsA detail: the "__" pre- and postfix is a notation reserved to the implementation.
-
Pietro over 5 years@mrtumnus - I get the (pedantic) warning: "ISO C++ forbids braced-groups within expressions", pointing to the first parenthesis.
-
mrtumnus over 5 years@Pietro Yeah, the extra parens probably aren't necessary. They carried over from the OP's original statement.
-
elklepo over 5 yearsKeith Thompson it is great solution, thank You. The only problem is that it seems that this macro cuts
__LINE__
value by one. So__LINE__
written in linex
gest evaluated tox-1
. At least with gcc 5.4. -
Keith Thompson over 5 years@Klepak: You're right, and that's standard behavior. The directive "causes the implementation to behave as if the following sequence of source lines begins with a source line that has a line number as specified by the digit sequence". And it has to be a digit-sequence, so you can't use
#line __LINE__-1, "file.c"
. I'll update my answer. -
l33t over 5 yearsI wonder if the optimizer is able to optimize the calls to
strchr
andstrrchr
. Not to mention references to the__FILENAME__
macro. If not, this solution is 100% bloat. -
Lekensteyn over 5 yearsOption
-ffile-prefix-map
indeed implies both-fdebug-prefix-map
and-fmacro-prefix-map
options. See also the references at reproducible-builds.org/docs/build-path The GCC bug that tracks-fmacro-prefix-map
and-ffile-prefix-map
is gcc.gnu.org/bugzilla/show_bug.cgi?id=70268 -
Andry over 5 yearsIt works only if a source file is under cmake list directory. If a source file is outside then it will break, might with access outside of a literal string. So be careful with that.
-
Tarion about 5 yearsIt actually does not reduce the code size. I guess the whole path is still compiled into the binary, just the pointer is modified.
-
RenatoUtsch about 5 yearsBoth the
__FILE__
macro and the SOURCE_PATH_SIZE macros are constants known at compile time. I'd expect modern optimizing compilers to be able to detect that part of the string is not used and simply remove it from the binary. Anyway, I don't think these few bytes would make a significant difference in the binary size, so I wouldn't really care about that. -
Gregory Pakosz about 5 years⚠️when you follow this method, you break Visual Studio's (as of 2019) /MP parallel compilation. As it batches compilation and having per-file compiling options degrades to batches of size 1. See randomascii.wordpress.com/2014/03/22/…
-
mike.dld almost 5 yearsCMake 3.4+ documentation states that "This variable has no effect. The partially implemented effect it had in previous releases was removed in CMake 3.4." If it worked for you with 3.13, there's another reason for that.
-
Paul Stelian over 4 years@RenatoUtsch The project I'm working on has a change which just specifies the file name, but has the disadvantage of giving the C file name to the header too. The change was made in order to get reproducible builds. So with gcc with -O2, would the string be indeed optimized and the build made reproducible?
-
RenatoUtsch over 4 yearsI'd expect that, but you'll have to test it out for yourself.
-
Franklin Yu over 4 yearsHow would it be for other compilers like Clang, MSVC, or Intel C Compiler?
-
Roman over 4 yearsMan, that's beautiful and it works, thank you! No idea why this answer is so underrated.
-
chqrlie about 4 yearsWhy do you need
std::max<const char*>
instead of juststd::max
? -
chqrlie about 4 yearsThis does not work for contents coming from include files.
-
Levi.G about 4 yearscan you post some code? A common case is to set variables in local scope and use it in another.
-
chqrlie about 4 yearsFor example if you use
__FILE__
with your definition to produce a diagnostic in an inline function defined in a header file, the runtime diagnostic will report the name of the file passed to the compiler instead of the name of the include file, whereas the line number would refer to the include file. -
Levi.G almost 4 yearsyes, it designed to be that, for the most common usage is
#define LOG(fmt, args...) printf("%s " fmt, __FILE__, ##args)
. when using theLOG()
macro, you do not really want to seelog.h
in messages. after all, the__FILE__
macro is expanded in every C/Cpp file (compile unit) instead of the included files. -
twex over 3 yearsI got "Using
$<
in a non-suffix rule context is a GNUmake idiom" from a non-GNU make. I used$(notdir $file)
instead. -
Laurie Stearn over 3 years
-
Mark Rotteveel about 3 yearsPlease don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes.
-
icebp about 3 yearsIn addition to working only with the make generator, this will no longer work starting with CMake 3.20. An alternative that is still make-specific is:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__FILENAME__='\"$(notdir $(abspath $@))\"'")
-
Matt Eding about 3 yearsAt line 0 of a file, I just do:
#line 2 "name.cpp"
. Also as a side note it is nice to know that it does not contaminate other files that#include
it (at least on MSVC) -
psyched about 3 yearsYou can define one more helper macro
#define LEAF(FN) (&FN[UTILITY_CONST_EXPR_VALUE(get_file_name_offset(FN))])
and use it like thisprintf("%s\n", LEAF(__FILE__));
-
Hadatko almost 3 yearsNope this is not purely compile time solution.
-
Steven Lu almost 3 yearsI can confirm this answer does not work and broke my cmakelists, I got
c++: fatal error: no input files
. I can also confirm that the above linked helper from this link works great. Thanks @ColinDBennett -
Burak over 2 yearsGood solution except
std::max
requires<algorithm>
which I would rather not include in a header file. Another option can be checking platform by#ifdef _WIN32
since__FILE__
will have consistent separator characters. -
LongLT over 2 yearsDamn, amazing solution
-
automorphic over 2 yearsThis should be the answer. It doesn't require cmake, modifying the makefile, or runtime computation. And it can be used by a new FILENAME macro to make it intuitive:
#define __FILENAME__ (__FILE__ + get_file_name_offset(__FILE__))
-
automorphic over 2 yearsWorks, but leaves subdirs relative to dir with
CMakeLists.txt
. @Andry's solution leaves just the filename. -
Cem Polat about 2 yearsWithout the /FC option, FILE uses the relative path instead of the absolute path. Although it is shorter, it is not a "file name without path" solution.
-
Ramón Gil Moreno about 2 yearsThe fact that the question uses "/" as path separator points to a non-Windows compiler. I doubt @mahmood was using MSVC; some comments state he was using gcc but I could not locate where he said so.
-
Luc Bloom about 2 years@Burak then any other simple "max" function will suffice. #define PATH_SEPARATOR will also help of course.
-
ocroquette almost 2 yearsIf your compiler supports this, like any decently recent version of GCC or Clang does, you should use this instead of the other solutions. It is so much more elegant and lightweight.