How to make sure different C++ code base using the same macro? - c++

We are working on two C++ code base, let's call it A and B, the A is an build as an library, and distribute the header files .h and .a file to B.
Let's say there is Lock.h file in A as following:
// Lock.h in code base A
class Lock {
... ...
#ifdef TRACK_THREAD_OWNER_FOR_DEBUG
virtual int GetLockOwner();
#endif
... ...
private:
CriticalSection section;
#ifdef TRACK_THREAD_OWNER_FOR_DEBUG
int threadOwner;
#endif
};
// Caller.cc in code base B
#include "xxx/xxx/Lock.h"
Lock lockObject;
lockObject.Lock();
In code base A, we by default will enable TRACK_THREAD_OWNER_FOR_DEBUG and may change it just before final release day.
We hit some hard bug because TRACK_THREAD_OWNER_FOR_DEBUG are different in A and B, and cause memory corruption because the sizeof(Lock) is different in two library.
So how to protect from this error? Can we trigger an compiler error when build the caller.cc file if the build macro TRACK_THREAD_OWNER_FOR_DEBUG is different in two project?

It is not possible to make this into compiler error, however it should be possible to make this into reasonably clear linker error by exporting some symbol which name depends on the currently defined macros. For example using static guard variable:
// Foo.hpp - library header file
#pragma once
class Foo
{
public: Foo();
#ifdef IMPORTANT_CONDITION
int m_field;
#endif
};
class ConditionGuard
{
public:
ConditionGuard(void) noexcept
{
#ifdef IMPORTANT_CONDITION
CONDITION_ON();
#else
CONDITION_OFF();
#endif
}
#ifdef IMPORTANT_CONDITION
private: static void CONDITION_ON(void);
#else
private: static void CONDITION_OFF(void);
#endif
};
static ConditionGuard const condition_guard{};
// Foo.cpp - library implementation file
#include "Foo.hpp"
Foo::Foo(void) {}
#ifdef IMPORTANT_CONDITION
void ConditionGuard::CONDITION_ON(void) {}
#else
void ConditionGuard::CONDITION_OFF(void) {}
#endif
Now when user code includes library header Foo.hpp it will also trigger construction of condition_guard static variable which will call a library function depending on condition being protected. So if there is a translation unit including Foo.hpp where IMPORTANT_CONDITION is defined differently than in compiled library then there will be a linker error for missing CONDITION_ON or CONDITION_OFF. CONDITION_ON and CONDITION_OFF function names should contain error text.

One option is to just include the full code for A into project B. What are you trying to do by compiling A into a static library?
I think you're best option is to generate different .a files depending the target. i.e. libA_debug.a when TRACK_THREAD_OWNER_FOR_DEBUG is set, libA.a when it is not.
Then you could set the library to link B to based on whether you are compiling a debug or release version.

Related

Dll export symbol of function from static linked library

I am wrapping a static library in Dll to hide a lot of the implementation stuff since only 4-5 functions are needed and to avoid providing all third-party libraries and many header files. I seem to be having an issue with exporting a function to the dll from the static lib.
The static lib has settings classes / structs similar to the one below
struct FooSettings
{
bool Read(const std::string& file); // implemented in .cpp
bool Write(const std::string& file); // implemented in .cpp
// rest members, just plain types
};
In the Dll side
#include "FooSettings.h"
#if defined(WIN32) || defined(_WIN32)
#if defined(LIB_EXPORT)
// DLL Build, exporting symbols
#define LIB_API __declspec(dllexport)
#elif LIB_IMPORT
// DLL use, importing symbols
#define LIB_API __declspec(dllimport)
#endif
#endif
#ifndef LIB_API
#define LIB_API
#endif
class LIB_API LibSDK
{
public:
LibSDK();
~LibSDK();
FooSettings get() const noexcept;
void set(const FooSettings& settings) const noexcept;
void dummy()
{
foo.Read("");
}
private:
// etc...
};
I can call dummy() on the "client" side without any issues
but the code below leads to unresolved symbols
FooSettings foo;
foo.Read("");
I would have expected that the FooSettings:Read is at least exported since it is part of a dummy function. Am I missing something ? My preference is to export it without the dummy function but I dont seem to be able to make it work either way.
Coming back to all this, the answer was actually to #define LIB_EXPORT in the static library build as well which I did not expect.
I did not think that such a thing would be needed for a static .lib files since all they are is just a bundle of object files so they did not need to be marked for export. Apparently, it was needed if you want to export the functions from the static lib to your wrapper dll.

C++ CRITICAL_SECTION object in .dll gives unresolved external symbol error

