Using a macro to define an include file - c++

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.

Related

String concatenation for include path

Is there a way to concatenate 2 strings literals to form an include path?
Code stub:
#define INCLUDE_DIR "/include"
#include INCLUDE_DIR "/dummy.h"
Looking at this question, the answers point in a different direction (compiler command line). It is mentioned here that it is seemingly not possible, but I wonder if the topic has been dug enough.
(I do have an use case in which this is relevant, please focus your answers/comments on this question only.)
It really seems this is not possible. I will report here the relevant section from Eric Postpischil's answer (he doesn't seem to be active anymore).
The compiler will do macro replacement on an #include line (per C
2011 [N1570] 6.10.2 4), but the semantics are not fully defined and
cannot be used to concatenate file path components without additional
assistance from the C implementation. So about all this allows you to
do is some simple substitution that provides a complete path, such as:
#define MyPath "../../path/to/my/file.h"
#include MyPath
Link to documentation. In particular this section doesn't leave much hope for portable solutions:
The method by which a sequence of preprocessing tokens between
a < and a > preprocessing token pair or a pair of " characters
is combined into a single header name preprocessing token is
implementation-defined.
For completeness, maybe something can be tried using https://stackoverflow.com/a/27830271/2436175. I'll investigate that when I have a moment...
I'm not sure that this is exactly what you want but anyway.
#define DECORATE(x) <x>
#define MAKE_PATH(root, file) DECORATE(root file)
#define SYS_DIR(file) MAKE_PATH(sys/, file)
#define ARPA_DIR(file) MAKE_PATH(arpa/, file)
#include SYS_DIR(types.h)
#include SYS_DIR(socket.h)
#include ARPA_DIR(inet.h)
Note, that generated filenames contain extra space - <sys/ types.h>, so it may not be a cross-compiler solution. But at least for me it works on Linux host on GCC 4.8 / 4.9.
P.S. It would be nice if someone could check this snippet with another compilers, e.g. MSVC.
Simply avoid the space and the concatenation (##) and use the < > it makes all simplier:
#include <QtCore/QtGlobal>
#define QT_VERSION_PREFIX QT_VERSION_MAJOR.QT_VERSION_MINOR.QT_VERSION_PATCH
#define _CONCATE(a, c) <a/QT_VERSION_PREFIX/a/private/c>
#include _CONCATE(QtWidgets, qwidgettextcontrol_p.h)

Need clarification on #ifndef #define

The code I am working has multiple headers and source files for different classes face.cc, face.hh, cell.cc, cell.hh edge.cc edge.hh and the headers contain includes like this,
#ifndef cellINCLUDED
#define cellINCLUDED
#ifndef faceINCLUDED
#define faceINCLUDED
I saw through http://www.cplusplus.com/forum/articles/10627/ and saw the way to write include guard is
#ifndef __MYCLASS_H_INCLUDED__
#define __MYCLASS_H_INCLUDED__
So in above code that I am working on, does compiler automatically understands it is looking for face.hh or cell.hh files?
better question : Is writing __CELL_H_INCLUDED__ same as cellINCLUDED ?
#ifndef __MYCLASS_H_INCLUDED__
#define __MYCLASS_H_INCLUDED__
So in above code that I am working on, does compiler automatically
understands it is looking for face.hh or cell.hh files?
No, the compiler doesn't automatically understand what you mean.
What really happens is that, when compiling a translation unit, the Compiler holds a list of globally defined MACROs. And so, what you are doing is defining the MACRO __MYCLASS_H_INCLUDED__ if it doesn't already exists.
If that macro is defined, that #ifndef until #endif will not be parsed by the actual compiler.
Hence you can test for the existence of that MACRO to determine if the Compiler has parsed that header file to include it once and only once in the translation unit... This is because the compiler compiles each translation unit as one flattened file (after merging all the #includes)
See https://en.wikipedia.org/wiki/Include_guard
Is writing __CELL_H_INCLUDED__ same as cellINCLUDED ?
Yes it is.... The reason some prefer using underscored prefixed and suffixed MACROs for include guards is because they have extremely low probability of ever being used as identifiers... but again, underscore could clash with the compiler...
I prefer something like this: CELL_H_INCLUDED
If you use cellINCLUDED, there are chances that someday, somebody may use it as an identifier in that translation unit
The preprocessor definitions have no special meaning. The only requirement is that they stay unique across the modules, and that's why the file name is typically a part of them.
In particular, the mechanics for preventing double inclusion aren't "baked in" the language and simply use the mechanics of the preprocessor.
That being said, every compiler worth attention nowadays supports #pragma once, and you could probably settle on that.
As the link you have referenced says, "compilers do not have brains of their own" - so to answer your question, no, the compile does not understand which particular files are involved. It would not even understand that '__cellINCLUDED' has anything conceptually to do with a specific file.
Instead, the include guard simply prevents the logic contained between its opening #ifndef and closing #endif from being included multiple times. You, as the programmer, are telling the compiler not to include that code multiple times - the compiler is not doing anything 'intelligent' on its own.
Nope, This is essentially telling the compiler/parser that if this has already been put into the program, don't puthave already been loaded.
This should be at the top (and have an #endif at the bottom) of your .h file.
Lets say you have mainProgram.cpp and Tools.cpp, with each of these files loading fileReader.h.
As the compiler compiles each cpp file it will attempt to load the fileReader.h. unless you tell it not to it will load all of the fileReader file in twice.
ifndef = if not defined
so when you use these (and the #endif AFTER all your code in the .h file)
you are saying:
if not defined: cellINCLUDED
then define: cellINCLUDED with the following code:
[code]
end of code
so this way when it goes to load the code in your .h file a second time it hits the if not defined bit and ignores the code on the second time.
This reduces compile time and also means if you are using a poor/old compiler it isn't trying to shove the code in again.

C++ #define in main, how to get other .cpp files to see it?

Good afternoon all,
I'm writing a program to read license plates that has 11 files currently:
Main.cpp
DetectPlates.h
DetectPlates.cpp
DetectChars.h
DetectChars.cpp
PossiblePlate.h
PossiblePlate.cpp
PossibleChar.h
PossibleChar.cpp
Preprocess.h
Preprocess.cpp
I have a feature allowing showing the intermediate processing steps, or not. Current this is implemented by having a global variable in Main.cpp as follows:
// global variables ///////////////////////////////////////////////////////////////////////////////
const bool blnShowSteps = false;
Then in DetectPlates.h and DetectChars.h, I have the following:
// external global variables //////////////////////////////////////////////////////////////////////
extern const bool blnShowSteps;
So in either DetectPlates.cpp or in DetectChars.cpp I can do something like the following:
if (blnShowSteps) {
cv::imshow("1a", imgGrayscaleScene);
cv::imshow("1b", imgThreshScene);
}
This is done many times in both DetectPlates.cpp and in DetectChars.cpp. So far I have used a global variable as above because I was translating this from a Visual Basic.NET version where the conditional looked at the state of a check box on a form and a global variable was an easy translation to start with.
To make this more "C++ish" I would like to change the global variable to conditional compilation. For example, in Main.cpp I would like to do:
#define SHOW_STEPS // NOTE: comment this line out, or not, to show or not show steps
Then in DetectPlates.cpp or DetectChars.cpp:
#ifdef SHOW_STEPS
cv::imshow("1a", imgGrayscaleScene);
cv::imshow("1b", imgThreshScene);
#endif
The problem is how do I implement this? If I #include "Main.cpp" in DetectPlates.h and/or DetectChars.h I get various errors depending on if I used a multiple include guard in Main.cpp or not, but either way I do not get a compile and also this violates the general practice rule of never including a .cpp file.
One possible answer seems to be adding another .h file, called "MyDefines.h" or similar, with only one line:
// MyDefines.h - single line .h file ??
#define SHOW_STEPS // NOTE: comment this line out to not show steps
But this is not an elegant solution for at least two reasons, for one adding an additional .h file to add one line seems poor, and also that would take the #define SHOW_STEPS out of the beginning of Main.cpp where it would logically be.
Another possible solution would seem to be to add a Main.h file, with the function prototypes and other stuff that is at the top of Main.cpp currently, and then to also add the #define SHOW_STEPS line. This is also not a very elegant solution either since I would be adding an entire .h file to add one line, most C++ programs do not have a Main.h file, and this would still remove #define SHOW_STEPS from being just above function main() where most people would intuitively look when figuring out the flow of the program.
Is there a way to do this where the "#define SHOW_STEPS" line would be in Main.cpp but still be seen in DetectPlates.cpp and DetectPlates.cpp?
As you suspected - place the definition in a header file (.h), and include it wherever necessary.
Either that, or don't use compiler tricks, make a configuration class, and pass the configuration object into the relevant part(s) of the program. Have the configuration class read from a file or be initialised in a relevant way.
Edit: Just to comment on, "To make this more "C++ish" I would like to change the global variable to conditional compilation". Both are pretty dodgy practises. Decent code design is probably what you're looking for!
If you introduce #defines to make your code more "C++ish", you're doing something very wrong.
You don't need to explictly remove the if's at all, the compiler can do this for you, given better circumstances. To start with, change your global variable from extern to static in a header.
...That should be enough. If in doubt, check the asm output.
Make it be defined for your whole project. Like adding -DSHOW_STEPS to GCC command line.

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

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.

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