How to detect where a header is included from - c++

Is it possible to detect (and print out) programmatically where a C++ header got included from?
I have a header like:
// DeprecatedHeader.h
__pragma( message ("DeprecatedHeader.h is deprecated - include NewHeader.h instead.") )
#include "NewHeader.h"
As you can see, compiler is MSVC, but I have macros to wrap. GCC is welcome, but if not possible, I would enable the 'trick' just on Windows.
But what I'm looking for is an output like
"AnyOtherFile.cpp was including DeprecatedHeader.h, please include NewHeader.h instead."
Edit: To be clear why I want this: The warning the compiler throws is helping already a lot: the code is not broken but pokes the people to change the include. Problem: it may blame the wrong 'guy' as you could pull in this header via another header. My objective was to blame the erroneous header, not the compilation unit.

You can run your compiler with the option to produce the preprocessed source code rather than the fully compiled (gcc -E, CL.EXE /E or whatever) . The resulting code will include tagging of where each snippet of code comes from.

Even though I don't think it's worth pursuing this functionality, but here's a solution.
On top of each header file, after checking for deprecated header and before including other files, put this:
#undef INCLUDING_FILE
#define INCLUDING_FILE "file_name.h"
This can be done with a simple bash script where for each .h file you write this, including the file name in the string.
So your headers would look like this (with gcc):
Normal header:
#undef INCLUDING_FILE
#define INCLUDING_FILE "normal.h"
#include "deprecated.h"
Deprecated header:
#ifdef INCLUDING_FILE
# pragma message "Internal bug: " INCLUDING_FILE " included " __FILE__ " which is deprecated"
#else
# pragma message "Note: you shouldn't included " __FILE__ " which is deprecated"
#endif
#undef INCLUDING_FILE
#define INCLUDING_FILE "normal.h"
#include "others.h"

Not sure about an exact solution (probably it is possible to do with __FILE__ and other similar macros), but you could try #warning preprocessor directive placed into a wrong header file. During compilation it will issue a warning, which will notify about whatever you want.

Related

C++ preprocessor executing both #ifdef and #ifndef

So I'm currently working on something that uses OpenCL. The OpenCL spec provides the users with a directive which must be included before the inclusion of the header (cl.h)
#define CL_TARGET_OPENCL_VERSION 110
Which basically defines the version they want to use. Suppose I'm making a library and I want my users to define this instead of me defining this inside my files. What I did was.
-----main.cpp---
#define CL_TARGET_OPENCL_VERSION 110
#include "library.h"
-------x---------
----library.h-----
#ifdef CL_TARGET_OPENCL_VERSION
#pragma message("def")
#endif
#ifndef CL_TARGET_OPENCL_VERSION
#pragma message("ndef")
#endif
.... include other headers.
--------x---------
And the compiler prints both def and ndef messages. And the OpenCL library also throws a warning that it's undefined. I thought that the library header would get substituted into main and it'd only print the def message. Is there anything I understood wrong?
I'm particularly confused as to where does the preprocessor start? If it starts from main.cpp and goes from top to down, then it surely has defined the macro. After that it sees the library inclusion, then it should only print the def message but it prints both.
This leds me to believe the preprocessor does scan the header file before including it in main? Dunno the reason why. Also I have assured that the library header isn't included elsewhere.
One interesting thing I noticed was, if i did this
-----helper.h---
#define CL_TARGET_OPENCL_VERSION 110
-------x---------
----library.h-----
#include helper.h
#ifdef CL_TARGET_OPENCL_VERSION
#pragma message("def")
#endif
#ifndef CL_TARGET_OPENCL_VERSION
#pragma message("ndef")
#endif
.... include other headers.
--------x---------
It prints the def message "twice". If anybody can explain all this I'd be grateful.
EDIT:- The files I'm compiling are main.cpp library.h and library.cpp
Library.cpp includes library.h from the start as usual. Maybe this other cpp is causing the problem?
In C/C++ programs, the compiler handles each .c and .cpp file separately.
The compilers build each source file (NOT the header files, only .c and .cpp files) independently from each other (this source files are called compilation unit).
Thus, when your main.cpp is built, the compiler finds the #define CL_TARGET_OPENCL_VERSION 110 you have added on top of the main.cpp file, emiting the defmessage.
But when the compiler builds the library.cpp file, it does not find the version define, so it emits the ndef message.
So, following this explanation, it is completely normal that in your last case, when you add the define to the .h file, the compiler emits the def message twice, once for the main.cpp file and once for the library.cpp file.
Now, the problem is where should you add the define, in order to have the program built consistently, with the same version for all the .cpp files.
Usually, all the IDEs have some configuration page where you can add global defines, for all the project, which are "inserted" into all the compilation units before everything else. So when the IDE calls the compiler, it passes the same defines to all the compilation units. You should add this kind of defines in this page.
In your IDE (I am using Code::Blocks, v 17.12), you can find this page in the menu: Project / Build Options
For each type (Debug or Release), you have to go to the tab Compiler Settings, and there to the sub tab #defines. There you can add global defines, which can be different if you are building in Debug or in Release mode (of course, if you set the same in both modes, they would be the same).
Once you have added your define here, please, remove it from the main.cpp, library.h and any other place where you may have added it, in order to avoid duplicities.
From the comments about portability:
You have several options:
Always use Code::Blocks: this would be the easiest way, since you can pass the Code::Blocks project along with the source files, and everything would be already setup.
Use cmake, which is a script build system, where you can set defines and so in the same way as using an IDE. cmake is much widely used than Code::Blocks, so maybe it is a better option.
Add a new options.h header file, where you set all the defines, and include it to all your .c/.cpp. This setup has the additional benefit that for different systems, changing only the options.h file the build can be completely different. This is a manually setup of what the IDE is doing. It has the advantage that does not rely on external tools, but the disadvantage that you have to remember to add it in all the new .cpp files added to the project.
My recommendation is go with cmake, just as the others have said.
Prefer using #ifndef XXXX_h #define XXXX_h #endif over #pragma once
If your #include search path is sufficiently complicated, the compiler may be unable to tell the difference between two headers with the same basename (e.g. a/foo.h and b/foo.h), so a #pragma once in one of them will suppress both. It may also be unable to tell that two different relative includes (e.g. #include "foo.h" and #include "../a/foo.h" refer to the same file, so #pragma once will fail to suppress a redundant include when it should have.
This also affects the compiler's ability to avoid rereading files with #ifndef guards, but that is just an optimization. With #ifndef guards, the compiler can safely read any file it isn't sure it has seen already; if it's wrong, it just has to do some extra work. As long as no two headers define the same guard macro, the code will compile as expected. And if two headers do define the same guard macro, the programmer can go in and change one of them.
#pragma once has no such safety net -- if the compiler is wrong about the identity of a header file, either way, the program will fail to compile. If you hit this bug, your only options are to stop using #pragma once, or to rename one of the headers. The names of headers are part of your API contract, so renaming is probably not an option.
(The short version of why this is problematic to use #pragma is that neither the Unix nor the Windows filesystem API offer any mechanism that guarantees to tell you whether two absolute pathnames refer to the same file.)

Include header files optionally in C++

I have a C++ code which needs to include a certain library in some servers and not in other servers. I build my code using bjam.
Code example:
if server in server_list:
include <header-file.h>
int function();
else:
int function();
And during build using bjam:
if server in server_list:
-llibrary
else:
...
Header file inclusion is a compile time activity not run time. So you can't use if conditions for the same
use #ifdefs
#define SERVER_IN_LIST
#ifdef SERVER_IN_LIST
#include<...>
#endif
In C and C++ any line that begins with a # is a pre-processor directive. The pre-processor is a text parser that parses a source code file before it is compiled. It understands particular directives such as #include, #define and #ifdef but it treats normal C++ code as if it were text. For this reason, you can't use normal C++ code to alter the interpretation of the pre-processor directives.
Let's look at an example:
if (x == 4){
#include "x4.h"
}
The above is wrong because the if statement and its braces are part of the C++ code so will be ignored by the pre-processor. The pre-processor will go straight ahead and interpret the #include directive, which will cause the contents of x4.h to be pasted into that position in the file.
The correct way to write this is to use conditional pre-processor directives such as #if or #ifdef. For example...
#ifdef INCLUDE_X4
# include "x4.h"
#endif
Note that the indentation in this code is optional.
More information about pre-processor directives can be found here.

What is the reason for #pragma once inside header guards?

Just seen this inside <boost/asio.hpp>
#ifndef BOOST_ASIO_HPP
#define BOOST_ASIO_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
/// ....
#endif // BOOST_ASIO_HPP
Disregarding the _MSC_VER preprocessor checks, what is the benefit of having the #pragma once in this case? Doesn't the preprocessor header guard ensure in all cases and on all platforms, the header contents are only ever included once?
#pragma once specifies that the file will be included (opened) only once by the compiler when compiling a source code file. This can reduce build times as the compiler will not open and read the file after the first #include of the module.
If you don't #pragma once, the file will be opened each time it is needed and compiler will stop parsing it on #ifndef BOOST_ASIO_HPP, if it has been defined.
Specifies that the file will be included (opened) only once by the compiler in a build. This can reduce build times as the compiler will not open and read the file after the first #include of the module
And one more related question from SO
Yes header guards ensures that the header contents are included only once. but here you are using #pragma for checking another definition and not include file.
The below link is existing question on header guards in SO.
Purpose of Header guards
#pragma once has the same purpose, but include guards are intended to require a deeper analysis to ensure a file is included exactly once - e.g.
// somerandomfileinmyproject.cpp
#undef BOOST_ASIO_HPP
#include <bost/asio.cpp>
Unless the compiler does handle such cases correctly, it still needs to open the file and pass it through the preprocessor even though it has been included before.
You can reproduce the effect of the #pragma once in a standard way using the following:
#if !defined GUARD_SYMBOL
#include "GUARDED_FILE"
#endif
although it is much more verbose. As others have said, it helps with compilation times since the file is not searched for / opened instead of opening the file and ignoring everything inside it - the file still has to be parsed by the preprocessor.

redefinition c++

how does header including in c++ work? I have the classes already implemented in .h file and when there is #include in two files, there's this error:
files.h:14:7: error: redefinition of ‘class abstract_file’
files.h:14:20: error: previous definition of ‘class abstract_file’`
multiple times for each class and enum.
Can anyone explain this?
Using include in C++ simply takes the file included and splats the contents into where it is included. To do this without worrying about multiple includes of the same file, you want to use header guards. Use this basic format for all header files:
#ifndef FILENAME_H
#define FILENAME_H
class foo (or whatever else is in the file!) {
...
};
#endif
You can only include a definition one time but headers can be included multiple times. To fix that, add:
#pragma once
to the top of each header file.
While #pragma once is relatively common, if you are using an older compiler it may not be supported. In that case, you need to fall back on manual include guards:
#ifndef MY_HEADER_H
#define MY_HEADER_H
...
#endif
(note that you need to replace MY_HEADER_H with a unique string for each header file)
header files usually define a unique symbol so that they are only included once.
e.g.
#ifndef _myheader_h
#define _myheader_h
// rest of header goes here
#endif
Some compilers support
#pragma once
See Pragma Once on wikipedia.
While many people have solved your error for you, it seems that nobody has answered your initial question:
how does header including in c++ work?
When the preprocessor finds an #include directive it replaces it by the entire content of the specified file.
You can read more on preprocessor directives at cplusplus.com.
Update: To illustrate this, you could try the following if you have gcc handy:
echo '#include <iostream>' > test.cxx
gcc -E test.cxx
You'll see the contrents of iostream whizz past your eyes as the preprocessed source code is sent to standard output.
What you can do is to guard your header from multiple inclusions:
#ifndef MY_HEADER__
#define MY_HEADER__
/* your stuff goes here! */
#endif
You can also use:
#pragma once
but it is not standard although it is supported by many compilers.
Use include guards in header files:
#ifndef FILES_H
#define FILES_H
struct foo {
int member;
};
#endif // FILES_H
This makes sure that your header will only get included once.
Another method is to use #pragma once in your header files, but it's not standard C. It's supported by Visual C, GCC and Clang though, so most likely it's ok to use.

Preprocessor switch determining version of a class

I have a class with two possible implementations, depending on a preprocessor switch. The way I have handled this is to create "src\CompSwitch1\class.h" and "src\CompSwitch2\class.h". In my standard include file, I use
#ifdef CompSwitch1
#include "CompSwitch1\class.h"
#elif CompSwitch2
#include "CompSwitch2\class.h"
#else
#error "Specify CompSwitch1 or CompSwitch2"
#endif
This works for most of my classes that need two versions. However, on one of them, I get a linker error (lnk2019: unresolved external symbol). I'm using MS Visual Studio 2005 and 2008, and it appears on both of them.
At the top of the .h file, I test against the preprocessor option.
Also, although I only referenced the .h file for brevity, there is also a .cpp file for each of these, in the appropriate directory.
It sounds like you might have included the header file for one of the classes, but linked the object file for for the other one, or neither
it should really be #ELIF DEFINED( CompSwitch2 ) really. Otherwise you are assuming "CompSwitch2" has been defined with a value of 1 ...
Try to put in the cpp implementation files after they include your header the following preprocessor line(s):
//in compswitch1.cpp
#ifndef CompSwitch1
# error "inconsistent header included"
#endif
//in compswitch2.cpp
#ifndef CompSwitch2
# error "inconsistent header included"
#endif
If you compile wrong header/cpp pairs you should get at least compilation errors and not linking errors. There are much easier to identify/fix ;)
Another possibility is that the cpp-files are not included into compilation at all. Put a message pragma inside the cpp file to see if they get compiled at all:
#pragma message( "Compiling " __FILE__ )
Or try to identify in the build directory if there object files created, which relate to cpp-compilation units.
Hope that helps,
Ovanes
You can use preprocessed cpp file (stage where all includes and macros are expanded).
In VS 2008 right click on your file in Solution Explorer->Properties->C++->Preprocessor and set "Generate Preprocessed File" set "With Line Numbers (/P)".
After that right click again your file and choose "Compile". File with extension "i") (e.g. main.i) will be created in the same directory where cpp resides. Open it and see which include file is included.
This method is very handful to solve hard compilation problems (e.g. some macro from system header files replaces something in your code).