Cmake Shared_Lib Link Problem

Yo du hast recht, die "Solution" is a bissl zu groß zum austesten.

Ich werde am Montag eine minimal version des ganzen bauen und dann schauen ob und wies funktioniert, dann sind die wege hoffentlich auch besser nachvollziehbar.

--> So das Problem hat mich nicht in Ruhe gelassen, bin daher heut gleich noch schnell ins Büro gefahren und habe diese Testversion aufgesetzt.

Stellvertredend für Toolbox und TMSTools habe ich mit CMAKE zwei VS 08 Projekte erstellt welche genau den Vorgang nachempfinden sollen (DLLExport) (DLLImport).

Daher:
DLLExport soll seine eine Klasse ExportClass in eine precomiled library verpacken, welche dann von ImportClass in DLLImport verwendet werden soll (ohne sie neu zu kompilieren).
Ich bekomme zurzeit die selbe Fehlermeldung wie gestern, vielleicht kannst du es aber mit diesen Files besser nachvollziehen!

Ich hänge zwei Archive an. Das eine beinhaltet die fertigen VS08 Projekte, das andere nur die c++ files mit dazugehöriger CMakeLists.txt.

mittel dieser kannst du mittels des Programms http://www.cmake.org/ eine Solution für deinen Compiler erstellen.

Wünsche weiterhin noch ein schönes Wochenende,
lg,
Andreas
 

Anhänge

  • DLLExport_VS08.zip
    111,1 KB · Aufrufe: 19
  • DLLExport_CmakeOnly.zip
    3,2 KB · Aufrufe: 21
Zuletzt bearbeitet:
Ok, ich habe nur die C++ Codes genommen. Dann habe ich deine DLL erstellt. Doch wenn ich den anderen Code erstellen will, sagt MinGW (habe eine Klasse TAuto implementiert):
Code:
C:\...\import\main.cpp|11|error: aggregate `TAuto a' has incomplete type and cannot be defined

Doch bei einer Funktion:
Code:
obj\Release\main.o:main.cpp:(.text+0x3d)||undefined reference to `SquareNumber'|

Jetzt bin ich selber verwirrt!!
 
hmm

wieso main.cpp ? in den zwei bibs gabs ja gar keine main.cpp da es ausschließlich zwei Funktionsbibliotheken sein sollten.


Vielleicht ist beim erstellen mit CMAKE was schiefgelaufen?

... ich komme immer noch nicht dahinter warum er die dll nicht erkennt, denn in der Solution implementiert er sie, er findet den entry point, aber wenn ich die Klasse über die DLL_EXPORT funktion importieren möchte erkennt er sie nacher nicht .... :confused:
 
Ich mir nochmals ein eigenes Projekt gemacht. Habe aber mit MinGW kompiliert.

Vielleicht kann ja ein anderer helfen. Ich bin jetzt ech überfragt. Aber vielleicht kann ich morgen besser denken ;)

Vielleicht ist beim erstellen mit CMAKE was schiefgelaufen?
Meiner Meinung, kann kein Computer auf dieser Welt was Falsches machen. Entweder ist der Programmierer oder der Anwender schuld! :)

EDIT: Ich glaube, das Problem hängt mit Klassen zusammen. Denn bei meiner Google-Recherche wegen diesem Fehler bin ich darauf gestoßen, das die Deklaration woanders sein muss. Mehr habe ich aber nicht erfahren, naja...
 
Zuletzt bearbeitet:
Hi.

@GreedyRaccoon: Du solltest evtl. mal ein paar Tutorials bzw. die Hilfe von CMake lesen.

CMake definiert automatisch eine ${PROJECT_NAME}_EXPORTS Präprozessorvariable wenn eine DLL erstellt wird.

Du hast die DLLExport Bibliothek im DLLImport Projekt nochmal definiert, was einfach Unfug ist.

Du hast die ExportClass.h Datei nicht in ImportClass.cxx eingebunden. Es ist unsinnig die Klassen im DLLImport Projekt zu definieren.

Du darfst die DLLDefines.h nicht in beiden Projekten unterschiedlich definieren bzw. keine Include-Guards verwenden. So ist die DLLImport DLL unbrauchbar, da DLL_EXPORT global auf dllimport gesetzt ist und man so . Am besten definierst du für jede Bibliothek eine eigene DLL_EXPORT Variable.

Code:
# DLLImport CMakeList.txt

