Getting base name of the source file at compile time - c++

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.

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 $<`\"" -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 $<`\"" -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.

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__.

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}\"")

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.

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
}

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.

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'.

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.

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.

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.

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.

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 :)

Related

Original file name of precompiled header

Is it possible to extract original filename (filepath) and compilation language from precompiled header? As I understand it's possible for Clang using llvm-bcanalyzer (LLVM bit code analyzer). So, could anybody help me with GCC?
For clang you can easily extract original PCH filename just parsing preprocessor output.
In out example header/header.h is original header and pch/pch.h.gch is precompiled header.
For example the follow command: clang -E -include pch/pch.h main.cpp returns result where we can find original PCH filename:
…
# 1 "/Users/user/pch_example/header/header.h" 1
…
# 1 "main.cpp" 2
int main() {return 42;}
Unfortunately parsing preprocessor output doesn’t help us with GCC, even if you use it with -fpch-preprocess option. So the only one way I found is compiling PCH with enabled dependency-tracking flag like -MD (or -MMD).
For example we can call the follow command: gcc-6 -MMD -x c++-header header/header.h -o pch/pch.h.pch. In this case GCC additionally generates dependency-file pch/pch.h.d, which contains path to the original PCH filename.

Inserting terminal output into source file before compilation

I've got a C++ project that happens to be stored in a Bazaar repo. This project also uses a #define'd string to display its version number. Someone just asked if we could simply tie this displayed version number to the bzr repo revision number.
So, in pseudo-C, pseudo-bash, something like:
#define VERSION_STRING "revision $(bzr revno)"
//...
cout << "Starting " << VERSION_STRING;
Or so. How might you answer this question? Does the makefile run a script that inserts the output of that command into the appropriate source file? Is there a macro solution for this? Etc?
I'm open to any and all clever solutions, as I'm drawing an educated blank on this one. =D
The compiler will have a flag to define a macro value externally. For g++ and clang++ this is -D:
g++ -DVERSION_STRING="revision $(bzr revno)" file.cpp -c -o file.o
To get that in the file as a string, you can either add extra quotes into the definition:
g++ -DVERSION_STRING="\"revision $(bzr revno)"\" file.cpp -c -o file.o
or you need to know how to stringify that value inside the file, which takes a little magic:
#define STRINGIFY_HELPER(X) #X
#define STRINGIFY(X) STRINGIFY_HELPER(X)
Then you could also have a default value. I'd recommend have a different variable set by the compiler to the one you use internally, it helps keep track:
#include <iostream>
#define STRINGIFY_HELPER(X) #X
#define STRINGIFY(X) STRINGIFY_HELPER(X)
#ifdef VERSION
#define VERSION_STRING STRINGIFY(VERSION)
#else
#define VERSION_STRING "0.0.0"
#endif
int main()
{
std::cout << VERSION_STRING << '\n';
}
results in:
$ g++ -DVERSION="1.0.0" SO.cpp
$ ./a.out
1.0.0
$ g++ SO.cpp
$ ./a.out
0.0.0
Note, $(bzr revno) is the syntax to run bzr revno and substitute its output in a shell (bash syntax, probably the same in most others). From within a makefile, as musasabi pointed out, the syntax is slightly different: $(shell bzr revno),

Instruct compiler to ignore header prefix found in a #include

