Fixing multiple definition error when using third party library (OpenGA) - c++

I'm fairly new to c++, and I'm using this project as a learning experience. I'm working in Visual Studio 2019, and I'm using this library
https://github.com/Arash-codedev/openGA
to try to solve a version of the vehicle routing problem.
I've run into a problem when refactoring my code into separate classes once it got unwieldy including everything in a single cpp file, although a single file was the approach outlined in the OpenGA library's examples.
Currently the bare bones structure that seems to be causing the problem is as follows.
Algorithm.cpp
#include "Crossover.h"
#include "EvaluateSolution.h"
...
Crossover.h
#include "GeneticStructs.h
...
EvaluateSolution.h
#include GeneticStructs.h
...
GeneticStructs.h
#include openga.hpp
...
The external library has the following definition:
openga.hpp
...
std::mutex mtx_rand;
...
GeneticStructs just has Chromosome and Gene structs with overloaded ostream operators for each.
The problem is when I compile, I get the following linker errors:
Crossover.obj : error LNK2005: "class std::mutex EA::mtx_rand" (?mtx_rand#EA##3Vmutex#std##A) already defined in Algorithm.obj
EvaluateSolution.obj : error LNK2005: "class std::mutex EA::mtx_rand" (?mtx_rand#EA##3Vmutex#std##A) already defined in Algorithm.obj
GeneticStructs.obj : error LNK2005: "class std::mutex EA::mtx_rand" (?mtx_rand#EA##3Vmutex#std##A) already defined in Algorithm.obj
So from what I understand, I'm violating the one definition rule. I think I understand why. The mutex gets defined separately in each object file and results in ambiguity when the linker tries to combine the object files. Of course, exposition on what is actually wrong would be welcome, since I'm a newbie to c++.
What would be the proper way to resolve something like this? I think the context should be clear from the outline I've given, but if more is necessary please let me know! Thank you.

This is not your fault; it looks like a bug in that OpenGA library.
The normal way would be to declare the variable in the header as:
extern std::mutex mtx_rand;
Then have one (and only one) source file (e.g. OpenGA.cpp) in which it's defined, taking the namespace into account:
#include "OpenGA.hpp"
NS_EA_BEGIN
std::mutex mtx_rand;
NS_EA_END
Of course, this is not needed if the header is included in one (and only one) source file, which is presumably the way the library's author has been using it.
Since the mutex is only used to protect the std::mt19937_64 rng inside the Genetic template, it might also work to just move the mutex declaration into that template as well. I haven't checked if that would break anything, though.

Thank you very much for using openGA.
This issue has been currently fixed. Please include the openGA in this way:
source1.cpp
#include "openGA.hpp"
...
source2.cpp
#define OPENGA_EXTERN_LOCAL_VARS
#include "openGA.hpp"
...
source3.cpp
#define OPENGA_EXTERN_LOCAL_VARS
#include "openGA.hpp"
...
Except for only one source file, at the beginning of all other source files that use openGA, define macro OPENGA_EXTERN_LOCAL_VARS. Then, you should not get such a linker error.
The mechanism of fix works as follows
#ifdef OPENGA_EXTERN_LOCAL_VARS
extern std::mutex mtx_rand;
#else
std::mutex mtx_rand;
#endif

Related

Recursion in includes (file 1 includes file 2 that includes file1)

I have been looking around but I have not found any question that really helps me to solve this issue. I am not very experienced, so maybe this problem is trivial and it is a question of my lack of knowledge.
I am trying to solve an issue. Our system has a Logger that takes different logs and puts them into a SharedMemory.
However, from one of our classes (a StateMachine) I can not use the Loogger because of recursion:
Logger.h includes SharedMemory.h
SharedMemory.h includes StateMachine.h
If I include Logger.h in StateMachine.h, compile errors appear everywhere. First i was trying to fix this problem by creating a second SharedMemory that is dedicated exclusively to the Logger and don't include StateMachine.h.
With this approach, the compilation errors were solved, but my manager does not like this design solution.
I have also tried to change include order, and to declare class before the include but it is not working (e.g. declare class SharedMachine; before #include SharedMachine.h)
The includes are like this:
In the StateMachine.h
#ifndef SM_H
#define SM_H
#include <map>
/* (different includes) */
#include Logger.h
In the Logger.h
#include SharedMemory.h
In the SharedMemory.h
#include StateMachine.h
I would like to know if there is any trick that I can use to make the includes work in this way, without architectural changes (that my manager seems not to like).
Try to move includes from header files to source (*.cpp) files
Use forward declarations: What are forward declarations in C++?
Change interfaces to work with pointers or references to needed types instead of using actual types, to make possible using forward declaration (if needed)

Using a class as the value for a STL map - Undefined Symbol

I'm using Embarcadero RAD Studio XE C++ Builder. I'm having a little problem getting my STL map to work correctly.
#ifndef BbTabManagerH
#define BbTabManagerH
#include "BbSeExplorer.h"
#include "BbTabPage.h"
#include <map>
#define TAB_MANAGER_MAX_TABS 7
class TBbSeExplore;
typedef std::map<std::string, BbTabPage> TabPageMap;
typedef std::map<std::string, BbTabPage>::iterator TabPageMapIt;
My problem is on the following line:
typedef std::map<std::string, BbTabPage> TabPageMap;
This gives me a compiler error:
[BCC32 Error] BbTabManager.h(13): E2451 Undefined symbol 'BbTabPage'
Full parser context
stdafx.h(229): #include ..\src***\Gui\Utilities\BbTabPage.h
BbTabPage.h(5): #include ..\src***\Gui\Frames\BbSeExplorer.h
BbSeExplorer.h(10): #include ..\src****\Gui\Utilities\BbTabManager.h
I find this weird, I included 'BbTabPage.h', which declares the class 'BbTabPage', so where does the undefined symbol come from?
I tried doing a forward declaration like this:
class BbTabPage;
But that doesn't seem to make much of a difference, except that it gives me a whole lot more compiler errors. The strange thing is that if I change it to a pointer:
typedef std::map<std::string, BbTabPage*> TabPageMap;
Everything compiles just fine.
This problem is driving me nuts, I've been trying to find a solution for hours. Are there some kind of requirements a class must comply with to be used as a value in a map?
Look like a problem with circular includes
BbTabPage.h includes BbSeExplorer.h
BbSeExplorer.h includes BbTabManager.h
BbTabManager.h includes BbTabPage.h
So the first time you hit your typedef BbTabPage has not been defined because the include guard from the partly processed BbTabPage.h prevents BbTabManager.h from including BbTabPage.h.
The answer is to reorganize your headers so they don't have a circular include. If two classes are completely dependent on each other then it's best to put them both in the same header file, so you can control more carefully what gets seen in what order.

undeclared identifier in C++ Visual Studio 2008

I have a C++ project in Visual Studio 2008.
In the project I have several forms and several non-form classes. One non-form specifically called Import_LP.h that is a class with several methods all of which are written in the header file with nothing in the resource file.
I have no problem with #include Import_LP in any of the form classes and creating objects and referencing any of its methods, however any other class I try to #include it into, it gives me a
syntax error : undeclared identifier 'Import_LP'
on the line it is referenced occurs ie Import_LP^ importLP;
I come from a java/c# background is there something I'm missing with the linking here?
If you have include guards, it goes like this: the preprocessor includes Import_LP.h, which says "only include me once", then includes Window.h, which tries to include Import_LP.h, but doesn't because of the include guard. So Window.h starts parsing the window class, but fails because the Import_LP.h class header hasn't fully loaded yet.
The solution is to predeclare the classes:
Window.h:
#ifndef WINDOW_H //works best if this is first
#define WINDOW_H
#pramga once
class Import_LP;
class Window {
Import_LP* member; //member has to be a pointer
void func();
};
#include "Import_LP.h"
inline void Window::func() {
}
#endif WINDOW_H
Import_LP.h:
#ifndef IMPORT_LP_H //works best if this is first
#define IMPORT_LP_H
#pramga once
class Window;
class Import_LP {
void func(Window& parent); //parameter has to be a pointer or reference
};
#include "Window.h"
inline void Import_LP::func(Window* parent) {
}
#endif IMPORT_LP_H
This will only allow you to reference the other by pointer or reference until the actual include, but that should be doable. Technically you only have to do this to one or the other headers.
I was able to resolve the problem by random chance.
So apparently you can't have two files include each other?
I was doing
#include Window.h
in Import_LP.h
and
#include Import_LP.h
in Window.h.
I would appreciate it if someone could explain to me why you can't do this.
Sounds like the type Import_LP is undefined, your challenge is to figure out why. First thing to do is to read the contents of import_LP.h and figure out how Import_LP is declared. One possible approach would be to open one of the good files, right click on a use of Import_LP and select "Go To Declaration". That should move the focus to the declaration of Import_LP that applies in that specific case.
It could be the declaration is surrounded by a #ifdef that somehow prevents it being compiled in your other files. Or it could be something else, we don't really have enough details to work with.
Update:
So apparently you can't have two files include each other?
. . .
I would appreciate it if someone could explain to me why you
can't do this.
You can end up defining types and variables more than once when you do that.
There are techniques like #include guard and #pragma once which may be used to mitigate these sorts of problems.

Another C++ was not declared in this scope error

Several questions has been asked related to this error, but each one of them practically relates to the object or type in question not declared before usage. For example:
class A
{
public:
A_Object a_obj;
};
Getting the error A_Object was not declared in this scope means A_object is not declared anywhere within the file.
NOTE: This is my understanding of the error.
Now I have a file called Account.h as shown below:
#ifndef ACCOUNT_H_
#define ACCOUNT_H_
class Account
{
//fields and methods
};
#endif /* ACCOUNT_H_ */
I also have a second file called Address.h as shown below:
#ifndef ADDRESS_H_
#define ADDRESS_H_
#include "Account.h"
typedef Account account_type;//Error here
class Address
{
//Fields and methods
};
#endif /* ADDRESS_H_ */
When I try to compile this file I get the error Account was not declared in this scope.
Any Ideas why?
Does Account.h actually also include Address.h? Such a circular reference seems the most likely situation.
Do you have a matching #endif at the end of both include files?
First point, your understanding about A_object is incorrect, the error means that A_object was not declared prior to it's first use, not that it wasn't declared anywhere.
Second point, the code you posted is incorrect, because you are missing #endif from both files. But assuming that was the only missing code then you would not get the error you describe. Post the real code that has the error.
I've seen this error when Address.h includes Account.h, which includes OtherFile.h, which includes Address.h. Is it possible you have a circular dependency? It may be hard to find.
This might be a case where a more core understanding of how the c/c++ compiler works would be in order. Include blocks, forward declarations, includes etc. All of these concepts did not make sense to me until I understood the basics of how compiler works. While I realize that this is somewhat of an oversimplification of compiler theory / logic, bear with me.
One of the first steps that a c++ compiler performs is a pre-processing (pre-compiler) step where it takes all of the files that are required, and combines them into one big flat file. In "C" languages, these pre-compiler operations a denoted using the hash (#) symbol. All an "#include" is doing, is directing the pre-compiler to bring this file into the entire "flat-file". If you have a cyclic include, your pre-compiler will get into an infinite loop and blow up, or say something super generic and useful like "the symbol has already been defined".
Include blocks, forward declarations, and all of the neat things that you are taught in c++ books that say "just do it, trust me" generally are helping you to avoid these type of compiling problems.

Clarification on a header without #includes

I was reading some code from the Doom 3 SDK ( in a VS solution ) when I found a header like this:
#ifndef __PLAYERICON_H__
#define __PLAYERICON_H__
class idPlayerIcon {
public:
idPlayerIcon();
~idPlayerIcon();
...... // omitted
public:
playerIconType_t iconType;
renderEntity_t renderEnt;
qhandle_t iconHandle;
};
#endif /* !_PLAYERICON_H_ */
The header has no forward class declaration nor #includes so, in my experience it should lead to an error like: Undeclared Identifier or Syntax error, cause renderEntity_t and qhandle_t are not "seen".
So how can this compile correctly?
Thank you in advance for the answers.
Because every time it is included, the needed entities are forward declared/included right before it, so everything is defined at the point of inclusion. As you correctly say, it will not work any other way.
I guess they include other headers before including this one.
Since this is a header file it's likely there is an order to their includes elsewhere (where this file is used perhaps?). As long as renderEntity_t and qhandle_t make it into the symbol table prior to this file being included it doesn't matter.
Is there something called stdafx.h? Most VS projects have these.
It would simply be a header that includes all the needed files for your application to reduce compile time from including headers.
So it would contain something like this:
#ifndef _STDAFX_H_
#define _STDAFX_H_
#include "playerIconAndOtherVariables.h"
#include "thatFileYouListed.h"
#endif