One of the issues I have had in porting some stuff from Solaris to Linux is that the Solaris compiler expands the macro __FILE__
during preprocessing to the file name (e.g. MyFile.cpp) whereas gcc on Linux expandeds out to the full path (e.g. /home/user/MyFile.cpp). This can be reasonably easily resolved using basename() but....if you're using it a lot, then all those calls to basename() have got to add up, right?
Here's the question. Is there a way using templates and static metaprogramming, to run basename() or similar at compile time? Since __FILE__
is constant and known at compile time this might make it easier. What do you think? Can it be done?
you might want to try the
__BASE_FILE__
macro. This page describes a lot of macros which gcc supports.Another possible approach when using CMake is to add a custom preprocessor definition that directly uses
make
's automatic variables (at the cost of some arguably ugly escaping):Or, if you're using CMake >= 2.6.0:
(Otherwise CMake will over-escape things.)
Here, we take advantage of the fact
make
substitutes$(<F)
with the source file name without leading components and this should show up as-D__FILENAME__=\"MyFile.cpp\"
in the executed compiler command.(While
make
's documentation recommends using$(notdir path $<)
instead, not having whitespace in the added definition seems to please CMake better.)You can then use
__FILENAME__
in your source code like you'd use__FILE__
. For compatibility purposes you may want to add a safe fallback:There is currently no way of doing full string processing at compile time (the maximum we can work with in templates are the weird four-character-literals).
Why not simply save the processed name statically, e.g.:
This way you are only doing the work once per file. Of course you can also wrap this into a macro etc.
In projects using CMake to drive the build process, you can use a macro like this to implement a portable version that works on any compiler or platform. Though personally I pity you if you must use something other than gcc... :)
Then to use the macro, just call it with the name of the CMake target:
I like @Chetan Reddy's answer, which suggests using
static_assert()
in a statement expression to force a compile time call to function finding the last slash, thus avoiding runtime overhead.However, statement expressions are a non-standard extension and are not universally supported. For instance, I was unable to compile the code from that answer under Visual Studio 2017 (MSVC++ 14.1, I believe).
Instead, why not use a template with integer parameter, such as:
Having defined such a template, we can use it with
basename_index()
function from @Chetan Reddy's answer:This ensures that
basename_index(__FILE__)
will in fact be called at compile time, since that's when the template argument must be known.With this, the complete code for, let's call it
JUST_FILENAME
, macro, evaluating to just the filename component of__FILE__
would look like this:I've stolen
basename_index()
almost verbatim from the previously mentioned answer, except I added a check for Windows-specific backslash separator.For Objective-C the following macro provides a CString which can replace the
__FILE__
macro, but omitting the initial path components.That is to say it converts:
/path/to/source/sourcefile.m
into:sourcefile.m
It works by taking the ouptput of the
__FILE__
macro (which is a C-formatted, null terminated string), converting it to an Objective-C string object, then stripping out the initial path components and finally converting it back into a C formatted string.This is useful to get logging format which is more readable, replacing, (for example) a logging macro like this:
with:
It does contain some runtime elements, and in that sense does not fully comply with the question, but it is probably appropriate for most circumstances.