C++ mulitple definitions of function when compiling for multiple architectures - c++

I have 4 files, linuxasm.h linuxasm.cpp windowsasm.h and windowsasm.cpp
in the main.cpp i have
#ifdef __linux
#include "linuxasm.h"
#elif _WIN64
#include "winasm.h"
#endif
the function names in the .cpps are identical
is there a way to prevent GCC from complaining about multiple definitions of functions?
Or should I go about it another way?

You should do it some other way. I would use your build system to omit the appropriate .cpp file from the build based on architecture (if I understand your situation correctly).
Basically, for one target, say Win64, the windowsasm.cpp is a dependency and is compiled; similarly for Linux. Look up how your system is managing dependencies for the build and give it a try.

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

Scope of a C++ symbol

AFAIK, symbols are useful to prevent multiple parsing. If both a.h and b.h include c.h, a
#ifndef C_H
#define C_H
...
// c.h definition would go here
...
#endif
will prevent c.h from being "parsed" (I believe it's not the right word) more than once.
However, I have seen something like
#ifdef WIN32
...
in other people's code. That symbol must have been defined somewhere else because a search for
#define WIN32
in the whole project returns empty. My question is: where are these symbols actually defined? Does the OS keep something similar to a pool of symbols that different programs can use to query for OS or other processes properties?
There are two options where those which are not in the code itself can originate from:
The compiler suite itself sets it as a default when you start compiling your code.
You give the compiler (or preprocessor, to be exact) a list of those definitions when you compile the code (or your IDE project preferences do, when you are using an IDE. For example, in Visual Studio 2013 you will find those when you open Project > Properties > Configuration Properties > C/C++ > Preprocessor > Preprocessor Definitions).
In general, those definitions are not only used for the reason you describe (as include guards), but also to enable or disable code based on the platform you develop for - for example, you can have code branches only compiled for windows, or only if you are using a 64 bit compiler.
You might want to take a look at some predefined compiler macros
Microsoft
AFAIK this is part of the compiler you use.
The Microsoft C++ compiler internally defines some macros such as WIN32, that's why it's not defined in any particular header. So when you build a source file with VC++ the stuff in inside #ifdef WIN32 gets compiled, but not on say Linux gcc.
Also your nomenclature is a bit off -- these are called preprocessor macros, not symbols. The names of the variables, functions, etc in your code are symbols.
Each compiler has a list of defined macros. MSVC defines WIN32 when compilation target is 32-bit Windows.

Adding a preprocessor #define to change which headers are included and which functions are called

I'm developing a game engine for Sega Dreamcast and Windows. I have implemented my own library for the Dreamcast hardware, which pretty much does the same thing as OpenGL for PC. Now, I want to merge the two builds into one project, so I don't need to dev to different project doing the exact same high level stuff.
I know you can add a preprocessing line like this: #define DREAMCAST, and then the Dreamcast headers will be included and the appropriate low level function will be called instead of OpenGL. This has been done before, but I don't know how to make that possible.
This has really nothing to do with Dreamcast, it could be Mac, Linux or whatever. I have different compilers for each platform. So when #define DREAMCAST, I want the G++ KOS compiler to include the Dreamcast-specific headers and classes. If #define DREAMCAST is not present, I want MingGW to include the Windows OpenGL headers and classes.
How can I do this?
For the initial problem of including different versions depending on a predefined symbol, a simple solution is available:
#if defined(DREAMCAST)
#include <my_dreamcast_header>
#else
#include <opengl_header>
#endif
This functionality should be available on just about any C or C++ compiler - and it definitely is on MinGW. You still need to invoke the correct compiler yourself of course, as there is no way to change the compiler once compilation starts.

Dynamic libraries; how to fix useless dependencies?

I have a bunch of Dll's in my project, using VStudio 9.0 compiler, pre-compiled headers are used for all my Dll's. The dll's loading process is done by implicit caller (.dll, .lib and header must be supplied).
I typically create a different macro definition file per dll, for instance if my current Dll is called MYMacroDll I add a file _MyMacroDll.h which contains:
#ifndef _MYMACRODLL_H_
#define _MYMACRODLL_H_
#ifdef _WIN32
#ifdef MYMACRODLL_EXPORTS
#define MYMACRODLL_API __declspec(dllexport)
#else
#define MYMACRODLL_API __declspec(dllimport)
#endif
#define MYMACRODLL_CALL __cdecl
#else
#define MYMACRODLL_API
#define MYMACRODLL_CALL
#endif
#endif
I know the code can be simplified but I keep the last defines for portability, at least, that's what I understood...
The pre-compiled header file pch.h, will always include the macro definition file _MyMacroDll.h, this makes things easier to me, 'cause later I can decide whether a new class or function will be interfaced or not. This so far works correct.
The confusion comes from using the dll interfaces in another dll; let's suppose a second dll ImageLoaderDll. This one uses instances or references of one (or several) of the interfaced classes/functions in _MyMacroDll. At first glance I guessed there was no need of including the _MyMacroDll.h, but when compiling the ImageLoaderDll it complains with
error C2470: '_AnInterfaceClassFromMyMacro' : looks like a function definition, but there is no parameter list; skipping apparent body
Then I have to include the _MyMacroDll.h in the pre-compiler header file of the other Dll, my project is becoming really messy and I find more and more useless dependencies.
What am doing wrong? Is there another way of setting up the macro definitions so I can avoid adding it to the client Dll's? Am not an expert regarding software design, but in this situation the more decoupled the better.
Hope my explanation was good enough.
If you are using the DLL interface from MyMacroDll in ImageLoaderDll, then you do have a dependency. ImageLoaderDll should include _MyMacroDll.h, otherwise you can't call its functions correctly. It's exactly the same as including <string.h> when you want to call strlen.

Making sure same configuration is used for library and executable

let's say I am distributing a library as binary. It is shipped in two versions, debug and release. Debug and release are incompatible with each other, so if e.g. the user builds a release executable, he/she must link with release library.
If there is a mismatch between library and executable versions, currently there will be subtle errors that are really hard to figure out. I would instead like to show a really clear error message that informs there is a mismatch, preferably at link time.
What would be a good way to achieve this?
I'm going to assume that you are using a static library and by binary you mean a .lib that will be linked at compile time (as opposed to a dll or the like that might be mismatched at run-time).
Seems to me the easiest way is to have this sort of a construct in your .h file
#ifdef _RELEASE //or whatever your compiler uses
#define InitialiseLibrary InitialiseLibraryRelease
#else
#define InitialiseLibrary InitialiseLibraryDebug
#endif
Similarly in the cpp file of the library:
#ifdef _RELEASE //or whatever your compiler uses
void InitialiseLibraryRelease()
{
CommonInitialise();
}
#else
void InitialiseLibraryDebug()
{
CommonInitialise();
}
#endif
Now in the main exe which is using the library:
InitialiseLibrary();
If the release-ness of the library and exe don;t match then the linker will report not matching one or other InitialiseLibrary... function.
A different option is to ensure that the release and debug libraries compile to differently named files and then get the link to work using #pragma in the .h file (as opposed to explicitly including the library in a project).
Using the #ifdef as above you can select at compile time which library to link by choosing which #pragma is used. This second technique doesn't exactly address your question (as it doesn't STOP the link happening if the programmer tries to force it) but it is a normal way of dealing with difficulties of this sort (and has advantages in complex build environments)
Could also checksum the binaries/libraries in your install script. Not a C answer, though.
Use #error directive, that will abort the compilation:
#ifndef RELEASE_VERSION
#error Release version required
#endif