Compiling source file path into executable

How can the entire filename of a source file be automatically stored into the compiled binary as a constant string? Automatically means “by the preprocessor or compiler” and not by me, because I will forget or screw it up.

programming environment: MS-VSC and PIO
framework: espidf

Right now I have these lines in my program:

 const char* filename = __FILE__;
 const char* date = __DATE__;
 const char* time = __TIME__;
 printf("Hello from %s\n", filename);
 printf("Compiled on %s at %s\n", date, time);

And that results in this output:
Hello from src/hello_world_main.c
Compiled on Jan 20 2024 at 23:42:36

Instead, I want the entire filename to print out, like this:
Hello from C:\Users\Jim\Documents\PlatformIO\Projects\espidf-hello-world\src\hello_world.c
Compiled on Jan 20 2024 at 23:42:36

HOW THIS CURRENTLY WORKS: The “FILE” preprocessor macro expands to the current source file’s name as a string literal. But this string is not the complete filename – it is the filename minus the higher-order path information that extends from the project folder up to the drive identifier. Since the project folder typically contains a folder named “src”, the result of “FILE” has this general form:
src/hello_world.c

MY QUESTION IS:
Is there a way to get the rest of the filename the FILE macro does not get? BTW, the BASE_FILE macro yields the same result as the FILE macro (I tried it).

I think this might be a PlatformIO “thing”. I created a test sketch for my Uno:

// On Arduino, this prints the full path.
// On PlatformIO, just src/main.cpp.
// Interesting!

void setup() {
  Serial.begin(9600);
  Serial.println(__FILE__);
}

void loop() {
}

When I ran it, the Arduino version produced:

/home/norman/Arduino/test__FILE__macro/test__FILE__macro.ino

However, the PlatformIO variant, same source code with an extra #include "Arduino.h", produced the same as you saw:

src/main.cpp

So it’s not just the espidf framework that is doing this.

I checked the docs , and there appears to be no mention of the __FILE__ macro, also, the C/C++ docs mention that __FILE__ is supposed to return the full path to the appropriate source file, so this could be a specific change, somehow, or a bug.

Sorry, not much help.

Cheers,
Norm.

The compiler might be reflecting the file argument in the compile command as __FILE__. For files in the src/ folder of the project, PlatformIO uses relative paths (and absolute ones for framework files), I think. A verbose build would reveal that.

Hi @maxgerhardt

as ever, you are correct. A verbose build gives:

Building in release mode
avr-g++ -o .pio/build/uno/src/main.cpp.o ..... src/main.cpp

which is indeed, the relative path.

Cheers,
Norm.

Also easily reproducable on just Linux + GCC.

max@XXXXXXXXX:/tmp$ cat test.c
#include <stdio.h>
int main() { printf("__FILE__ = %s\n", __FILE__); return 0; }
max@XXXXXXXXX:/tmp$ gcc -o test test.c && ./test
__FILE__ = test.c
max@XXXXXXXXX:/tmp$ gcc -o test $(pwd)/test.c && ./test
__FILE__ = /tmp/test.c

It’s all about what’s passed to GCC.

On the other hand, this may benefit then from a build_src_flags setting (only applied to source files) that uses this, something along the lines of -ffile-prefix-map=src=$PROJECT_SRC_DIR, so that src/ gets expanded to <project dir>/src/ instead.

Edit: This seems to promising, at least on the commandline. I’m sill giving GCC the relative path to the source file, but then remapping the src folder to the current directory/src.

max@XXXXXXXX:/tmp$ gcc -o test -ffile-prefix-map=src=$(pwd)/src src/test.c && ./test
__FILE__ = /tmp/src/test.c

Yeah that actually works for me.

[env:native]
platform = native
build_src_flags =
   -ffile-prefix-map=src=$PROJECT_SRC_DIR

With src/test.c as

#include <stdio.h>
int main() { printf("__FILE__ = %s\n", __FILE__); return 0; }

will print

$ pio run
Processing native (platform: native)
-------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 0 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Compiling .pio/build/native/src/test.o
Linking .pio/build/native/program
====================[SUCCESS] Took 0.52 seconds ====================
max@XXXXXXX:~/temp/remap$ ./.pio/build/native/program
__FILE__ = /home/max/temp/remap/src/test.c

Without it, it’s just src/test.c.

1 Like

I (OP) am not completely clear on this last post from maxgerhardt. It seems to indicate if I add these lines to my “platformio.ini” file, I will get a complete pathname when I use the FILE macro:

build_src_flags =
-ffile-prefix-map=src=$PROJECT_SRC_DIR

I added them but didn’t see a change, the result was still the local relative path and not the complete path.

I see you are using a Linux machine and I am using Win10, would that matter?

Lastly, I am unclear on these lines:
[env:native]
platform = native

Adding those lines to my project crashes the compile.

Thanks for any additional help you can offer this weak programmer.

I’ve only showcased it in a native project (that uses the system’s native compiler to produce an exectuable), not in an ESP-IDF environment. It may need this option in the CMake file, or in a different way.

Okay, thanks.

If you think up some other way to do this, I’m all ears. It seems some system variable somewhere must hold the whole path. Or maybe I can have PIO call up a PowerShell script that writes the path into a header file to be then read during compile?

Your thoughts?

I (OP) asked Bard for help, and got some good advice mixed with bad advice, then I took it all to ChatGPT and got things straightened out. The solution is to include this macro definition in the platformio.ini file:

build_flags = -DPROJECT_DIR="\"${PROJECT_DIR}\""

and then invoke the macro thusly in your program:

printf("Main File Path: %s%s\n", PROJECT_DIR, __FILE__);

The new macro and the existing macro FILE are appended to get the correct full path name. Thank you ChatGPT (man, that shit is amazing and will change the world fast).

Also, why does this web site take my input with double underscores (remove the dashes below):

_-_-FILE-_-_ 

and turn it into a bold-faced entry that has no underscores?:

__FILE__

Kind of annoying…

Oh crap, that last post didn’t come out looking the way I had expected, it seems that the underscore character itself is banned from this site. I am now seeing that all of my underscores have been removed.

No, it’s just about formatting options. If you enclose something in backticks (the ` charcater), it will not transform double-underscore to bold formatting.

This is without backticks

__This is with backticks__

Nice workaround, placing the project dir as a second variable. Still weird though that it couldn’t be solved by modying __FILE__ alone.

Thanks for explaining the deal with the underscore. And thanks (I guess) for editing my post, although now it makes less sense, since you fixed the formatting where I was complaining about the formatting.

Also, I left a slash out of the print statement to properly separate the two macro results; here is the correct print statement for those that might follow down this road:
printf("Main File Path: %s/%s\n", PROJECT_DIR, __FILE__);

Lastly, don’t congratulate me, congratulate ChatGPT. It’s the real brains behind this effort.

1 Like