Question: What am I doing to cause a multiple definition symbol linker error?
OSFrameworkWindows10Module.ixx
module;
#include <memory>
export module OSFrameworkWindows10Module;
export class OSFramework {
private:
struct impl;
std::unique_ptr<impl> _impl;
public:
OSFramework();
~OSFramework();
};
typedef struct OSFramework::impl {
impl();
~impl();
} impl;
impl::impl()
{}
impl::~impl() = default;
OSFramework::OSFramework() : _impl{ std::make_unique<impl>() } {}
OSFramework::~OSFramework() = default;
winmain.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
import OSFrameworkWindows10Module;
int WINAPI wWinMain (
_In_ HINSTANCE hinst,
_In_opt_ HINSTANCE,
_In_ PWSTR,
_In_ int
)
{
auto os_framework = std::make_unique<OSFramework>();
return S_OK;
};
compiler output
1>------ Build started: Project: Vegas22Metroidvania1, Configuration: Debug x64 ------
1>Scanning sources for module dependencies...
1>OSFrameworkWindows10Module.ixx
1>Compiling...
1>OSFrameworkWindows10Module.ixx
1>winmain.cpp
1>OSFrameworkWindows10Module.ixx.obj : error LNK2005: "public: __cdecl OSFramework::~OSFramework(void)" (??1OSFramework##QEAA#XZ::<!OSFrameworkWindows10Module>) already defined in winmain.obj
1>D:\projects\Vegas22Metroidvania1\x64\Debug\Vegas22Metroidvania1.exe : fatal error LNK1169: one or more multiply defined symbols found
1>Done building project "Vegas22Metroidvania1.vcxproj" -- FAILED.
Pretty lost here as to why OSFramework::~OSframework() is being counted as defined more than once. I'm somehow instantiating it in my winmain.cpp file even though I'm just setting up a smart pointer for the class instance.
Maybe relevant info: I'm using Visual Studio 17.4.3
This feels like a compiler bug. Here are a list of things that make the compiler cooperate, but none of them should matter:
Declaring the destructor declaration inline (inline ~OSFramework();).
Defining the out-of-line destructor inline (inline OSFramework::~OSFramework() = default;)
Defining the out-of-line destructor with = {} instead of = default;.
Moving the = default; constructor back to within the class definition.
None of these should fix anything. Member functions in modules are not implicitly inline, but that shouldn't cause a multiple-definition error. Importing a module is not like including a header.
And changing from = default; to = {} shouldn't change whether multiple definitions are created.
No, this is a compiler bug. I'd say that you should just = default it inline. It makes the code clearer anyway.
I ended up separating implementation from interface:
winmain.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <memory>
import OSFrameworkWindows10Module;
int WINAPI wWinMain (
_In_ HINSTANCE hinst,
_In_opt_ HINSTANCE,
_In_ PWSTR,
_In_ int
)
{
auto os_framework = std::make_unique<OSFramework>();
return S_OK;
};
OSFrameworkWindows10Module.ixx
module;
#include <memory>
export module OSFrameworkWindows10Module;
export class OSFramework {
private:
struct impl;
std::unique_ptr<impl> _impl;
public:
OSFramework();
~OSFramework();
};
OSFrameworkWindows10.cpp (new)
#include <memory>
import OSFrameworkWindows10Module;
using impl = struct OSFramework::impl {
impl();
~impl();
};
impl::impl()
{}
impl::~impl() = default;
OSFramework::OSFramework() :_impl{ std::make_unique<impl>() } {}
OSFramework::~OSFramework() = default;
compiler output
1>------ Build started: Project: Vegas22Metroidvania1, Configuration: Debug x64 ------
1>Scanning sources for module dependencies...
1>OSFrameworkWindows10Module.ixx
1>Compiling...
1>OSFrameworkWindows10Module.ixx
1>OSFrameworkWindows10.cpp
1>winmain.cpp
1>Generating Code...
1>Vegas22Metroidvania1.vcxproj -> D:\projects\Vegas22Metroidvania1\x64\Debug\Vegas22Metroidvania1.exe
I want to thank #alanbirtles for the tip about the inline keyword when used in a header file, because this got me thinking about how I would normally do this just using a header file and a source file. This allowed me to re-read some blog posts about separating module interface and implementation and better understand what was being discussed.
Related
I encountered a strange behavior for an msvc c++ build while compiling two shared libraries and an executable. The complete setup can be found on GitHub
Information:
platform toolset is v143
4 projects: 1 header only, 2 DLL`s, 1 executable
The 4 projects are:
HeaderOnlyInterface (header only)
Implementation (DLL)
Factory (DLL)
SharedLibsTest (EXE)
Projects 2 - 4 can include all header files from HeaderOnlyInterface.
HeaderOnlyInterface consists of two header files:
DLLExport.h
#pragma once
#ifdef MAKEDLL
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __declspec(dllimport)
#endif
IFoo.h
#pragma once
#include "DLLExport.h"
class EXPORT IFoo
{
public:
virtual ~IFoo() = 0 {}
virtual void Bar() = 0;
};
The next project is Implementation which implements the defined abstract class. This class has MAKEDLL defined as PREPROCESSOR macro. I only show the header because the source is unnecessary:
Foo.h
#pragma once
#include <IFoo.h>
class EXPORT Foo : public IFoo
{
public:
void Bar() override;
};
Going on to Factory, which also defines MAKEDLL and links against Implementation.lib, I have these two files:
FooFactory.h
#pragma once
#include <IFoo.h>
class EXPORT FooFactory
{
public:
static IFoo* Create();
};
FooFactory.cpp
#include "FooFactory.h"
#include <Foo.h>
IFoo* FooFactory::Create()
{
return new Foo();
}
And at the last, I have a main method in an Executable, which links against Factory.lib:
#include <FooFactory.h>
int main()
{
auto* foo = FooFactory::Create();
foo->Bar();
delete foo;
}
For me, the strange thing is, that everything compiles and works fine until now. I have no compile or linker warnings.
The strange thing for me is the compilation and linkage of Factory.lib (and NOT against Implementation.lib).
This library imports a class and exports it also and I do not know why it works. I try to explain my thinking by providing in (pseudo-) code what happens if FooFactory.cpp is pre-processed:
class __declspec(dllexport) IFoo
{
public:
virtual ~IFoo() = 0 {}
virtual void Bar() = 0;
};
class __declspec(dllexport) FooFactory
{
public:
static IFoo* Create();
};
class __declspec(dllexport) Foo : public IFoo
{
public:
void Bar() override;
};
IFoo* FooFactory::Create()
{
return new Foo();
}
The macro is the same for all compiled libs meaning that Factory.lib is exporting all classes. But it does not compile the implementation of Foo::Bar(). Also, it is somehow able to import the implementation because the code works fine. I am not sure why it works, and what really happens under the hood.
If someone could lighten me up on this behavior and also maybe could explain why I should do it not like this or maybe why this is a good idea to do it like this, that would be really helpful.
Thanks!
I got a weird C++ question and have no idea how to resolve it.
I have a public header:
// a.h
#ifdef A_EXPORTS
#define A_API __declspec(dllexport)
#else
#define A_API __declspec(dllimport)
#endif
struct A_API IWorker
{
virtual bool foo() { return false; }
};
I built a.DLL with -DA_EXPORTS.
But my test.exe just needs a mocked IWorker.
// test.cpp
#include "a.h"
class CMockWorker : public IWorker
{
public:
bool foo() override { return true; }
};
I built test.exe, and found it depends on a.DLL because of external symbol public: __cdecl IWorker::IWorker(void) __ptr64
I know that IWorker has a compiler-generated constructor because of the vtbl, but could it be inline so we can get rid of a.DLL?
Thanks!
As #hans-passant mentioned, yes, once I removed the definition of virtual methods, problem resolved.
// a.h
struct IWorker
{
virtual bool foo() = 0;
};
But in existing project, some so-called interface class has similar dummy body and hard to refactor them.
So I really want to find the ideal solution to force-inline the c'tor, if has. Maybe not today, hope it could be impl-ed in the future.
I'm using Visual Studio 2015 Update 2.
I have two headers called Error.h and Game.h.
Error.h:
#ifndef _Error_H
#define _Error_H
#include "Main.h"
#include "Core.h"
#include <Log.h>
#include <CWindows.h>
// ErrorIDs
enum
{
ErrUnknownID = 0,
blah,
blah2,
blah3
};
struct ErrInfo
{
unsigned int eiID;
String strCaption; // String is another class which implemented from std::string which works fine!
String strText;
bool bFixable = false;
};
// Static errors
extern ErrInfo WinNotSupported;
// blah blah
class Error
{
public:
void Initialize();
bool ShowError(ErrInfo ErrorInfo);
BOOL FixError(unsigned int uiErrorID);
// -----------------------------------------
// --------------- Singleton ---------------
// -----------------------------------------
public:
static Error& Instance()
{
static Error instance;
return instance;
}
static Error *InstancePtr()
{
return &Instance();
}
private:
Error()
{
}
public:
Error(Error const&) = delete;
void operator=(Error const&) = delete;
};
#endif // !_Error_H
And Game.h:
#ifndef _Game_H
#define _Game_H
#include "Main.h"
#include "Error.h"
#include "Core.h"
#include <CWindows.h>
#include <AFile.h>
struct missingfileSt
{
String strFileURL;
String strDLFileName;
String strFileName;
String strChecksum;
long long llSize;
ErrInfo errError; // Many errors here <-
};
struct deletablefileSt
{
String strFileName;
ErrInfo errError; // Many errors here too
};
#define siMissingFiles 7
#define siDeletableFiles 5
class Game
{
public:
void ValidateFiles();
DWORD dwGamePID;
missingfileSt mfMissingFiles[siMissingFiles];
deletablefileSt dfDeletableFiles[siDeletableFiles];
// -----------------------------------------
// --------------- Singleton ---------------
// -----------------------------------------
public:
static Game& Instance()
{
static Game instance;
return instance;
}
static Game *InstancePtr()
{
return &Instance();
}
private:
Game()
{
dwGamePID = 0;
}
public:
Game(Game const&) = delete;
void operator=(Game const&) = delete;
};
#endif // !_Game_H
Now, when I compile I get many errors from Game.h and all of them are:
Error C3646 'errError': unknown override specifier
Error C4430 missing type specifier - int assumed. Note: C++ does not support default-int
I got really confused, why errors!?
Also I must say, in header Core.h it will include Error.h again but it mustn't be problem!
An old question already but a useful answer is missing for all C++ newbies or those who are forced to understand (very) bad C++ compiler messages.
If you get "missing type specifier", "unknown override", "undefined type/class", "syntax error: (" (for a beginning function parameter list) although you included the proper header file then it indicates that there is some circular reference in your include-hierarchy. This is also true if you have a forward declaration and the type is still "unknown".
The only solution with the old include-system in C++ is to avoid circular references between #includes. It's achieved by moving #includes from a header file A.h to the A.cpp and by forward declaring the types (or methods) in A.h. If you don't move the #include to A.cpp it still can fail despite forward declaration.
Let A.h be a circular include in B.h because B.h would already be included by A.h. Instead of
#include "A.h"
class B {
A a;
}
you can write
class A;
class B {
A a;
}
and include A.h in your CPP file(s).
You can avoid the need for method forward declarations if you only define methods in CPP files.
I just moved ErrInfo struct to another header with the same include guard and it compiled and worked without problem, I think it's compiler failure, if it isn't please explain.
I've got simple singleton with
class Options {
private:
Options()
{};
Options(Options const&);
void operator=(Options const&);
public:
static Options& get()
{
static Options INSTANCE;
return INSTANCE;
}
};
I've got this definition in header in shared library A
but when I call get() first from application B I see how there instance is creating and then I call methods from shared library C and using get() there I'm getting yet another instance...
How can I have something alike Application level singleton? (is it something with extern keyword?)
It should work under windows provided:
you consistently use __declspec(dllexport) for export and __declspec(dllimport) for import
the implementation of Options::get() is moved in a cpp file so that it only exists in the DLL.
Here is an example :
options.dll build with OPTIONS_EXPORT symbol defined:
options.h:
#pragma once
#ifdef OPTIONS_EXPORTS
#define DLLAPI __declspec(dllexport)
#else
#define DLLAPI __declspec(dllimport)
#endif
class DLLAPI Options
{
private:
Options()
{};
Options(Options const&);
void operator=(Options const&);
public:
static Options& get();
int val;
};
options.cpp:
#include "Options.h"
Options& Options::get()
{
static Options INSTANCE;
return INSTANCE;
}
A dummy c.dll using options.dll build with C_EXPORT symbol defined and linked with options.lib:
c.h:
#pragma once
#ifdef C_EXPORTS
#define dll __declspec(dllexport)
#else
#define dll __declspec(dllimport)
#endif
#include "../a/options.h"
namespace C {
dll Options& relay();
};
c.cpp:
#include "c.h"
Options& C::relay() {
Options& opt = Options::get();
return opt;
}
And a minimal main linked with both options.dll and c.dll:
#include <iostream>
#include "../a/options.h"
#include "../c/c.h"
int main() {
Options& o1 = Options::get();
o1.val = 12;
Options& o2 = C::relay();
std::cout << ((o1.val == o2.val) ? "Ok" : "Ko") << std::endl;
return 0;
}
Output is as expected: Ok
The issue is that all of your applications and libraries compile their own copy of your class into the library, since you tell all of them how the class should look.
First of, start by moving the implementation of theget function into the source file. After this is done and you compile you should see that your shared libraries does not know how the function should look and they will not compile (linker errors except in the library that contains the class).
From there start to fix the compilation by letting the application and other libraries know where to link the function from.
On windows you need to export the class in the library that it is implemented in using __declspec(dllexport).
On the library and possibly the application you need to use __declspec(dllimport) to import the class.
On Linux this should not be necessary.
I have files::
//ClassA.h
#ifndef ClassA_H
#define ClassA_H
#pragma once
class ClassA
{
public:
void func1(){
}
ClassA(void) {
}
~ClassA (void) {
}
};
#endif
//ClassA1.h
#include "ClassA.h"
class ClassA1 {
ClassA<2> b;
};
//ClassA1.cpp
#include "ClassA1.h"
//main_file.cpp
#include "ClassA1.h"
#include "iostream"
int main (int argc , char** argv) {
std::cout<<"in main"<<std::endl;
}
So this compiles fine...As soon as i define function of class ClassA outside the class in Class.h i get following error during build
1> LINK : c:\users\adudeja\documents\visual studio 2010\Projects\Test\Debug\Test.exe not found or not built by the last incremental link; performing full link
1>ClassA1.obj : error LNK2005: "public: void __thiscall ClassA::func1(void)" (?func1#ClassA##QAEXXZ) already defined in main_file.obj
1>ClassA1.obj : error LNK2005: "public: __thiscall ClassA::ClassA(void)" (??0ClassA##QAE#XZ) already defined in main_file.obj
1>ClassA1.obj : error LNK2005: "public: __thiscall ClassA::~ClassA(void)" (??1ClassA##QAE#XZ) already defined in main_file.obj
1>c:\users\adudeja\documents\visual studio 2010\Projects\Test\Debug\Test.exe : fatal error LNK1169: one or more multiply defined symbols found
So what is the difference between defining function outside class and inside class.
Below is the non working code...
#ifndef ClassA_H
#define ClassA_H
#pragma once
class ClassA
{
public:
void func1();
ClassA(void);
~ClassA(void);
};
void ClassA::func1(){
}
ClassA::ClassA(void) {
}
ClassA::~ClassA (void) {
}
#endif
So what is the difference between defining function outside class and inside class.
When you define it in the class body it is implicitly inline, and an inline function can be defined in multiple files.
A non-inline function must be defined exactly once only.
So either put the non-inline definition into a single .cpp file, not in a header included by multiple files, or define it with the inline keyword.
OK, let's see...
In your example, no function is defined outside the class declaration.
Both ClassA1.cpp and main_file.cpp "see" the definition of ClassA. Since all functions defined inside a class declaration are considered inline, i.e. the linker does not see it as a seperate function at all, and has nothing to complain about.
But if you put the definition of e.g. func1() outside the class declaration (but still in ClassA), it's no longer considered inline, it's a seperate function. But as it is still visible to two compilation units, it gets compiled in both translation units.
So when you attempt to link the two object files together, you got two instances of func1(), and the linker complains.
The solution is to either:
define a function inside the class declaration, or
define the function in one seperate translation unit (ClassA.cpp), and link with that.
Using templates limits your options somewhat, as template code must be visible to each translation unit it is used in, i.e. you cannot just declare it in a header and implement it elsewhere, leaving you with only option 1. above.
Post-code-review:
ClassA.hpp:
#ifndef ClassA_HPP
#define ClassA_HPP
class ClassA
{
public:
ClassA();
~ClassA();
void func1();
};
#endif
ClassA.cpp:
#include "ClassA.hpp"
void ClassA::func1()
{
// ...
}
ClassA::ClassA()
{
// ...
}
ClassA::~ClassA()
{
// ...
}
ClassA1.hpp:
#ifndef ClassA1_HPP
#define ClassA1_HPP
#include "ClassA.hpp"
// Your example still assumed that ClassA is a template,
// so I twisted that into an inheritance instead since
// ClassA isn't a template anymore, and if it *were* a
// template, it would change things significantly.
// Perhaps trying too much at once?
class ClassA1 : public ClassA
{
// ...
};
#endif
ClassA1.cpp:
#include "ClassA1.hpp"
// ...
main_file.cpp:
#include "ClassA1.hpp"
#include <iostream>
int main( int argc, char * argv[] )
{
std::cout << "in main" << std::endl;
return 0;
}