Force project files to inlude a header

Started by
5 comments, last by Monkeynuts 10 years, 4 months ago

Hi,

I have a project with a config.h file that controls several things in my source. I want to make sure that all my files include it. Sometimes I forget to include it in new files, which means that things that were supposed to be conditionally compiled get compiled when they shouldn't and vice-versa, and that creates all kinds of problems. Sometimes it takes a while to trace the problem back to the fact that I forgot the include.

Is there any way to make sure that all my files include a certain header file? My code gets compiled by gcc, clang and visual c++, and I'd relly prefer a cross-compiler and build system solution to this.

Advertisement
I don't know about the others, but in Visual Studio, you can use the "force include file" option in the project properties under C/C++ > Advanced.

Thanks! However, I really do need a cross-compiler solution.

According to the documentation for clang and gcc, it looks like you would need -include (or /FI if using clang-cl).

Seems to be what I need! You've provided me with a solution for all three compilers now, that's great. Thanks!

Sometimes I forget to include it in new files, which means that things that were supposed to be conditionally compiled get compiled when they shouldn't and vice-versa, and that creates all kinds of problems

While the answers you have received were quite correct, I think you'll find with more experience that the correct solution is to simply make it so you can't even use features you don't have the right header for.

A further simple approach though would be to use explicit numeric values to enable/disable features and then enable warnings for undefined macro usage (-Wundef in GCC-like compilers and /w14668 in VC++), and then use value tests instead of ifdef or if defined():

//config.h
#define FEATURE 1
#define DISABLED_FEATURE 0

// somecode.cpp
#include "config.h"

#if FEATURE
stuff
#endif

#if OTHER_FEATURE
stuff that is disabled
#endif
The advantage here is that the compiler will (with those compiler flags) emit a diagnostic that FEATURE and OTHER_FEATURE are undefined if you try to test them without including config.h first.

A better technique is to abstract one level further. Use higher-level macros like THING_THAT_USES_FEATURE(stuff) which is defined in some header that itself includes config.h. An easy example is an assert library:

// config.h
#define ENABLE_ASSERTS 1

// asserts.h
#if ENABLE_ASSERTS
#define ASSERT(...) assert_stuff_here
#else
#define ASSERT(...)
#endif

// somecode.cpp
#include "asserts.h"

ASSERT(something)
As you can see in that example, there is no opportunity to remember or not config.h in order to use the assert library. If you include the header necessary to use the asserts at all, you're implicitly pulling in config.h, too.

The gist is that you don't use config headers. Make the config something that is passed to the compiler in your build system. This is trivial in every build system I've ever seen. Now there's no additional burden on the programmer after configuring the build. Every third-party library I've used that uses config headers for these kinds of things (a UNIX norm, sadly) is a pain in the ass to integrate into more complicated needs (like the many separate build configurations common in game development).

About the only thing I use forced includes for are precompiled headers (otherwise people tend to write all kinds of C++ code that accidentally requires that the precompiled header includes something they need which is unfortunate since the PCH is a build optimization and neither it nor its contents should be a hard dependency of any code).

Sean Middleditch – Game Systems Engineer – Join my team!

I'm actually using defines passed to the build system right now to configure my builds. I was going to migrate to a config file instead, to have all defines in a common place (together with nice comments and explanations). However, now that you mention it, that will probably be more of a headache when building for different platforms.

I like the second approach (and I've seen this in use, but never realized that it will actually help me by making sure I get compile time errors when appropriate - that's what happens when you just read something and don't use it yourself : )).

Thanks for the explanation and for expanding my views on this.

This topic is closed to new replies.

Advertisement