Can you use environment variables in C/C++ include directives? - c++

Say I have a folder layout as such:
.
+-- Project
+-- src
+-- foo.h
+-- foo.cpp
+-- test
+-- test_foo.c
And test_foo.c looks as such:
#include "../src/foo.h"
#include <stdio.h>
#include <assert.h>
int main() {
assert(foo() == true);
printf("Test complete");
return 0;
}
Is there a way to replace the line #include "../src/foo.h" with a variable that points to the source directory? For instance, say in my environment I have a have a variable:
PROJECT_SRC="./Project/src/"
And then I could have the include directive as such:
#include "PROJECT_SRC/foo.h"
This would be nice as I could then have a bash script that exports all the paths I need for a certain project. Also, if the file is included in different test and build files I would have to set up the relative path for each (although not much work) which would be less robust than one absolute path.
An alternative might be a tool like CMake that can do this. Or is this considered bad practice?

Weeelll...it is possible, sort of, but it's not pretty, and it has some pitfalls. It is usually better to add the include path in the build system, such as (assuming plain make):
# C PreProcessor flags. This variable is used by make's implicit rules for
# everything preprocessor-related.
CPPFLAGS += -I$(PROJECT_PATH)
and #include the headers without the path in the source file. This will make make call the compiler with -Iyour/project/path, which will make the compiler look for headers in your/project/path. That is to say, in the Makefile you can have
PROJECT_PATH = foo/bar
CPPFLAGS = -I$(PROJECT_PATH)
and in the sources
#include "foobar.h"
to have the effect of #include "foo/bar/foobar.h".
...also, did I see you try to #include source files instead of headers? Do not go down that road; down that road madness lies. Compile the source files separately and link them together the usual way unless you have a really good reason to do otherwise.
So, I don 't see a reason why you would want to reference the project path directly in #include directives in the code; the only change on the build system side is only that you have to pass -DPROJECT_PATH=foo/bar/ instead of -IPROJECT_PATH=foo/bar/ and that the construct is more brittle than the mechanisms that are actually designed for this sort of stuff. But if you really want to do it, then here is how:
The first problem you run into is that
#include "foo/bar/" "baz.h" // no dice.
is ill-formed, so the easy way is out. We have to try preprocessor magic, and it works like this:
#define HEADER_STRING(s) #s
#define HEADER_I(path, name) HEADER_STRING(path ## name)
#define HEADER(path, name) HEADER_I(path, name)
// v-- important: no spaces allowed here!
#include HEADER(PROJECT_PATH,foobar.h)
Perhaps start from the bottom up:
#define HEADER_STRING(s) #s
makes a string from its argument. That is to say, HEADER_STRING(foo/bar/baz.h) expands to "foo/bar/baz.h". Notably, macro parameters are not expanded, so HEADER_STRING(PROJECT_PATH) will expand to "PROJECT_PATH" even if a macro PROJECT_PATH is defined. This is one of the most common problems you run into when you try to do anything complicated with the preprocessor, and the solution is to add another layer in which the parameters can be expanded:
#define HEADER_STRING_I(s) #s
#define HEADER_STRING(s) HEADER_STRING_I(s)
...we do not need this for HEADER_STRING, but it is used in HEADER, so keep the trick in mind. I'm afraid the precise preprocessor substitution rules are somewhat arcane, and explaining them in detail goes beyond the scope of a SO answer. In a nutshell, macros are expanded in layers, and when macros don't get expanded, the trick is usually to give them a place to expand, i.e., to add another layer.
HEADER_I then,
#define HEADER_I(path, name) HEADER_STRING(path ## name)
tapes its arguments together and passes them to HEADER_STRING. HEADER_I(foo,bar) expands to HEADER_STRING(foobar). Because of the problem I mentioned above, HEADER_I(PROJECT_PATH,foobar.h) expands to HEADER_STRING(PROJECT_PATHfoobar.h), which in turn expands to "PROJECT_PATHfoobar.h", so we need another layer for the expansion of PROJECT_PATH:
#define HEADER(path, name) HEADER_I(path, name)
This just adds the place for the path and name parameters to be expanded. Finally, with PROJECT_PATH #defined to foo/bar/, HEADER(PROJECT_PATH,foobar.h) expands to "foo/bar/foobar.h", and then we can say
#include HEADER(PROJECT_PATH,foobar.h)
to #include "foo/bar/foobar.h". PROJECT_PATH can then be set in the makefile and passed with -DPROJECT_PATH=$(some_make_variable).
The last pitfall is that you must take care to not let any spaces slip between the tokens.
#include HEADER(PROJECT_PATH,foobar.h)
ultimately expands to "foo/bar/ foobar.h" (note the space), which does not work.