I'm currently developing a game that comes in two parts: the engine is in a .dll and the actual game code is part of an .exe. The engine, among other header files, contains one that manages all components, ranging from Win32 specific objects and pointers to D3D11. These components are included in a class that allows them to be accessed globally via a function that returns a reference to it. Furthermore, for every item it manages there are two functions that allow the component to be set or to be returned. I also added a thread protection using a critical section.
So, in State.h I have:
#if defined(NF3D_NONCLIENT_BUILD)
#define NF3D_API __declspec(dllexport)
#else
#if defined(__MINGW32__)
#define NF3D_API NF3D_API
#else
#define NF3D_API __declspec(dllimport)
#endif
#endif
...
#endif
...
extern NF3D_API CRITICAL_SECTION CriticalSection;
class NF3D_API NF3DLock
{
public:
#pragma prefast( suppress:26166, "Thread safeness is enabeled." )
FORCEINLINE _Acquires_lock_(CriticalSection) NF3DLock(void) { EnterCriticalSection(&CriticalSection); }
#pragma prefast( suppress:26165, "Thread safeness is enabeled." )
FORCEINLINE _Releases_lock_(CriticalSection) ~NF3DLock(void) { LeaveCriticalSection(&CriticalSection); }
};
class NF3D_API STATE
{
public:
...
inline void SetMember(int val) { NF3DLock Lock; Elements.Member = val; }
inline int GetMember(void) { NF3DLock Lock; return Elements.Member; }
private:
struct ELEMENTS
{
int Member;
} Elements;
}
FORCEINLINE NF3D_API STATE* NF3DGetEngineState(void);
In State.cpp I initialise and delete the critical section but also:
CRITICAL_SECTION CriticalSection;
...
FORCEINLINE NF3D_API STATE* NF3DGetEngineState(void)
{
static STATE s_State;
return &s_State;
}
Calling 'NF3DGetEngineState' inside the .dll causes no problems and the compilation runs perfectly, but if I use this function outside the engine, inside the application I get a linker error in the .exe:
2>Main.obj : error LNK2001: unresolved external symbol "struct _RTL_CRITICAL_SECTION NewFrontiers3D::CriticalSection" (?CriticalSection#NewFrontiers3D##3U_RTL_CRITICAL_SECTION##A)
The engine is included in a namespace called 'NewFrontiers3D'.
This error intrigued me even more when I declared 'extern NF3D_API CRITICAL_SECTION CriticalSection' as static, as it compiled fine but gave an access violation exception when entering the critical section in the constructor of NF3DLock. Also, if I remove 'EnterCriticalSection' and LeaveCriticalSection' the linker errors disappear. I don't know what is happening and why is it happening and that's why I'm addressing this question to anybody who might be able to help me.
Update:
From the line:
#define NF3D_API __declspec(dllexport)
it looks like you are always exporting, and never importing (which you should do when the header is included from external projects).
For example, compile your code using defining NM3D_API_EXPORTS macro (if I am not mistaken: -d option.
And, then, in the header define NM3D_API in the following way:
#ifdef NM3D_API_EXPORTS
#define NM3D_API __declspec(dllexport)
#else
#define NM3D_API __declspec(dllimport)
#endif
Original Post:
Include's work in a very dumb way. They take whole contents of the file you are including, and paste them over the include statement.
This is why, when you are trying to include this header to a different project, that project doesn't know about your declaration in previous .dll. Since it was done in a different file, about which your other project knows nothing about.

Preventing "already defined" error for class implementation in header file

I want to include the definition and implementation of a C++ class in a header file.
I'm creating a library that need to be C-compatible. The .h file defines a C++ class that can be subclassed for easy C++-style access to the library. It is internally used in the library as well.
As the header file is imported into several subclasses, I always get the "multiple definition" error. Because the class definition should be importable for users of the library, I do not want to move the implementation in a separate cpp file.
Do you have any idea how this problem can be solved?
simplified example:
//library:
typedef struct IFoo{
virtual void foo = 0;
};
void library_fun_a(IFoo*);
void library_fun_b(IFoo*);
//header file
#pragma once
class FooWrapper : public IFoo{
virtual void foo() override;
};
void FooWrapper::foo(){
//some magic here
}
[Edit] Using include guards doesn't help to stop the compile from including the implementation in all object files and therefore the linker to encounter the "multiple definition" error.
You must use include guards which are essentially just macros that determine if the compiler has already included the interface or whatever contents are in the header file.
For example
#ifndef FOO_WRAPPER_H
#define FOO_WRAPPER_H
// header contents here ...
#endif // !FOO_WRAPPER_H
If you're using a Microsoft compiler, you can use the directive #pragma once at the top of the header file. Note that this breaks compatibility with other compilers.
You can easily solve your multiple defintion problem when you inline your code correctly:
class FooWrapper : public IFoo {
virtual void foo() override {
//some magic here
}
};

Encapsulating static libraries in dynamic-link libraries (DLL)

I'm trying to increase my understanding of basic library linking, dependencies, etc. I created a Visual Studio solution with three projects
Static lib using /MTd with a single class (Foo), one method int GetNum() { return 5; }
Shared dll using /MDd with a single class (Bar), one method int GetNum() { Foo f; return f.GetNum(); }
Win32 console app. That calls Bar b; std::cout << b.GetNum() << std::endl
When I tried to build this, it complained it couldn't find my dll's associated lib. Did a little research, saw that I needed to add __declspec(dllexport) to my GetNum() method and I'd get a .lib. Cool.
Next hurtle was the console app said it couldn't find the static lib for Foo. I added it to my references and it all build and ran fine.
My question is - why does my exe need to know anything about Foo? I wanted to effectively "bake" in all my dependencies into the dll so I could just share that, link into it, and be good to go.
Is this just not how the language works or a setting / pattern I'm missing? My end goal is to be able to build a dll that encapsulates the usage of third party .lib's and not have the client app need to worry about adding references to all of them.
Update
Here is most of the code.
// ---------------------- Lib (e.g. Foo)
#pragma once
class MathLib
{
public:
MathLib(void);
~MathLib(void);
int GetNum() { return 83; }
};
// ---------------------- DLL (e.g. Bar)
#pragma once
#ifdef CONSOLETEST_EXPORT
#define CONSOLETEST_API __declspec(dllexport)
#else
#define CONSOLETEST_API __declspec(dllimport)
#endif
#include "MathLib.h"
class MathDll
{
public:
__declspec(dllexport) MathDll(void);
__declspec(dllexport) ~MathDll(void);
__declspec(dllexport) int GetNumFromDyn()
{
MathLib m;
return m.GetNum();
}
};
// ---------------------- exe
int _tmain(int argc, _TCHAR* argv[])
{
MathDll m;
std::cout << "num is " << m.GetNumFromDyn() << std::endl;
return 0;
}
With C/C++, it's very important to structure your code properly across headers (e.g. h, hpp, hxx, h++, etc.) and translation units (usually called sources, e.g. c, cpp, cxx, c++, etc.). When you design a library, you should be constantly thinking what belongs to its interface (i.e. supposed to be seen by consumers) and what belongs to its implementation (i.e. not supposed to be seen by consumers).
Remember the rule of thumb - all symbols that are present in any header will be seen by consumers (if included), and, as a result, required by consumers to be resolved during linking stage at some point in time later!
This is essentially what happened to you in your toy example. So let's fix it by using a simple rule, which you should remember by heart: Put as much as possible into translation units, i.e. keep headers minimal. Now let's use your example to show how it works:
MathLib.hpp:
#pragma once
class MathLib {
public:
MathLib();
~MathLib();
int GetNum();
};
MathLib.cpp:
#include "MathLib.hpp"
MathLib::MathLib() {}
MathLib::~MathLib() {}
int MathLib::GetNum() { return 83; }
Now build MathLib.cpp as static library.
MathDll.hpp:
#pragma once
#ifdef CONSOLETEST_EXPORT
# define CONSOLETEST_API __declspec(dllexport)
#else
# define CONSOLETEST_API __declspec(dllimport)
#endif
class CONSOLETEST_API MathDll {
public:
MathDll();
~MathDll();
int GetNumFromDyn();
};
MathDll.cpp:
#include "MathDll.hpp"
#include "MathLib.hpp"
MathDll::MathDll() {}
MathDll::~MathDll() {}
int MathDll::GetNumFromDyn() {
MathLib m;
return m.GetNum();
}
Now build MathDll.cpp as dynamic-link library (DLL) and don't forget to add definition CONSOLETEST_EXPORT during its build, so that CONSOLETEST_API is __declspec(dllexport), and, as a result, an import library with exported symbols (i.e. the MathDll class and its methods) is generated for the DLL. On MSVC you can achieve this by adding /DCONSOLETEST_API to the invocation of compiler. Finally, when building this DLL, certainly link it with previously built static library, MathLib.lib.
NOTE: It's better to export the whole class like I did above with class CONSOLETEST_API MathDll, rather than export all methods individually.
main.cpp:
#include "MathDll.hpp"
#include <iostream>
int _tmain(int argc, _TCHAR* argv[]) {
MathDll m;
std::cout << "num is " << m.GetNumFromDyn() << std::endl;
return 0;
}
Now build main.cpp as console application and only link it with previously built import library for DLL, MathDll.lib.
Notice how the problem is gone because I've got rid of transitive dependency to MathLib (through MathDll.hpp) from main.cpp, since now the #include "MathLib.hpp" inclusion is done in the translation unit MathDll.cpp (because it's actually only needed there according to above rule), and is therefore built into binary artifact (DLL in this case) and not present in its interface.
Understanding all of this is really important for proper native software development with C/C++, so it's really good that you ask this question beforehand. I meet people who don't know/understand this quite often, what results in complete nightmare for them (amateurs), and us, when we have to deal with that crappy software they write...
Consider the case when MathLib is a part of MathDll class.
//MathDll.h
#include "MathLib.h"
class MathDll
{
private:
MathLib m;
public:
__declspec(dllexport) MathDll(void);
__declspec(dllexport) ~MathDll(void);
__declspec(dllexport) int GetNumFromDyn()
{
return m.GetNum();
}
};
you will have to now include MathLib.h into your MathDll.h, which propagates to the console app too.
You can avoid this...
By using PIMPL idiom to encapsulate everything into the DLL.
Provide the forward declaration of the class MathLib in the header and the rest of the implemenation hidden in the Dll. You can also consider exporting the whole class.
//------------MathDll.h
// we do not include "MathLib.h" here. include it in the MathDll.cpp only
class MathLib;
class __declspec(dllexport) MathDll
{
private:
MathLib* m;
public:
MathDll(void);
~MathDll(void);
int GetNumFromDyn();
};
//--------------MathDll.cpp
#include "MathLib.h"
#include "MathDll.h"
MathDll::MathDll(void)
{
m = new MathLib();
}
MathDll::~MathDll(void)
{
delete m;
}
int MathDll::GetNumFromDyn()
{
return m->GetNum();
}

C++ cross-platform development to avoid preprocessor directives

I need to maintain a project that supports running on Linux and Windows. Some codes using preprocessor directives like this are fine.
#ifdef _WIN32 // _WIN32 is defined by Windows 32 compilers
#include <windows.h>
#else
#include <unistd.h>
#endif
But some are the actual implementation, which I would like to prevent using preprocessor directives.
void Foo()
{
#ifdef _WIN32 // _WIN32 is defined by Windows 32 compilers
code for windows
#else
code for Linux
#endif
some common code...
#ifdef _WIN32 // _WIN32 is defined by Windows 32 compilers
code for windows again
#else
code for Linux again
#endif
}
So things get convoluted and harder to maintain. Is there any better way?
The traditional way is to "hide" all the code that is specific to any OS in wrapper functions - you can either do that in complete functions that do a higher level functionality - e.g. have a function that returns all directory entries based on a given path as input, or implement the individual base-functions, e.g. start_read_directory(path), read_dir_entry(), end_read_directory() - that's just an example functionality, the same principle(s) can be applied on almost any system specific functionality. Wrap it enough, and you wouldn't be able to tell what you are programming for.
In essence, you are doing it wrong if you have a lot of #ifdef in the code itself.
Handle the OS specifics from the build system, not the code. For instance, have two versions of Foo.cpp: one that gets compiled on Linux and another on Windows. Ideally, the header file will be common and all function signatures identical.
You can use a simplified version of the factory pattern.
Have a common interface
class MyClass
{
public:
virtual void Foo() = 0;
};
And for each platform you create a specific class
#import <windows.h>
class MyClassWindows : MyClass
{
public:
virtual void Foo() { /* Do something */ }
};
#import <linux.h>
class MyClassLinux : MyClass
{
public:
virtual void Foo() { /* Do something */ }
};
Then when you need this class, you use your factory:
class MyClassFactory
{
public:
static MyClass* create()
{
#if defined _WIN32
return new MyClassWindows();
#elif defined _LINUX
return new MyClassLinux();
#endif
}
}
There a many variants of this methods, including defining the MyClassFactory::create method in the .cpp of each platform-specific class and only compiling the .cpp for the appropriate platform. This avoids all preprocessing directives, the switching is made by choosing the correct implementation file.
A common pattern would be to provide system independent header files, and platform-specific implementation files.
Nothing platform specific in the header:
class Foo
{
...
};
In two different implementation files, foo_linux.cpp
Foo::Foo() { .. linux code }
foo_windows.cpp
Foo::Foo() { .. windows code }
and maybe platform independent implementation in foo.cpp
void Foo::plat_independent_function()
Your platform builds then link in foo.cpp and foo_platform.cpp
A possibility for the implementation of this is to use the PIMPL idiom, where your class just publishes the "interface" and declares a meaningless pointer to an implementation class (in its dark, hidden and private corner) and the build system takes care of pulling in the correct platform dependent code for the class containing the implementation of your PIMPL.