Please excuse my basic question and poor programming knowledge.
I have an implementation that I need to use in many of my projects. But the included header files are different for different projects.
Say I have spi.h header file to be used in projecta.c and projectb.c. But a particular include (definitions.h) is not required in projectb.c then how do I make this include project specific?
I have seen that is done through #ifdef and #ifndef and directives. But can someone please help me understand how is it done.
Thank you
Say I have spi.h header file to be used in projecta.c and projectb.c. But a particular include (definitions.h) is not required in projectb.c then how do I make this include project specific?
Like this:
// projecta.c
#include "spi.h"
#include "definitions.h"
// projectb.c
#include "spi.h"
There's no need for ifdef directive.
You can include a certain header depending on an #ifdef like that:
#ifdef INCL_DEFINITIONS
# include "definitions.h"
#endif
The in the project where you need definitions.h you have to add -DINCL_DEFINITONS to the compiler parameters
I have seen that is done through #ifdef and #ifndef and directives.
It can be done through #ifdef and #ifndef directives or #if directives.
The key part of this is you need some way to define preprocessor macros based on what project is being built. A common way this is done is:
Each project has its own build settings.
Those build settings include options to pass to the compiler.
The compiler has options to define preprocessor symbols.
For example, with GCC and Clang, you can use -Dsymbol to cause symbol to be defined (with no replacement tokens; it is defined, but the definition is empty) or -Dsymbol=replacement to cause it to be defined with the indicated replacement.
Once you have this, there are choices about how to use it. One choice is for a symbol to be defined if a feature should be included and undefined if not. Then you would have directives such as:
#if defined FeatureX
#include "HeaderForFeatureX.h"
#endif
Another choice is for a symbol to be defined to be 1 if the feature should be included and 0 if not. Then you would have:
#if FeatureX
#include "HeaderForFeatureX.h"
#endif
Historically, some people used the first choice and some people used the second. Because of this, it is common to write your settings and code to cover both of them. When defining a symbol with a compiler option, we will both define it (satisfying the first method) and define it to be 1 (satisfying the second method), as with -DFeatureX=1. When testing it, we will test with with #if defined FeatureX because that is true if either choice is used, whereas #if FeatureX is true only if FeatureX is defined to be 1, not just defined with empty replacement tokens.
(In a #if directive, if a token that could be a preprocessor macro name is not a defined preprocessor macro name, it is replaced with 0. So, if FeatureX is not defined, #if FeatureX becomes #if 0.)
A third choice is to define a symbol to have different values according to the features chosen. For example, we could define ProductLevel to be 10, 20, or 30, and then use directives such as:
#if 10 <= ProductLevel
#include "Level10Features.h"
#if 20 <= ProductLevel
#include "Level20Features.h"
#if 30 <= ProductLevel
#include "Level30Features.h"
#endif
#endif
#endif
Related
I have a single header C/C++ library which contains different inline functions whether the header is included from C or C++.
#ifndef __cplusplus
// C stuff
#else
// C++ stuff
#endif
The problem is that doxygen always parses just one of the two paths depending on whether I predefine __cplusplus myself or not. Entirely disabling preprocessing is no option either as I have other macros I'd like to keep in the documentation.
Is there any sane way to generate documentation for the C and the C++ part of the header?
If I have SOME_MACRO which is defined as either __declspec(dllimport) or __declspec(dllexport), is there a way to check at compile time which one is being used?
I.e. something like this:
#if SOME_MACRO == __declspec(dllimport)
// do something
#else
// do something else
#endif
UPD.
Looking at the answers I'm getting I guess I should be more specific in why I need this.
I'm trying to compile a rather big 3rd party library, which has a function declared as dllexport in most parts of their code where it's included. There's however one component in which it's a dllimport.
I need to modify the declaration slighly for the dllimport case. The switch between the two declarations is not very simple, it is a result of quite a deep tree of #ifdef instructions spread across several files. In principle I could dig this info out form these instructions, but to be sure I did it correctly I'd have to try and compile the whole library under several different configurations (each compilation taking a couple hours).
If on the other hand there was a simple way check whether their SOME_MACRO is evaluated to import or export, I could test this on a small program quickly and safely put that inside the library.
You cannot use
#if SOME_MACRO == __declspec(dllimport)
__declspec(dllimport) is not a valid token for a preprocessor expression.
Your best option is to use another preprocessor macro, such as:
// Are we building the DLL?
#if defined(BUILD_DLL)
// Yes, we are.
#define SOME_MACRO __declspec(dllexport)
#else
// No. We are using the DLL
#define SOME_MACRO __declspec(dllimport)
#endif
Now, you can use:
#if defined(BUILD_DLL)
to include conditional code depending on whether you are building the DLL or using the DLL.
Practically speaking, that ends to be a little bit more involved.
Most projects have more than one DLL. BUILD_DLL is not going to work. You will need BUILD_xxx_DLL for each DLL you build. Let's say you have two DLLs, utility and core. and an application that depends on both.
You may also need to create a static library.
You will need something like the following in every public .h file of the utility library.
#if defined(BUILD_UTILITY_STATIC)
#define UTLIITY_EXPORT
#elif defined(BUILD_UTILITY_DLL)
#define UTLIITY_EXPORT__declspec(dllexport)
#else
#define UTLIITY_EXPORT__declspec(dllimport)
#endif
Of course, you don't want to have to repeat the same code in lots of .h files. You will create a .h file that contains the above and #include that in all other .h files.
When building utility.dll, you will need to define BUILD_UTILITY_DLL and leave BUILD_UTILITY_STATIC undefined.
When building utllity.lib (static library), you will need to define BUILD_UTILITY_STATIC and leave BUILD_UTILITY_DLL undefined.
Users of utility.dll will leave BUILD_UTILITY_STATIC as well as BUILD_UTILITY_DLL undefined.
Users of utility.lib (static library) will need to define BUILD_UTILITY_STATIC and leave BUILD_UTILITY_DLL undefined.
You will need a similar file for core.dll and core.lib.
The macro is named by you the DLL creator.
You want a header file that works in export or import mode.
A C/C++ file will be used, to create a program, to build the DLL (export).
Other C/C++ files will be used to call the DLL (import functions).
In the build implementation file a macro, that you name, is defined before the inclusion of the header.
e.g.
#define DLLNAME_BUILD_DLL
#include "dll_header.h"
In the header, if the macro is defined, the mode is set to export. When using the DLL the macro is not defined and the functions are imported.
Short description:
Header.h has #include <stdbool.h> which has a Macro for _Bool in c.
file.cpp includes Header.h, but since file.cpp is C++ - it has bool as a native type. Now lint complains about a set of things due this (redeclaration, non-existing methods etc.). Is there a way to prevent inclusion of <stdbool.h> in file.cpp without touching Header.h?
If my description of a problem looks ridiculous - please throw tomatoes at me :) Otherwise, thanks for help.
Edit: Now thinking of this again: knowing the basic concepts of compilation and linking I should have realized that 'excluding' some header in downstream file/header sounds funny and should not be possible without cludges. But still, thanks for help. Another small brick to my understanding of this.
You could create your own stdbool.h and put it earlier in the include path so it is found before the system one. That's technically undefined behaviour, but you have a broken <stdbool.h> so it's one way to work around that. Your own version could either be empty (if it will only be included by C++ files) or if you can't prevent it also being used by C files then you could do:
#if __cplusplus
# define __bool_true_false_are_defined 1
#elif defined(__GNUC__)
// include the real stdbool.h using the GNU #include_next extension
# include_next <stdbool.h>
#else
// define the C macros ourselves
# define __bool_true_false_are_defined 1
# define bool _Bool
# define true 1
# define false 0
#endif
A cleaner solution would be to do this in file.cpp before including Header.h:
#include <stdbool.h>
// Undo the effects of the broken <stdbool.h> that is not C++ compatible
#undef true
#undef false
#undef bool
#include "Header.h"
Now when Header.h includes <stdbool.h> it will have no effect because it's already been included. This way is technically invalid (see comment below), but in practice will almost certainly work portably.
It needs to be done in every file that includes Header.h, so you could wrap it up in a new header and use that instead of Header.h e.g. CleanHeader.h that contains:
#ifndef CLEAN_HEADER_H
#define CLEAN_HEADER_H
// use this instead of Header.h to work around a broken <stdbool.h>
# include <stdbool.h>
# ifdef __cplusplus
// Undo the effects of the broken <stdbool.h> that is not C++ compatible
# undef true
# undef false
# undef bool
#e ndif
# include "Header.h"
#endif
I know C or C++ code usually needs to use include guards like this:
#ifndef __A__H__
#define __A__H__
class A{
};
#endif
and to speed up compile time, in other cpp (e.g.:B.cpp), it can change
#include "A.h"
to:
#ifndef __A__H__
#include "A.h"
#endif
but the question is why doesn't the compiler automatically add or generate the include guard, and therefore why does the programmer need to add it manually if an include guard is usually required?
There are times when it is absolutely incorrect to generate the header guard. The standards contain an example: <assert.h> in C and <cassert> in C++.
The effect of reincluding those headers depends on the state of the NDEBUG macro when the header is (re)included. It is legitimate to write:
#undef NDEBUG
#include <assert.h>
…code using assert…
#define NDEBUG 1
#include <assert.h>
…more code using assert…
If the compiler automatically generated a header guard, that would not work correctly. Therefore, compilers do not generate header guards automatically.
Incidentally, user code should not use header guard macro names that start with double underscore, or underscore capital letter. Such names are reserved for the implementation. In C++, no user-defined name may legitimately contain a double underscore at all. Use something more like:
#ifndef A_H_INCLUDED
#define A_H_INCLUDED
…body of header…
#endif
The compiler, or more strictly the pre-processor cannot determine the programmer's intent in using inclusion. The compiler does not explicitly distinguish between .h files and .c or .cpp files; they differ only in the type of code one places in them. In fact the compiler deals only in a single translation unit; it is the responsibility of the C preprocessor to concatenate all included files into a single file for compilation. It would be incorrect for the pre-processor to omit an inclusion that it has previously included because it has no semantic knowledge of the code and may cause intended behaviour to change by second-guessing the developer.
In some circumstances, an IDE may add include guards for template code that it has generated. For example Microsoft Visual Studio will add them for code that it generates via its project start-up wizards. If it happens at all, it is properly the responsibility of the IDE rather than the compiler or pre-processor.
In an MSVC C++ program I have a part of code which I want to enable or disable depending on a preprocessor definition
// 1.h
#ifdef MYOPTION
//...
#endif
But I find that it is quite dangerous when it is used in a .h file included in more than one compilation unit, as I can easily get inconsistent headers (I don't want to define MYOPTION globally as it would require a complete recompilation each time I change it):
// 1.cpp
#define MYOPTION
#include "1.h"
// 2.cpp
#include "1.h"
Of course, it is much more complicated than this simplified example due to the chained header inclusion.
Is there a way to avoid such inconsistency, e.g. have a compile-time error without too much effort?
I thought of doing #define MYOPTION 0 or 1, but then I would have to write something like
#if MYOPTION == 1
//...
#elif !defined(MYOPTION)
#error ...
#endif
which looks too complicated... Maybe there is a better option?
How about something like this: have 1.h define a dummy section in the obj with different options. This way, if MYOPTION is ever used inconsistently, the linker will issue a warning.
1.h:
#ifdef MYOPTION
#pragma section("MYOPTION_GUARD",write)
#else
#pragma section("MYOPTION_GUARD",read)
#endif
namespace { __declspec(allocate("MYOPTION_GUARD")) int MYOPTION_guard; }
Compiling with MYOPTION defined in a.cpp but not in b.cpp yields this linker warning (using VC 2008):
b.obj : warning LNK4078: multiple 'MYOPTION_GUARD' sections found with different attributes (40300040)
A consistent definition yields no linker warnings at all.
I think you've listed most solution yourself, basically. I would use the last solution, but perhaps in a slightly different form:
#ifndef MYOPTION
#error ...
#endif
...
#if MYOPTION == 1
//...
#endif
Because often this #if MYOPTION == 1 will appear more than once in each file. It's also clearer that MYOPTION is a requisite for that file.
You say it "looks too complicated", but I'm afraid there's probably no solution that's less "complicated" than this.
Assuming that you actually need to use the defines, better is to define them via the compiler command line than #define in your source files. Then your configure script/makefile/build process sets the define once and you're guaranteed that it will agree properly across all source files.
Perhaps what you want is to create a separate configuration.
You can go to Build -> Configuration Manager and create a new configuration (separate from DEBUG, RELEASE). Creating a new configuration will allow you to define preprocessor symbols specific to that configuration.
For example, with a new configuration titled "MyOption 1" you could add the preprocessor definition MYOPTION = 1. The same thing goes with MYOPTION = 2, 3, ...
Each configuration has to be built separately.
DEBUG and RELEASE are examples of separate configurations; DEBUG defines _DEBUG and RELEASE defines NDEBUG