9

I am (was) using the __FILE__ and __LINE__ macros for printing diagnostic messages out of my code. This works quite well when you use GCC with make, the file is as short as you specified it on the command line. I recently switched to using CodeLite which uses fully qualified file names (at least under windows) when building. Suddenly my diagnostic output is almost not readable.

It there a way to get only the file component of the filename in the preprocessor? I can live with a non portable GCC specific solution. (I will fallback to plain __FILE__ other cases.)

Sure I can pass the contents of __FILE__ through a function and extract only the file component, but string operations was not what I had in mind for diagnostic messages that should not change runtime behavior...

NOTE: I use the filename the way GNU uses it. A Path is collection of filenames and a filename is either a relative or absolute identifier of a file. A filename can be made up of a directory component and file component.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
rioki
  • 5,988
  • 5
  • 32
  • 55
  • Diagnostics does change runtime behavior (otherwise there would be no diagnostics), and whether you call one extra function makes little difference, since the output itself is calling library functions to do the output anyway. – eudoxos Sep 13 '11 at 08:21
  • Printing a diagnostic message usually involves, in addition to dozens of string operations, some not-so-benign file I/O actions. For some reason nobody seems to be worried about this. Why worry about adding a call to another side-effect-free function that only affects diagnostic messages? – n. m. could be an AI Sep 13 '11 at 08:44
  • You both are right, adding diagnostics is not effect free. I implemented it that way, I let it pass through a function. I was more wondering it something like it exists. It sure is not standard, but finding documentation about this is not perfect. (Even the gcc manual does not outline every predefined macro.) – rioki Sep 19 '11 at 11:52
  • About I/O; not every diagnostic is bound to print to STDOUT/STDERR or a file. Ever heard of a ring buffer that is output when the application crashes? For example GNU Nana implements that. In contrast to file I/O that has "almost" no impact on performance. – rioki Sep 19 '11 at 11:55
  • FYI there's also c++ constexpr solution: https://stackoverflow.com/a/38237385/52074 – Trevor Boyd Smith May 14 '19 at 12:43

4 Answers4

9

If you are using GNU Make then you can simply pass -D BASE_FILE_NAME=\"$*.c\" in on the preprocessing stage of compilation (if you're doing them separately, or at compilation if in a single stage, which is the norm).

This depends upon the way you have your file names determined. Mine come from a list of plain file names and are prefixed with directories using functions in the makefile at a later stage.

IE, this works well for me, but your mileage may vary! :-)

A simplified version of my make "code" :

CLASSES = main.c init.c

PREPROCESSED = $(patsubst %.c,$(PPCDIR)/%.pp.c,$(CLASSES))

$(PREPROCESSED): $(PPCDIR)/%.pp.c: %.c $(ALLH) 
    $(GCC) $(GCCOPTS) -D BASE_FILE_NAME=\"$*\" -E $< > $@

The simply use BASE_FILE_NAME in your code as you like :-)

FredCooke
  • 177
  • 2
  • 4
  • Unfortunately I am working with CodeLite, that generates the makefiles for me. Using CodeLite is great, until you want to do something that falls out of the norm. Still nice ideea, +1 – rioki Dec 09 '11 at 10:35
  • The same idea can be used in Visual Studio. In Visual Studio 2008: right click on project file(.vcproj) -> Properties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions. Add __BASE_FILE__=\"$(InputFileName)\". You can use __BASE_FILE__ instead of __FILE__ in your source files. – user720594 Nov 28 '12 at 17:13
4

In reply to FredCooke above, you can exchange this line:

-D BASE_FILE_NAME=\"$*.c\"

With:

-D BASE_FILE_NAME=\"$(<F)\"

This will give you proper file name expansion, for .cpp as well.

user2745509
  • 411
  • 4
  • 5
Ying
  • 361
  • 4
  • 8
4

There is no known preprocessor macro that provides the functionality. Passing __FILE__ through a function seams like the only sensible option.

rioki
  • 5,988
  • 5
  • 32
  • 55
  • For gcc there is [\_\_BASE_FILE\_\_](https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html). – fret Jun 15 '17 at 02:42
  • 2
    @fret : for me, `__BASE_FILE__` outputs the same as `__FILE__`. If you read the documentation to which you linked, it provides the name (not necessarily basename) of the file with the `main` function (not the current file, even). – JellicleCat Nov 03 '17 at 20:30
  • 1
    if you can use c++ then there is a constexpr solution: https://stackoverflow.com/a/38237385/52074 – Trevor Boyd Smith May 14 '19 at 12:48
  • @TrevorBoydSmith good point. But, to be honest, if you look at the date, this question was asked one month after the C++11 was released and not widely adopted yet. – rioki May 15 '19 at 10:53
2

As has already been mentioned in other answers, the only portable way to do this is by passing in a define from the compiler, there are however compiler spesific extensions:

  • Clang: __FILE_NAME__
  • GCC: __BASE_FILE__
ideasman42
  • 42,413
  • 44
  • 197
  • 320