PROJECT(DLLImport)
cmake_minimum_required(VERSION 2.6)

# Use the include path and library for Qt that is used by VTK.
INCLUDE_DIRECTORIES(
  ${CMAKE_CURRENT_BINARY_DIR}
  ${CMAKE_CURRENT_SOURCE_DIR}
  ../DLLExport
)

# ************************************************************************************
# ------------------- Main Program with User Interface -------------------------------
# ************************************************************************************

SET (DLLImportSrcs
	DLLDefines.h
	ImportClass.h
	ImportClass.cxx
)


#----------------------------------
LINK_DIRECTORIES(../DLLExport/release/)
FIND_LIBRARY(DLLEXPORT_VAR "DLLExport"  ../DLLExport/release/)

# ----- LINK SELF --------------
ADD_LIBRARY( DLLImport SHARED ${DLLImportSrcs})
SET_TARGET_PROPERTIES(DLLImport PROPERTIES LINKER_LANGUAGE CXX)

TARGET_LINK_LIBRARIES( DLLImport ${DLLEXPORT_VAR})
C:
// DLLExport DLLDefines.h 
#ifdef DLL_EXPORT
#  undef DLL_EXPORT
#endif

#ifdef DLLExport_EXPORTS
#  define DLL_EXPORT  __declspec(dllexport)
#else
#  define DLL_EXPORT __declspec(dllimport)
#endif
C:
// DLLImport DLLDefines.h
#ifdef DLL_EXPORT
#  undef DLL_EXPORT
#endif

#ifdef DLLImport_EXPORTS
#  define DLL_EXPORT  __declspec(dllexport)
#else
#  define DLL_EXPORT __declspec(dllimport)
#endif
C++:
// ImportClass.cxx
#include "ImportClass.h"
#include "ExportClass.h"

...
Gruß
 
Guten Morgen!
Vielen Dank für den Input.


Code:
# DLLImport CMakeList.txt

PROJECT(DLLImport)
cmake_minimum_required(VERSION 2.6)

# Use the include path and library for Qt that is used by VTK.
INCLUDE_DIRECTORIES(
  ${CMAKE_CURRENT_BINARY_DIR}
  ${CMAKE_CURRENT_SOURCE_DIR}
  ../DLLExport
)

# ************************************************************************************
# ------------------- Main Program with User Interface -------------------------------
# ************************************************************************************

SET (DLLImportSrcs
	DLLDefines.h
	ImportClass.h
	ImportClass.cxx
)


#----------------------------------
LINK_DIRECTORIES(../DLLExport/release/)
FIND_LIBRARY(DLLEXPORT_VAR "DLLExport"  ../DLLExport/release/)

# ----- LINK SELF --------------
ADD_LIBRARY( DLLImport SHARED ${DLLImportSrcs})
SET_TARGET_PROPERTIES(DLLImport PROPERTIES LINKER_LANGUAGE CXX)

