Matroids Matheplanet Forum Index
Moderiert von Bilbo
Matroids Matheplanet Forum Index » Informatik » C++ unresolved external symbol beim Linken gegen DLL
Autor
Universität/Hochschule C++ unresolved external symbol beim Linken gegen DLL
Wolti
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 17.05.2004
Mitteilungen: 110
Wohnort: Rhede, Deutschland
  Themenstart: 2023-02-04

Hallo zusammen. Ich schreibe gerade ein CMake Script für ein C++ Projekt: https://github.com/wo80/essentia/tree/cmake Das Projekt kann ich mit Visual Studio problemlos statisch linken. Wenn ich allerdings eine DLL baue und dann versuche gegen die DLL zu linken, bekomme ich einen Fehler. Der folgende Beispielcode ergibt die Fehlermeldung: \sourceon test.obj : error LNK2001: unresolved external symbol private: static class a::Factory * a::Factory::_instance \sourceoff Unter Linux und MinGW ist das dynamische Linken mit GCC kein Problem. Mir ist bewusst, dass man mit Visual C++ z.B. keine statischen Variablen aus DLLs exportieren kann. Das wird im Code aber auch gar nicht versucht und im main-Programm wird auch nicht direkt auf _instance zugegriffen. Der Beispiel-Code ist vorläufig hier als ZIP erhältlich: http://wo80.bplaced.net/files/factory-test.zip Einfach mit CMake bauen (Symbol shared=On für dynamisches Linken): \sourceon cmake -B build -S . -Dshared=On cmake --build build \sourceoff Meine Fragen: 1) Warum beschwert sich der Visual C++ Linker, GCC aber z.B. nicht? 2) Wie müsste die Implementierung geändert werden, so dass das Linken auch unter Visual Studio funktioniert? Gruß, Christian --- Hier der Code: \showon config.h \sourceon cpp #ifndef CONFIG_H #define CONFIG_H #if DLL_EXPORTS # define EXPORT __declspec(dllexport) #else # define EXPORT #endif #endif // CONFIG_H \sourceoff a.h \sourceon cpp #include "config.h" namespace a { EXPORT void init(); EXPORT void shutdown(); namespace foo { EXPORT void registerAlgorithms(); } namespace bar { EXPORT void registerAlgorithms(); } } \sourceoff a.cpp \sourceon cpp #include #include "a.h" #include "factory.h" namespace a { namespace foo { void registerAlgorithms() { std::cout << "a::foo:registerAlgorithms()" << std::endl; } } namespace bar { void registerAlgorithms() { std::cout << "a::bar:registerAlgorithms()" << std::endl; } } bool _initialized; void init() { foo::AlgorithmFactory::init(); foo::registerAlgorithms(); bar::AlgorithmFactory::init(); bar::registerAlgorithms(); std::cout << "a::init()" << std::endl; _initialized = true; } void shutdown() { foo::AlgorithmFactory::shutdown(); bar::AlgorithmFactory::shutdown(); std::cout << "a::shutdown()" << std::endl; _initialized = false; } template<> foo::AlgorithmFactory* foo::AlgorithmFactory::_instance = 0; template<> bar::AlgorithmFactory* bar::AlgorithmFactory::_instance = 0; } \sourceoff algorithm.h \sourceon cpp #ifndef ALGORITHM_H #define ALGORITHM_H #include "config.h" namespace a { namespace foo { class EXPORT Algorithm { public: void process() {} }; } // namespace foo namespace bar { class EXPORT Algorithm { public: void process() {} }; } // namespace bar } // namespace a #endif // ALGORITHM_H \sourceoff factory.h \sourceon cpp #ifndef FACTORY_H #define FACTORY_H #include #include #include "a.h" namespace a { template class EXPORT Factory { static Factory* _instance; public: static void init() { if (!_instance) { _instance = new Factory(); std::cout << "a::Factory::init()" << std::endl; } } static void shutdown() { delete _instance; _instance = nullptr; std::cout << "a::Factory::shutdown()" << std::endl; } static Factory& instance(); protected: // protected constructor to ensure singleton. Factory() {} }; } #include "algorithm.h" namespace a { namespace foo { typedef Factory AlgorithmFactory; } namespace bar { typedef Factory AlgorithmFactory; } } // include implementation, because the factory is now templated #include "factory_impl.h" #endif // FACTORY_H \sourceoff factory_impl.h \sourceon cpp #ifndef FACTORY_CPP #define FACTORY_CPP namespace a { template Factory& Factory::instance() { if (!_instance) { throw std::runtime_error("Factory not initialized."); } return *_instance; } } #endif // FACTORY_CPP \sourceoff test.cpp \sourceon cpp #include "factory.h" using namespace a::foo; int main() { a::init(); AlgorithmFactory& factory = AlgorithmFactory::instance(); a::shutdown(); } \sourceoff CMakeLists.txt \sourceon cmake_minimum_required(VERSION 3.16.0) project(factory_test VERSION 1.2.3 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) if (DEFINED shared) set(BUILD_SHARED_LIBS "${shared}") endif () if(BUILD_SHARED_LIBS) #add_compile_definitions(DLL_EXPORTS) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) endif() add_library(factory) target_include_directories(factory PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") target_sources(factory PRIVATE a.cpp a.h config.h algorithm.h factory.h factory_impl.h) add_executable(test test.cpp) target_link_libraries(test PUBLIC factory) \sourceoff \showoff


   Profil