Related

Using a macro to define an include file

To make a long story short, I'm working on some code that needs different header files based on various configuration options. I could do something like this:
#if OPTION == A
#include "relative/path/to/file/a.hpp"
#elseif OPTION == B
#include "relative/path/to/file/b.hpp"
#elseif OPTION = ...
...
#endif
This would work, but it seems like a really ugly solution for what could potentially be more than a handful files. I could also simply include all the various header files, but that, too, seems like a bit of an ugly solution, and it could pose problems in the future if files (for some horrible reason) start redefining the same objects. The idea I had was that something like the following would be nice, particularly in the context of how the rest of the code is written:
#define QUOTE(str) #str
#define STRINGIFY(A,B) QUOTE(A##B)
...
#include STRINGIFY(relative/path/to/option/,OPTION)
The problem with this seems to be two-fold:
The OPTION definition doesn't expand properly inside STRINGIFY.
If there are any forward slashes in the path name, STRINGIFY fails altogether, with g++ giving me an error along the lines of the following:
error: pasting "/" and "OPTION" does not give a valid preprocessing token
I can't seem to find any real information on why / is a bad character for the C++ preprocessor, just a few articles saying that you should just put "/" in and rely on automatic C++ string concatenation (which doesn't work in an #include statement). I'm willing to consider design alternatives if I'm just trying to do something really dumb, but I'd also like to figure out why this isn't working.
EDIT: I should make the clarification that I'm working on a codebase originally designed by a group of scientists. Reasonable coding conventions and typical expectations for how a code gets used go completely out the window. This code will probably be modified at least as many times as it gets used, often by people who have spent their entire careers writing Fortran 77 and think object-oriented programming is some new-fangled invention that just makes your code harder to understand.
When writing macros it is essential to look at the output after preprocessing. With gcc thats the -E option.
To include different files I would rely on your build tools rather than macro voodoo. For example when the code is
include option
Then gcc -E -option=\"foo.h\" yields
include "foo.h"
Note that I ommitted the # here, otherwise preprocessing would fail due to not finding "foo.h".
I wanted to do something similar, searched around and found this post, and after trying few things I think I can help you.
So, your approach:
#define QUOTE(str) #str
#define STRINGIFY(A,B) QUOTE(A##B)
...
#include STRINGIFY(relative/path/to/option/,OPTION)
As I understand from https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html doesn't work because when using ## to paste tokens, the result must be a valid token, where something like path/to/file.hpp is not a valid preprocessing token.
Now, I think that you only need to have a macro which holds the path plus the token to be replaced. Well, you don't really need to add the relative path if you are using the -I flag. Your macro could look like #define myMacro relative/path/to/file/OPTION.hpp, then you just need to define OPTION and pass it to one macro so OPTION gets replaced with its value and then another macro to stringize. These two levels of macros are described here https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing
The following example will ilustrate both cases (with/without -I flag).
Consider this directory structure:
.
|-- a.c
|-- headers
| |-- A.hpp
| `-- B.hpp
`-- makefile
Where a.c:
#define header OPTION.hpp
#define xstr(x) #x
#define str(x) xstr(x)
#include str(header)
makefile:
PATH_OPTION ?= headers/A
OPTION ?= A
.PHONY: all
all: a.c
cpp -D OPTION=${PATH_OPTION} $<
cpp -I./headers -D OPTION=${OPTION} $<
A.hpp
#warning Including A.hpp
1
B.hpp
#warning Including B.hpp
2
With this, you can call make which by default will include headers/A.hpp and you should be able to see both approaches (with/without -I flag) working and printing to stdout the corresponding warning.
To include headers/B.hpp you would do make OPTION=B or make PATH_OPTION=headers/B depending on the approach you take.
I also tried with g++ instead of cpp and it works as well.

how to concatenate strings in #include statement [duplicate]