TARGET_LINK_LIBRARIES( DLLImport ${DLLEXPORT_VAR})
Genau so eine CmakeLists.txt hatte ich bevor ich das hier beschriebenen Problem anfing. Das Problem mit dem Header einbinden (#include ExportClass.h) ist, dass bei jedem Kompiliervorgang die exportClass neu kompiliert wird. Bei größeren Projekten wird es mühsam die grundlegenden Klassen die sich nicht mehr ändern jedesmal neu kompilieren zu müssen.

Deshalb wollte ich eine precompiled SHARED Library, grundlegender Funktionen, erzeugen, aus der ich ohne neu kompilieren zu müssen die Klassen verwenden kann. (in C# ging das ohne Probleme meine Frage ist wie und ob dies mit C++ und CMAKE funktioniert)

Ich habe soeben diesen Artikel gelesen der schreibt, dass man wie gehabt die *.lib (wie oben stehend) verlinkt UND die dll in die runtime library kopieren muss
http://www.cmake.org/pipermail/cmake/2009-November/033349.html

Code:
.
.
#=============== LINK DLL EXPORT ====================================================
// ----- Link .lib
LINK_DIRECTORIES(../DLLExport/release/)
FIND_LIBRARY(DLLEXPORT_VAR "DLLExport"  ../DLLExport/release/)
ADD_LIBRARY(DLLEXPORT_LIB SHARED   ${DLLEXPORT_VAR})
SET_TARGET_PROPERTIES(DLLEXPORT_LIB PROPERTIES LINKER_LANGUAGE CXX)
set_target_properties(DLLEXPORT_LIB PROPERTIES  LINK_FLAGS "/ENTRY:\"DllMain\"")
//------------------------

//---- Copy .dll to runtime directory
                 INSTALL(FILES ../DLLExport/release/DLLExport.dll
                     DESTINATION ./Release/
                     CONFIGURATIONS Release
                     COMPONENT Applications)

ADD_CUSTOM_TARGET(DLLEXPORT-Release-Copy ALL
                             COMMAND ${CMAKE_COMMAND} -E
			copy_if_different ../DLLExport/release/DLLExport.dll
                        ${CMAKE_CURRENT_SOURCE_DIR}/Release/     
                        COMMENT "Copying ../DLLExport/release/DLLExport.dll to ${CMAKE_CURRENT_SOURCE_DIR}/Release/"

                             )
#===================================================================================
.
.

So weit so gut ... er kopiert die dll in das directory, jetzt muss ich nur noch schaffen die klassen einzubinden
lg,
Andreas
 
Zuletzt bearbeitet:
Genau so eine CmakeLists.txt hatte ich bevor ich das hier beschriebenen Problem anfing. Das Problem mit dem Header einbinden (#include ExportClass.h) ist, dass bei jedem Kompiliervorgang die exportClass neu kompiliert wird. Bei größeren Projekten wird es mühsam die grundlegenden Klassen die sich nicht mehr ändern jedesmal neu kompilieren zu müssen.
Der Code sollte sich in den CPP Dateien befinden. Die Header müssen in C++ immer eingebunden werden.

Um die Implementation zu verstecken und (ohne Neukompilieren) ändern zu können kann man in C++ das Pimpl Idiom anwenden. :google:

Wenn du nicht die vollständige Definition der Klassen benötigst (also nur mit Zeigern hantierst), reicht auch eine Vorwärtsdeklaration aus, aber wenn du eine Instanz einer Klasse erstellen willst, muss die vollständige Definition der Klasse vorliegen.

Nochmal zum Mitschreiben. Das hier ist kompletter Unsinn:
Code:
ADD_LIBRARY(DLLEXPORT_LIB SHARED   ${DLLEXPORT_VAR})
SET_TARGET_PROPERTIES(DLLEXPORT_LIB PROPERTIES LINKER_LANGUAGE CXX)
set_target_properties(DLLEXPORT_LIB PROPERTIES  LINK_FLAGS "/ENTRY:\"DllMain\"")
Das hier auch:
Code:
 INSTALL(FILES ../DLLExport/release/DLLExport.dll
                     DESTINATION ./Release/
                     CONFIGURATIONS Release
                     COMPONENT Applications)
Das Install Target wird nicht beim Kompilieren ausgeführt. Es ist dazu da, das endgültige Programm und die Bibliotheken im System zu installieren. Deswegen gehört dieser Code (wenn überhaupt) in das DLLExport Projekt.

Du könntest auch eine statische Bibliothek erstellen, die läßt sich einfacher nutzen.

Gruß
 
Zuletzt bearbeitet:
Der Code sollte sich in den CPP Dateien befinden. Die Header müssen in C++ immer eingebunden werden.
Ok, gibt es eine Möglichkeit die HeaderFiles direkt aus der dll zu beziehen oder müssen die *.h Files immer in einem Directory verfügbar sein?

Um die Implementation zu verstecken und (ohne Neukompilieren) ändern zu können kann man in C++ das Pimpl Idiom anwenden. :google:
*gesucht* klingt super danke für den Tipp!!

Du könntest auch eine statische Bibliothek erstellen, die läßt sich einfacher nutzen.
Yo das habe ich ja vorher gemacht, wollte auf SHARED umsteigen um die Kompilierzeit zu verkürzen, was mich aber offenbar auf einen Irrweg gebracht hat.
 
Ok,

Vermutlich eine blöde Frage, aber was bringt mir die *.dll dann überhaupt wenn es sowieso nur über
Code:
LINK_DIRECTORIES(${DLLEXPORT_PATH})
FIND_LIBRARY(DLLEXPORT_LIB "DLLExport"  ${DLLEXPORT_PATH})

also einbinden des *.lib files und verlinken des HeaderDirectories funktioniert?
 

Neue Beiträge

Zurück