ElMachete
Senior Letzter Besuch: im letzten Quartal
Dabei seit: 08.12.2009
Mitteilungen: 727
  Beitrag No.1, eingetragen 2023-02-05

Hallo Wolti, Du bist auf einer der fundamentalen Unterschiede zwischen den beiden Welten gestossen. Per Default werden von GCC alle Symbole exportiert, während MSVC (Visual Studio) keine exporiert. Streng genommen müsstest Du auf Klassen- und Funktionsebene regeln, was exportiert respektive importiert werden soll: siehe etwa die GCC-Doku für ein Beispiel wie man das plattformunabhängig hinbekommt (der mit "please read" markierte Abschnitt ist wichtig!). Als Abkürzung tut es möglicherweise auch diese CMake-Option. Dein Makro für Export/Import schaut mir noch nicht ganz richtig aus. Mit besten Grüssen, Dominik


   Profil
Wolti
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 17.05.2004
Mitteilungen: 110
Wohnort: Rhede, Deutschland
  Beitrag No.2, vom Themenstarter, eingetragen 2023-02-05

Hallo Dominik. Ich habe sowohl den üblichen Weg über __declspec(dllexport) (alle relevanten Klassen sind damit versehen, insbesondere die Factory Klasse) als auch mit CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS versucht. Das Folgende (in Kurzform) sollte ja eigentlich reichen: \sourceon cpp template class EXPORT Factory { static Factory* _instance; public: static Factory& instance(); }; \sourceoff D.h. ich müsste so ja eigentlich auch über eine DLL auf Factory::instance() zugreifen können. Edit: Zum Ex-/Import Makro: auch mit __declspec(dllimport) funktioniert es nicht (außerdem sollte hier natürlich noch zwischen MSVC und anderen Compilern unterschieden werden). \sourceon cpp #ifdef DLL_EXPORTS #define EXPORT __declspec(dllexport) #else #define EXPORT __declspec(dllimport) #endif \sourceoff Gruß!


   Profil
Wolti
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 17.05.2004
Mitteilungen: 110
Wohnort: Rhede, Deutschland
  Beitrag No.3, vom Themenstarter, eingetragen 2023-02-05

Es scheint nun zu laufen. Ich habe 1) statt factory_impl.h in factory.h zu inkludieren eine factory.cpp Datei angelegt (wie es sich eigentlich gehört). 2) statt Factory::instance() zu implementieren, die beiden Typen (definiert über typedefs) im foo und bar namespace implementiert: \sourceon cpp foo::AlgorithmFactory& foo::AlgorithmFactory::instance() { if (!_instance) { throw std::runtime_error("foo::AlgorithmFactory not initialized."); } return *_instance; } bar::AlgorithmFactory& bar::AlgorithmFactory::instance() { if (!_instance) { throw std::runtime_error("bar::AlgorithmFactory not initialized."); } return *_instance; } \sourceoff Der Beispielcode kompiliert und läuft. Mal schauen ob es auch mit dem eigentlichen Projekt läuft. Ich lasse das Thema mal noch offen, falls es noch Anmerkungen gibt... Danke bis hierher, Gruß, Christian


   Profil
Wolti hat die Antworten auf ihre/seine Frage gesehen.

Wechsel in ein anderes Forum:
 Suchen    
 
All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest © 2001-2023 by Matroids Matheplanet
This web site was originally made with PHP-Nuke, a former web portal system written in PHP that seems no longer to be maintained nor supported. PHP-Nuke is Free Software released under the GNU/GPL license.
Ich distanziere mich von rechtswidrigen oder anstößigen Inhalten, die sich trotz aufmerksamer Prüfung hinter hier verwendeten Links verbergen mögen.
Lesen Sie die Nutzungsbedingungen, die Distanzierung, die Datenschutzerklärung und das Impressum.
[Seitenanfang]