I would like to have include file paths dynamically created by a macro for a target-configuration-dependent part of my program.
for example, I would like to construct a macro that would be invoked like this:
#include TARGET_PATH_OF(header.h)
Which will expand to a something like this:
#include "corefoundation/header.h"
when the source is configured (in this case) for OSX
So far all attempts have failed. I'm hoping someone out there has done this before?
example of what does not work:
#include <iostream>
#include <boost/preprocessor.hpp>
#define Dir directory/
#define File filename.h
#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
#define MyPath MakePath(File)
using namespace std;
int main() {
// this is a test - yes I know I could just concatenate strings here
// but that is not the case for #include
cout << MyPath << endl;
}
errors:
./enableif.cpp:31:13: error: pasting formed '/filename', an invalid preprocessing token
cout << MyPath << endl;
^
./enableif.cpp:26:16: note: expanded from macro 'MyPath'
#define MyPath MakePath(File)
^
./enableif.cpp:25:40: note: expanded from macro 'MakePath'
#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
^
/usr/local/include/boost/preprocessor/cat.hpp:22:32: note: expanded from macro 'BOOST_PP_CAT'
# define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b)
^
/usr/local/include/boost/preprocessor/cat.hpp:29:36: note: expanded from macro 'BOOST_PP_CAT_I'
# define BOOST_PP_CAT_I(a, b) a ## b
^
1 error generated.
I tend to agree with the comment in utnapistim's answer that you shouldn't do this even though you can. But, in fact, you can, with standard-conformant C compilers. [Note 1]
There are two issues to overcome. The first one is that you cannot use the ## operator to create something which is not a valid preprocessor token, and pathnames do not qualify as valid preprocessor tokens because they include / and . characters. (The . would be ok if the token started with a digit, but the / will never work.)
You don't actually need to concatenate tokens in order to stringify them with the # operator, since that operator will stringify an entire macro argument, and the argument may consist of multiple tokens. However, stringify respects whitespace [Note 2], so STRINGIFY(Dir File) won't work; it will result in "directory/ filename.h" and the extraneous space in the filename will cause the #include to fail. So you need to concate Dir and File without any whitespace.
The following solves the second problem by using a function-like macro which just returns its argument:
#define IDENT(x) x
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define PATH(x,y) STR(IDENT(x)IDENT(y))
#define Dir sys/
#define File socket.h
#include PATH(Dir,File)
Warning: (Thanks to #jed for passing on this issue.) If the strings being concatenated contain identifiers which are defined elsewhere as macros, then unexpected macro substitution will occur here. Caution should be taken to avoid this scenario, particularly if Dir and/or File are not controlled (for example, by being defined as a command-line parameter in the compiler invocation).
You need to also be aware than some implementations may define words which are likely to show up in a token-like fashion in a file path. For example, GCC may define macros with names like unix and linux unless it is invoked with an explicit C standard (which is not the default). That could be triggered by paths like platform/linux/my-header.h or even linux-specific/my-header.h.
To avoid these issues, I'd recommend that if you use this hack:
you use a C (or C11) standards-conformant compiler setting, and
you place the sequence very early in your source file, ideally before including any other header, or at least any header outside of the standard library.
Also, you wouldn't need the complication of the IDENT macro if you could write the concatenation without spaces. For example:
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define Dir sys
#define File socket.h
#include STR(Dir/File)
Notes
I tried it with clang, gcc and icc, as available on godbolt. I don't know if it works with Visual Studio.
More accurately, it semi-respects whitespace: whitespace is converted to a single space character.
I would like to have include file paths dynamically created by a macro for a target-configuration-dependent part of my program.
You should be unable to (and if you are able to do so, you probably shouldn't do this).
You are effectively trying to do the compiler's job in a source file, which does not make much sense. If you want to change include paths based on the machine you compile on, this is a solved problem (but not solved in a header file).
Canonical solution:
Use an IF in your Makefile or CMakeLists.txt, use custom property pages depending on the build configuration in Visual Studio (or simply set the particular settings for your build in the OS environment for your user).
Then, write the include directive as:
#include <filename.h> // no path here
and rely on the environment/build system to make the path available when the compiler is invoked.
This works for VS2013. (It can be done easier, ofcourse.)
#define myIDENT(x) x
#define myXSTR(x) #x
#define mySTR(x) myXSTR(x)
#define myPATH(x,y) mySTR(myIDENT(x)myIDENT(y))
#define myLIBAEdir D:\\Georgy\\myprojects\\LibraryAE\\build\\native\\include\\ //here whitespace!
#define myFile libae.h
#include myPATH(myLIBAEdir,myFile)
From your description, it sound like you discovered that not every "" is a string. In particular, #include "corefoundation/header.h" looks like an ordinary string but it isn't. Grammatically, quoted text outside preprocessor directives are intended for the compiler, and compile to null terminated string literals. Quoted text in preprocessor directives is interpreted by the preprocessor in an implementation-defined way.
That said, the error in your example is because Boost pasted the second and third token : / and filename. The first, fourth and fifth token (directory, . and h) are left unchanged. This is not what you wanted, obviously.
It's a lot easier to rely on automatic string concatenation. "directory/" "filename" is the same string literal as "directory/filename" Note that there is no + between the two fragments.

How should a C++ api be laid out?

Imagining I'm publishing a C++ library with its include files in a folder named api.
// file: api/mylib/fwd/foo.h
inline int mylib_foo();
// file: api/mylib/impl/foo.h
inline int mylib_foo() { return 42; }
In the context of this question, is it advisable for library builders to always use the 'full path' to their own (api) include files?
// file: api/mylib/all.h
#include "mylib/fwd/foo.h" // as opposed to "fwd/foo.h"
#include "mylib/impl/foo.h" // as opposed to "impl/foo.h"
Or could it be acceptable to rely on the fact that the preprocessor 'often' searches the including folder first?
If you don't want to add /home/xtofl/libs/mylib/api to the compiler's include path but rather ... #include "/home/xtofl/libs/mylib/api/mylib/all.h", or even just put mylib next to the client code.
// file: api/mylib/all.h
#include "fwd/foo.h"
#include "impl/foo.h"
N.B. this is nothing to do with how the project is laid out (as the title of your question says), because in all cases you are assuming that the headers are in a sub-directory called fwd. The question is about what kind of #include directives to use given a particular layout. Anyway ...
In the context of this question, is it advisable for library builders to always use the 'full path' to their own (api) include files?
// file: api/mylib/all.h
#include "mylib/fwd/foo.h" // as opposed to "fwd/foo.h"
#include "mylib/impl/foo.h" // as opposed to "impl/foo.h"
That assumes that the including code adds the api dir to its search paths, and you already mentioned two ways that assumption can fail:
If you don't want to add /home/xtofl/libs/mylib/api to the compiler's include path but rather ... #include "/home/xtofl/libs/mylib/api/mylib/all.h", or even just put mylib next to the client code.
So IMHO this is better:
Or could it be acceptable to rely on the fact that the preprocessor 'often' searches the including folder first?
Yes, I think it's better to rely on that, and do:
// file: api/mylib/all.h
#include "fwd/foo.h"
#include "impl/foo.h"
That handles the case where api is in the search path, and the case where it's not, and the case where mylib isn't in a directory called mylib at all.
It relies on the implementation-defined rule that searching for headers included with #include "..." starts in the including file's directory, but that is common to all compilers I know, and is a safer assumption than the other assumptions about where the files are installed.

Concatenate and stringize macro values for #include

I'm trying to create a string from multiple macros/values for use in a #include. I'm doing this to clean up some code for an initial state in a simple state system.
I have 2 default, redefinable macros (if not defined there's a default value)
#define DEFAULT_STATE StateName // name of class
#define DEFAULT_STATE_LOCATION states/ // location of header file from root
The include directive is being used from a file 4 folders in from the root, so the include should look like this
#include "../../../../states/StateName.h"
based on the example above.
So I want to define a macro from the 4 values.
../../../../
DEFAULT_STATE_LOCATION
DEFAULT_STATE
.h
into some macro, say DEFAULT_STATE_INCLUDE
so I can say
#include #DEFAULT_STATE_INCLUDE
(to stringize the value for quotes)
That way I can change the default state and the path from the root of the header file for the default state in a prefix header, and the source using the #include will not have to be updated, and I can omit the constants from redefinition every time.
I'm not including the .h in the DEFAULT_STATE macro because I use the same macro to create and instance of the default state.
I've tried using the concatenation ##, and the stringize operator, and some tricks I've found online, but nothing worked.
I can define ../../../../ and .h in their own macros if needed.
But simply
#define DEFAULT_STATE_INCLUDE ../../../../ ## DEFAULT_STATE_LOCATION ## DEFAULT_STATE ## .h
#include #DEFAULT_STATE_INCLUDE
gives tons of errors.
Any help is appreciated.
Thanks
Note that footnote 143 in section ยง6.10.2 "Source file inclusion" of the C99 standard says:
143) Note that adjacent string literals are not concatenated into a single string literal (see the translation
phases in 5.1.1.2); thus, an expansion that results in two string literals is an invalid directive.
Thus, any string concatenation must be done outside the source code. Token concatenation with ## is not an option; that is used to build identifiers, and the bits of the header name you are joining are not identifiers.
I think you should simply use something like:
#ifndef STATE_HEADER
#define STATE_HEADER "states/StateName.h"
#endif
#include STATE_HEADER
and leave it to the build system, not the source code, to determine that -I../../../.. is required as an option to the compiler.
You'd better pass the include directory to gcc with -I option
-I../../../..
From gcc man page:
-I dir
Add the directory dir to the list of directories to be searched for header files.
This seems relevant: Computed Includes
My reading of that is that the #define macro has to include the " (quote) characters and that you can't rely on the stringize or concatenation operators to do it for you.

Preprocessor directives

When we see #include <iostream>, it is said to be a preprocessor directive.
#include ---> directive
And, I think:
<iostream> ---> preprocessor
But, what is meant by "preprocessor" and "directive"?
It may help to think of the relationship between a "directive" and being "given directions" (i.e. orders). "preprocessor directives" are directions to the preprocessor about changes it should make to the code before the later stages of compilation kick in.
But, what's the preprocessor? Well, its name reflects that it processes the source code before the "main" stages of compilation. It's simply there to process the textual source code, modifying it in various ways. The preprocessor doesn't even understand the tokens it operates on - it has no notion of types or variables, classes or functions - it's all just quoted- and/or parentheses- grouped, comma- and/or whitespace separated text to be manhandled. This extra process gives more flexibility in selecting, combining and even generating parts of the program.
EDIT addressing #SWEngineer's comment: Many people find it helpful to think of the preprocessor as a separate program that modifies the C++ program, then gives its output to the "real" C++ compiler (this is pretty much the way it used to be). When the preprocessor sees #include <iostream> it thinks "ahhha - this is something I understand, I'm going to take care of this and not just pass it through blindly to the C++ compiler". So, it searches a number of directories (some standard ones like /usr/include and wherever the compiler installed its own headers, as well as others specified using -I on the command line) looking for a file called "iostream". When it finds it, it then replaces the line in the input program saying "#include " with the complete contents of the file called "iostream", adding the result to the output. BUT, it then moves to the first line it read from the "iostream" file, looking for more directives that it understands.
So, the preprocessor is very simple. It can understand #include, #define, #if/#elif/#endif, #ifdef and $ifndef, #warning and #error, but not much else. It doesn't have a clue what an "int" is, a template, a class, or any of that "real" C++ stuff. It's more like some automated editor that cuts and pastes parts of files and code around, preparing the program that the C++ compiler proper will eventually see and process. The preprocessor is still very useful, because it knows how to find parts of the program in all those different directories (the next stage in compilation doesn't need to know anything about that), and it can remove code that might work on some other computer system but wouldn't be valid on the one in use. It can also allow the program to use short, concise macro statements that generate a lot of real C++ code, making the program more manageable.
#include is the preprocessor directive, <iostream> is just an argument supplied in addition to this directive, which in this case happens to be a file name.
Some preprocessor directives take arguments, some don't, e.g.
#define FOO 1
#ifdef _NDEBUG
....
#else
....
#endif
#warning Untested code !
The common feature is that they all start with #.
In Olden Times the preprocessor was a separate tool which pre-processed source code before passing it to the compiler front-end, performing macro substitutions and including header files, etc. These days the pre-processor is usually an integral part of the compiler, but it essentially just does the same job.
Preprocessor directives, such as #define and #ifdef, are typically used to make source programs easy to change and easy to compile in different execution environments. Directives in the source file tell the preprocessor to perform specific actions. For example, the preprocessor can replace tokens in the text, insert the contents of other files into the source file...
#include is a preprocessor directive meaning that it is use by the preprocessor part of the compiler. This happens 'before' the compilation process. The #include needs to specify 'what' to include, this is supplied by the argument iostream. This tells the preprocessor to include the file iostream.h.
More information:
Preprocessor Directives on MSDN
Preprocessor directives on cplusplus.com