Inserting terminal output into source file before compilation - c++

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

Related

MACRO definition both for a number and a string [duplicate]

I'd like to pass the name of an include file as a compiler argument so that I can modify a large number of configuration parameters. However, my C++ build is via a makefile like process that removes quotes from arguments passed to the compiler and pre-processor. I was hoping to do something equivalent to
#ifndef FILE_ARG
// defaults
#else
#include "FILE_ARG"
#endif
with my command line including -DFILE_ARG=foo.h. This of course doesn't work since the preprocessor doesn't translate FILE_ARG.
I've tried
#define QUOTE(x) #x
#include QUOTE(FILE_ARG)
which doesn't work for the same reason.
For scripting reasons, I'd rather do this on the command line than go in and edit an include line in the appropriate routine. Is there any way?
For adding quotes you need this trick:
#define Q(x) #x
#define QUOTE(x) Q(x)
#ifdef FILE_ARG
#include QUOTE(FILE_ARG)
#endif
You can do
#ifdef FILE_ARG
#include FILE_ARG
#endif
On the command line
$ gcc -DFILE_ARG="\"foo.h\"" ...
should do the trick.
You can also try the -include switch.
gcc manual:
-include file
Process file as if #include "file" appeared as the first line of the primary source file. However, the first directory searched for file is
the preprocessor's working directory instead of the directory
containing the main source file. If not found there, it is searched
for in the remainder of the #include "..." search chain as normal.
If multiple -include options are given, the files are included in the order they appear on the command line.*
Works for me. Maybe you forgot to quote correctly in your Makefile?
$ cat example.c
#include FILE_ARG
$ cat test.h
#define SOMETHING
$ gcc -Wall -Wextra -W -DFILE_ARG=\"test.h\" -c example.c
$
EDIT:
The reason you might not be able to get quoting to work is because the preprocessor works in phases. Additionally I used "gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2", results may vary between compilers.

How to compile C++ for the same preprocesor variable

In main.c ++ I have several preprocessor variables defined.
#ifndef FIRST
#define FIRST "./path/for/output/files"
#endif
#ifndef SECOND
#define SECOND 0.0125
#endif
#ifndef THIRD
#define THIRD "./input_file.mesh"
#endif
I have to compile this .cpp by varying the three preprocessor macros. To do this, I tried to make a bash file with a for loop to vary the values that these macros took, that is:
#!/bin/bash
for i in *.mesh
do
g++ -Ofast -fopenmp main.cpp eig3.cpp vema.cpp -o main10 -DFIRST=\"\.\/$i\" -DSECOND=0.0125 -DTHIRD=\'\"\.\/$i\"\'
done
This loop constantly reports error, it does not recognize the input file and neither does the output folder. I imagine that I am making many mistakes, I am new to C ++ and I am still a bit lost.
I would like to know if there is any possibility to compile this code with many different values for each parameter. Thank you!
If you really don't want to change the program all that much, compile it once as follows:
g++ -Ofast -fopenmp main.cpp eig3.cpp vema.cpp -o main10 -DFIRST='getenv("OUTPUT")' -DSECOND=0.0125 -DTHIRD='getenv("INPUT")'
And call it as follows:
for i in *.mesh; do
INPUT=./$i OUTPUT=./path/for/output/files ./main10
done

Adding quotes to argument in C++ preprocessor

I'd like to pass the name of an include file as a compiler argument so that I can modify a large number of configuration parameters. However, my C++ build is via a makefile like process that removes quotes from arguments passed to the compiler and pre-processor. I was hoping to do something equivalent to
#ifndef FILE_ARG
// defaults
#else
#include "FILE_ARG"
#endif
with my command line including -DFILE_ARG=foo.h. This of course doesn't work since the preprocessor doesn't translate FILE_ARG.
I've tried
#define QUOTE(x) #x
#include QUOTE(FILE_ARG)
which doesn't work for the same reason.
For scripting reasons, I'd rather do this on the command line than go in and edit an include line in the appropriate routine. Is there any way?
For adding quotes you need this trick:
#define Q(x) #x
#define QUOTE(x) Q(x)
#ifdef FILE_ARG
#include QUOTE(FILE_ARG)
#endif
You can do
#ifdef FILE_ARG
#include FILE_ARG
#endif
On the command line
$ gcc -DFILE_ARG="\"foo.h\"" ...
should do the trick.
You can also try the -include switch.
gcc manual:
-include file
Process file as if #include "file" appeared as the first line of the primary source file. However, the first directory searched for file is
the preprocessor's working directory instead of the directory
containing the main source file. If not found there, it is searched
for in the remainder of the #include "..." search chain as normal.
If multiple -include options are given, the files are included in the order they appear on the command line.*
Works for me. Maybe you forgot to quote correctly in your Makefile?
$ cat example.c
#include FILE_ARG
$ cat test.h
#define SOMETHING
$ gcc -Wall -Wextra -W -DFILE_ARG=\"test.h\" -c example.c
$
EDIT:
The reason you might not be able to get quoting to work is because the preprocessor works in phases. Additionally I used "gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2", results may vary between compilers.

C++ preprocessor

I'd rewritten a simple C++ program using unix as a variable name. But the program compilation failed.
#include <iostream>
int main() {
int unix = 1;
return 0;
}
After searching a lot on the internet I got to this website which helped me by saying that unix is predefined macro equal to 1.
I want to know list of all such predefined macros.
You can list all the predefined macros by using the GNU preprocessor cpp as:
cpp -dM file.cpp
Also note that macros such as unix, linux are non standard and you can disable them by using the -ansi compilation flag as:
g++ -ansi file.cpp
And you can use the -ansi flag with cpp also to get the list of all standard predefined macros:
cpp -dM -ansi file.cpp
touch mysymdef.h; g++ -dM mysymdef.h
It will generate a file mysymdef.h.gch which will have all predefined symbols/macros for you system. File is binary but with some edit it will work out.
for details refer to
http://gcc.gnu.org/onlinedocs/cpp/Invocation.html#Invocation
http://gcc.gnu.org/onlinedocs/cpp/System_002dspecific-Predefined-Macros.html
I don't think there's such a list as you are asking for that's available across every potential platform. You may want to see Pre-defined macros for more information. The 'gcc -dM' will work on Linux.
$ uname
Linux
$ cpp -dM <<<'' | grep unix
#define __unix__ 1
#define __unix 1
#define unix 1

Getting base name of the source file at compile time

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