[As Cornstalks explained below, I'm trying to strip a header prefix that's used in an #include. So it appears this question is not a duplicate of How to make g++ search for header files in a specific directory?]
I'm making some changes to a library. I have the library locally, so its not installed in its customary system location.
I have a test source file and its sided-by-side with the library. The test file has a bunch of includes like:
#include <foo/libfoo.h>
And it also has a bunch of customary includes, like:
#include <iostream>
I'm trying to compile the test file using:
$ g++ ecies-test.c++ -I. -o ecies-test.exe ./libcryptopp.a
And (the space between -iquote . does not appear to make a difference):
$ g++ ecies-test.c++ -I. -iquote . -o ecies-test.exe ./libcryptopp.a
The problem I am having is I don't know how to tell g++ that <foo/libfoo.h> means "./libfoo.h". Effectively, I'm trying to strip the prefix used to include the header. I've looked in the manual under 2.3 Search Path, but it does not really discuss this scenario.
I have about 60 extra test files I use for the library. And each has 10 or 20 includes like this. So I can't go through and change #include <foo/libfoo.h> to #include "./libfoo.h" in 500 or 600 places.
I tried #rici's work around by creating the fictitious directory structure, but it broke GDB debugging. GDB cannot find symbols for class members, so I can't set breakpoints to debug the code I am attempting to modify.
How do I tell the compiler to look in PWD for system includes?
Below is a typical error. ECIES_FIPS is in my local copy of the library.
$ g++ -DNDEBUG=1 -g3 -Os -Wall -Wextra -I. -iquote . ecies-test.c++ -o ecies-test.exe ./libcryptopp.a
ecies-test.c++:29:17: error: no member named 'ECIES_FIPS' in namespace
'CryptoPP'
using CryptoPP::ECIES_FIPS;
~~~~~~~~~~^
ecies-test.c++:44:5: error: use of undeclared identifier 'ECIES_FIPS'
ECIES_FIPS<ECP>::Decryptor decryptor(prng, ASN1::secp256r1());
^
ecies-test.c++:44:16: error: 'ECP' does not refer to a value
ECIES_FIPS<ECP>::Decryptor decryptor(prng, ASN1::secp256r1());
^
/usr/local/include/cryptopp/ecp.h:30:20: note: declared here
class CRYPTOPP_DLL ECP : public AbstractGroup<ECPPoint>
...
In case it matters:
$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin12.6.0
Thread model: posix
There is no option which tells gcc to ignore directory prefixes in include paths. If your program contains #include <foo/header.h>, there must be some path_prefix in the include list such that path_prefix/foo/header.h resolves to the desired file.
While you cannot configure gcc to ignore the foo, you can certainly modify the filesystem as you please. All you need is that there be somewhere a directory foo which maps onto the directory where the header files are stored. Then you can add the parent of that directory to the search path.
For example:
mkdir /tmp/fake
ln -s /path/to/directory/containing/header /tmp/fake/foo
gcc -I /tmp/fake ... # Ta-daa!
Using the -I option to add the current folder as an include directory, you could create a folder called "foo" in the current directory and put your libfoo.h file inside.
Obviously, this doesn't strip the "foo" prefix in your #include, but it is a workaround.
I have about 60 extra test files I use for the library. And each has 10 or 20 includes like this. So I can't go through and change #include to #include "./libfoo.h" in 500 or 600 places.
If the above criteria is just a matter of convenience, then a tool like sed can be used to do all the work. Something like
$ sed -i 's/\(^\s*#include\s*[<"]\)foo\/\([^>"]*[>"]\s*$\)/\1\2\t\/\/ This line was replaced/' *
will replace all the occurrences of #include <foo/file.h> with #include <file.h> (you might have to adjust it slightly, I'm on a Windows machine at the moment and can't test it). This will work if all the files are in the PWD. If there is a more complex file structure, then it can be used in conjunction with grep and xargs.
NOTE: Make sure that the svn directories are ignored when using.

Linking pcap library in OpenWrt Makefile

My simple pcap test app compiles and runs fine using: gcc main.c -o test -lpcap
but when using the OpenWrt SDK: make package/myapp/compile V=s
I get the error message:
main.c:(.text.startup+0x24): undefined reference to `pcap_lookupdev'
collect2: error: ld returned 1 exit status
From what I've read, I need to add the line:
LDFLAGS = -lpcap
to one of the Makefiles, but I'm not sure where it should go. What confuses me is that I can use the pcap constant PCAP_ERRBUF_SIZE, can anyone tell me why I can access this, but not pcap functions?
main.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pcap.h>
int main(int argc, char **argv)
{
printf("Hello PCAP!\n");
char *dev, errbuf[PCAP_ERRBUF_SIZE];
printf("%d\n\n", PCAP_ERRBUF_SIZE);
// Make works without this part
dev = pcap_lookupdev(errbuf);
printf("Device: %s\n", dev);
return 0;
}
Makefile
include $(TOPDIR)/rules.mk
PKG_NAME:=myapp
PKG_VERSION:=0.1
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/myapp
SECTION:=utils
CATEGORY:=Utilities
DEPENDS:=+libpcap
TITLE:=Intro to PCAP for OpenWrt
endef
define Package/myapp/description
Outputs device name
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
LDFLAGS=-lpcap
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/myapp/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/myapp $(1)/usr/bin/
$(INSTALL_DIR) $(1)/etc/init.d/
$(INSTALL_BIN) files/myapp.init $(1)/etc/init.d/myapp
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) files/myapp.config $(1)/etc/config/myapp
endef
$(eval $(call BuildPackage,myapp))
Constants and the like used in code are resolved during compilation and come from header files. So the pcap.h header file is found (apparently by default).
I would have expected DEPENDS:=+libpcap to handle the linking for you (I'm not sure why else it would be necessary, but ). (Is that the correct format for that line?)
You actually want LDLIBS not LDFLAGS for this (assuming you are using the built-in rules and variables). See 10.3 Implicit Variables for what they each mean.
Without knowing what the rest of that make framework is doing though I can't say whether either LDLIBS or LDFLAGS will actually work though. That framework might have its own variable for this.
I figured out how to compile native C code for OpenWrt (runnin on a mips processor inside of a TP-LINK router) that depends on other libs (also in C) and generate .ipk s for both (the library and the executable) via a single makecommand. The library itself needed to be fetched from
I documented the efforts on my blog here
Basically there are three Makefiles involved - one for the library which tells the build system where to get the tarball from. The other two would be for your native C code. Consider my case for example: I want compile my code (mfm383c) that makes uses of a library (libmodbus):
/package/libmodbus/Makefile - this specifies URL from where to get the tar ball of the sources and the system will fetch the sources and compile it for you. It also tells the system where to place the .so file when the .ipk is installed on the OpenWrt target
/package/mfm383c/src/Makefile - this Makefile take care of telling the build system how to compile the .c and .h and also passes the dependency flag to the linker (-lmodbus)
/package/mfm383c/Makefile - This Makefile is the most important of the three - it tells the build system to build the libmodbus library before building mfm383c to ensure that the dependencies are met. We also need to make sure that the modbus.h file included in mfm383c.c can be found in the right place. The most notable section of this file being the following line at the end:
$(eval $(call BuildPackage,mfm383c,+libmodbus))
and the part about the code being dependent on another package in the define section:
DEPENDS:=+libmodbus
All three makefile are posted on my blog - they were too big to post here

How to force Eclipse to use g++ instead of gcc?

I already asked how to call a C++ constructor from a C file in How to call a C++ constructor from a C-File. Now when I successfully apply these methods suggested there, I receive an error
fatal error: string: No such file or directory compilation terminated
this error message points to the line: #include <string> in a header of a .cpp file.
I already found out that <string> is used by c++/g++ and <string.h> by c/gcc. Well the problem got clearer, when I checked the console output and there I can see, the (.cpp) file with the error was called by the gcc, which actually expects the <string.h> but that's not my intention - I need to compile it with the g++.
Now my question is: Can I force Eclipse to use a specific compiler? Here, for example just g++ (I heared it is capable of C-code too.) - Or even better, is there a way to chose the compiler for each directory in the workspace ?
Thanks for your advises
Answer respecting the wish of being able to specify the compiler for every subfolder:
What you are searching is probably a makefile project. That allows you to specify the toolchain, being for example the preprocessor, compiler and linker. g++ is an example for such a toolchain, as much as clang++ would be.
You can generate such a project in eclipse, writing the makefiles by hand, or use some build environment, such as CMake, which I would recommend for better portable code.
Both solutions would allow you to specify the compiler, as well as the compile flags, for every single directory of your project, if you wished so.
Writing a makefile for your existing C/C++ project can be achieved by completing the following steps:
in the folder where your source file is, right click and create a new file. New > File
name it makefile and click Finish
The new makefile should pop up in the editor and can be filled like follows:
makefile:
all: executable_name
clean:
-rm main.o executable_name[.exe on windows] executable_name
executable_name: main.o
g++ -g -o executable_name main.o
main.o: main.cpp
g++ -c -g main.cpp
Change Project's Setting can force eclipse to compile using g++: