gcc precompiled header: pragma once in main file - c++

I created a header file. Something simple as follows.
#pragma once
#include <iostream>
template<typename T>
void say(T t) {
std::cout << t << std::endl;
}
and then use g++ to create the gch pre-compiled header with g++ hello.h. It gives me this warning ->
pch.h:2:9: warning: #pragma once in main file
2 | #pragma once
| ^~~~
But the gch file created and the pre-compiled header works fine. This error goes away if I use header guards.
Am I doing something wrong here?

You're not doing anything wrong; this is a quality of implementation issue that has been mentioned on the issue tracker before (but, to my knowledge, there are currently no plans to change the behaviour).
In Clang, you could turn off the warning for that particular compiler invocation (with -Wno-pragma-once-outside-header); in GCC you'll just have to grin and bear it for now.

The main source file used to generate a precompiled header is usually a made-up "indirect" header that contains only a bunch of #include for all the actual real headers you want to precompile.
When you use the machinery this way, there is no need for a #pragma once (nor guard) in the main file, and hence it works as intended with no warning.

This is a known GCC bug:
Pragma once warning when compiling PCH
To my knowledge, there is no good way to disable this warning. One way that retains matching behavior is an additional indirection. In pch.h, use
#include <pch-real.h>
(without #pragma once), and store the actual header contains in pch-real.h. This mostly preserves the include-only-once optimization even if <pch.h> is included multiple times in non-PCH mode.

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

Weird Behavior with gcc precompiled headers

I was having troubles getting pre-compiled headers to work, so I came up with the following minimal-working-example.
This is the header file foo.h
#include <iostream>
using namespace std;
void hello() {
cout << "Hello World" << endl;
}
I compile this as g++ -c foo.h gives me a compiled header foo.gch. I expect that when I compile the following source file that includes foo.h, it should pick the header foo.h.gch and I am good.
// test.cpp
#include <cstdio> // Swap ordering later
#include "foo.h" // ------------------
int main() {
hello();
}
But surprisingly, this does not compile using foo.h.gch, but rather uses foo.h. To verify you can compile this as g++ -H test.cpp
However, if I change the order of included header files as follows:
// test.cpp
#include "foo.h" // ------------------
#include <cstdio> // Ordering swapped
int main() {
hello();
}
Now if I compile using g++ -H test.cpp, it compiles from foo.h.gch, whew!
So I was wondering if this is a bug in GCC or are we supposed to use pre-compiled headers like that? In either case I think its useful to know..
With GCC, precompiled headers work only if they are the only header, and if they are included first (without any previous header).
This answer explains more why it is so.
See also the Precompiled headers chapter of GCC documentation, which says:
Only one precompiled header can be used in a particular compilation.
A precompiled header can't be used once the first C token is seen.
BTW, it could happen that pre-compiling some large header (notably in C++) is not worth the effort. YMMV.
In a nutshell, the precompiled header thing works thus:
When you request to create a '.pch' file, the compiler processes the source file as usual. While it does so, its internal structures (mostly, name tables and all associated data) are populated. At the end, it makes a snapshot of these internal structures and saves it to the '.pch' file.
Later, when compiling a source file that includes a header for which a '.pch' file exists, the compiler can omit the expensive processing of the header file and load the ready-for-use snapshot from the '.pch' file instead.
Obviously, this can be done without affecting the semantics only if:
the inclusion directive comes before anything else;
the compiler options are the same.
Anything that comes before the inclusion directive may:
add something to the internal data structures of the compiler;
affect the processing of the header file;
alter relations between entities described there.
Therefore, in this case, loading the snapshot of internal data structures would be wrong because there'd be no guarantee that it would leave these structures in the same state as after the normal processing of the header.
From the GCC manual pages:
A precompiled header can't be used once the first C token is seen.
So including <cstdio> in your precompiled header or including it first will work.

Checking header file for dependencies at compile-time

Do compilers offer the capability to automatically check if each source file (and its associated header file, if any) include all other headers that are required? Or at least issue a warning, say, if a required header is not included explicitly?
For example, I would like the compiler to report when I do something like this:
header1.h
#include <string>
...
header2.h
#include "header1.h"
#include <iostream>
std::string blah; //<-- issue warning here, <string> not included explicitly
...
source2.cpp
#include "header2.h"
...
cout << endl; //<-- issue warning here, <iostream> not included explicitly
I am using g++ and Visual Studio, so my question primarily applies to these compilers. Thanks!
There is no automatic way for doing so, as far as I know.
My suggestion is to confine inclusions into headers only to what is needed for the "interface" defined in the .h
In C++ Coding Standards (Sutter, Alexandrescu) you can find an item which tackles this explicitly (it's titled Make header files self-sufficient). I cite:
Behave responsibly: Ensure that each header you write is compilable standalone, by
having it include any headers its contents depend upon
and
But don't include headers that you don't need; they just create stray dependencies.
Consider this technique to help enforce header self-sufficiency: In your build, compile
each header in isolation and validate that there are no errors or warnings.
Moreover you should always include your own .h first, since this maximizes the probability of finding out if there are inclusion errors.
In all cases, headers should be swappable, so that if your file includes a.h and b.h, both possible orders should do.

#pragma warning(push) without #pragma warning(pop)

Using C++ Native solution in Visual Studio 2010.
#pragma warning (push) is used in the beginning of the cpp file, after all the includes. After that there are couple of disabled warning by #pragma warning(disable : XXXX).
What are possible consequences of omitting #pragma warning(pop) at the end of the file?
Thanks
If you have any other source files that #include that cpp file, then the warning state when compiling the outer file will be messed up -- it could fail to give warnings when the warnings were warranted.
Note, however, that #includeing a cpp file is considered bad form and a code smell; there are certain, rare, situations where it might be the right thing to do (such as a build system that #includes many source files into one to reduce compilation times, sort of like precompiled headers), but almost always it's the wrong thing to do, even if it manages to compile and link without errors.
If that source file is never #included anywhere else, then failing to have a #pragma warning(pop) will not have any adverse consequences, assuming the compiler doesn't complain about that mismatch in the first place.
Since this is a compiler only setting, it won't have any impact on the program itself. It may though screw up warnings for external includes.

How can the order of include statements matter in the linking step?

I cannot explain the behaviour I am seeing when linking my code. Maybe someone has an idea what's going on...
I have a multiple file C++ project which uses GNU automake tools as its build system (all on Linux).
After adding a source and header file (lets call them util.cc and util.h) to the project and having an already existing source file (calc.cc) calling a function from the newly added files I get a linking error depending on where the include statement appears. I repeat: The error occurs in the linking step, compilation runs fine!!
Example:
I get an error when putting the new include statement at the end of the preexisting statements, like:
calc.cc:
#include "file1.h"
#include "file2.h"
#include "file3.h"
#include "file4.h"
#include "util.h" // new header
This version compiles fine. But linking produces an error (symbol not found)!!
Now, when changing this to
#include "util.h" // new header
#include "file1.h"
#include "file2.h"
#include "file3.h"
#include "file4.h"
then compilation and linking runs fine!
Since the linker only reads the .o files, this must mean that different content is produced depending on where the include statement appears. How can this be?
Compiler is g++ (GCC) 4.4.6
Chances are that util.h has a #define that changes the behaviour of one of the other files.
Your best chance of working out exactly what is going on would involve examining those header files for the name of the missing symbol and getting the pre-processor output from compiling calc.cc both 'working' and 'non working' way, and comparing the two files.
Simple, header files can (re)define macros which can change the interpretation of later macros.
For instance, in your example above, if file1.h does
#define lseek lseek64
and util.h has an inline function which calls lseek, then depending on the include order the generated object code will have a symbol reference to lseek or lseek64.
Which is why projects tend to have rules that config.h (generated by autoconf) is included first.
You're absolutley right: different object code is produced in the two cases. As #hmjd also points out, most likely there's a macro in util.h which one of the other (.h or .c) files use, and any undeclared, called identifier is assumed to be a function by the compiler -- this is most likely the error here.