Preprocessor switch determining version of a class - c++

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

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

Precompiled header error in Visual Studio 2015

I beg your pardon if this question has been already answered, but I have been trying to implement precompiled headers in my game engine with no success so far.
My precompiled header is called UtilBase.h:
#pragma once
#if !defined(NF3D_UTIL_BASE_H)
#define NF3D_UTIL_BASE_H
// This is a precompiled header.
#pragma message("Compiling precompiled header.")
// Include engine specific files.
#include <Utilities\Platform\Types.h>
// Include external header files (STL, Win32 API, Direct3D 11, etc)
// There are some typedefs here:
typedef __int32 int32; // And so on.
#endif
Although this is against the standards, I included UtilBase.h in other headers because I need access to some of its contents. It is also included in all .cpp files, first line, from the current project (the solution has two projects).
I need it in some headers because it stores some typedefs that are used in function declarations. For example, I have some file called Window.h:
#pragma once // And include guards that are omitted here
int32 NF3DCreateWindow();
The associated source file is called UtilBase.cpp and has only one line of code:
#include <Utilities\UtilBase.h>
The project has been set up correctly in my opinion:
for all platforms and configurations.
UtilBase.cpp has this setting:
However, when I compile I get this error:
1>Source Files\Utilities\UtilBase.cpp(2): error C2857: '#include' statement specified with the /YcD:\New Frontiers\NewFrontiers3D\Header Files\Utilities\UtilBase.h command-line option was not found in the source file
which points to the only line in UtilBase.cpp (#include <Utilities\UtilBase.h>).
Why does this happen and what can I do to make it work? I will gladly send any further information about this scenario. Thank you very much in advance.
Finally made it! For anybody in my situation here is what I did: in project settings, Precompiled Header File tag, I added $(ProjDir)\Header Files\Utilities\UtilBase.h and it was evaluated to the full path of the file. The correct way is to simply add the file: Utilities\UtilBase.h and that's it.
Thank you for your support.
try #ifndef instead of #if !defined

Managing code with using #define

I have several source and header files that contains code that should be compiled dependent on the same option. That option might be set with
#define myOption
To be visible this option in all my files I need to put it in place where all files could see it. I see only one way - place this option in special header file and include it to all source and header files. Is there any other way to solve my problem? What is the best practices with code organisation?
UPD
In comments I found option that header file that contains myOption might be stdafx.h. But this is not good practice as far I can see because in CPP projects with enabled precompile header I can have for example some units with C code with turned off precompiled header.
As #Paranaix mention you can provide preprocessor definition for compiler as command line argument like -DmyOption. Let suppose you use Visual Studio, you can open project properties->C/C++->Preprocessor->Preprocessor Definitions and place myOption in that list. It automatically add -DmyOption argument for compiler. So every source file in your project now can check that option.

C++ Visual Studio DLL File

My objective is to create a dll and lib file so i'm following this guide
1) I created a new win32 Console Application project in VS, chose DLL as 'Application Type' and Emptied Project
2) I'm trying to create a database in C++. So I have 5 headers with ONLY function declarations.
3) Database.h is my top header, it looks like this:
#ifdef DBDLL_EXPORTS
#define DBDLL_API __declspec(dllexport)
#else
#define DBDLL_API __declspec(dllimport)
#endif
#ifndef __Database_H
#define __Database_H
#include "Table.h"
class DBDLL_API Database { ... };
#endif
4) Now with only headers, I tried compiling the project. It compiled but I don't see any DLLs or Libs anywhere in the project folder. How do I create them?
This is because headers are not compiled -- only CPP files are compiled (which pull in the headers -- a source file and all the headers it pulls in is called a "translation unit", which is the thing actually being compiled (independent of other TUs)).
So, in effect, the build system thinks you're building an empty project, and in this case generates nothing at all. Note that even if the headers are pulled in and compiled, unless an exported symbol is actually referenced somewhere, it may be optimized out. In such cases, you will get an (empty) DLL, but no .lib file (which can cause errors down the line if you have dependent projects looking for this .lib before there's anything in the DLL).
You'll need to create some CPP files that implement the functions declared in the headers. If you have everything in the headers and don't need any CPP files at all, then there's no point in having a DLL! (Since you could include the headers in any other project without needing any other dependency.)
Finally, your include guard (#ifndef ...) should encompass the entire header, including the DLL export macros, otherwise you'll eventually get macro redefinition warnings.
I would suggest using #pragma once instead of include guards since it's simpler and recognized by pretty much every compiler. I would also put the DLL macro goop into its own header (e.g. "dllmacros.h") and include that where it's needed (this will reduce duplication).

c++ precompiled header defined in a header VS2010. Compiler can't find

I've inherited some code that did something like this,
Header: HeaderFile.h
#ifndef HEADERFILE_H
#define HEADERFILE_H
#ifndef HEADERFILE_PCH_H
#include<LibStuff>
#include<LibStuff2>
#include<LibStuff3>
#include<LibStuff4>
#include<LibStuff5>
#endif
#include "FilesInProject"
Class A
{
//Code
};
#endif
Cpp: HeaderFile.cpp
#include "HeaderFile_pch.h" //(1)
#include "HeaderFile.h"
//More code
I understand what a precompiled header is for and what the code is doing here (sort of). When I copy these files into my project, this is so I can update deprecated code but not effect the original project, VS2010 chocks on line (1). VS2010 Saying it can't find that file.
I've gone between the two projects and I can't find any differences in settings.
What am I missing and why is it okay to imbed PCH's in headers like this instead of actually moving them to a file called HeaderFile_pch.h. Is this some kind of macro hack?
For starters, there is no such file as Headerfile_pch.h either in the samples you provided above nor likely on your local fs.
Visual C++ allows you to define several ways of setting up precompiled header files. The most common is to enable it for ALL source files at the project configuration level, Under Configuration Properties/C++/Precompiled Headers, setting "Precompiled Header", select "Use". The same location, setting "Precompiled Header File", is usually "stdafx.h" but can be anything you choose. All files will get this setting (thus the configuration at the project level) EXCEPT....
One file is responsible for generating the PCH file. That file is typically the stdafx.cpp file in your project, but again, it can be whatever single source you desire. Most just setup a dummy cpp file that has one thing in it: #include "myheader.h" (duh).. Configuring Precompiled Headers for THAT ONE FILE, switch from "Use" to "Create". This ensures that if the prime-header for PCH gets out of synch that source file is recompiled first to regenerate the PCH data file before the others are kicked off.
The one attribute of this that is absolutely mandatory: that include header (myheader.h or whatever you're calling it) must be the first include in any source file you're compiling that is participating in using pch including (hopefully obviously) the file you specified as the "generator" (the one marked as "Create" in the prior paragraph).
Lastly, you can disable pch on a file-by-file basis if this is a problem due to unusual conditions in your build environment (i.e. 3rd party headers that do stupid things).
There are other ways of configuring PCH setting in Visual Studio, but this is by far the most common.