Newbie-Frage zum Verlinken einer C-Library in C++ Code
-
Hallo zusammen,
ich starte gerade mit C++, da ich meine Diplomarbeit darin verfassen werde. Ich habe bisher nur Erfahrung mit .NET, Java, Assembler, und diversen davon abhängigen Sprachen, daher stehe ich bei dem aktuellen Problem wahrscheinlich aufgrund mangelnder Erfahrung seit Tagen auf dem Schlauch.
Die Firma in der ich arbeite, entwickelt für das Simulationsprogramm "Robcad" eigene Plugins, die immer in C verfasst wurden. Dazu steht mir eine "Schablone", also quasi ein "Leerprojekt" zum Starten zur Verfügung. Dieses ist in C geschrieben. Ich habe das Projekt nun so weit angepasst, dass ich C-Code in den Headern inExtern "C"{ }
Bereiche einsetze. Die Kompilierung mit dem C++ Compiler von MS VisualC++ ist nun kein Problem mehr, jedoch der Linker-Vorgang.
Wichtig ist dabei, dass in das Projekt eine DLL eingebunden wurde, die rose_uil.dll mittels der rose_uil.lib Library. Dies habe ich unter den "Additional Dependencies" im Compiler eingetragen. Was unter C wunderbar funktioniert, endet unter C++ beim Linken mit folgenden Fehlern, mit denen ich absolut nichts anfangen kann:main.cpp Linking... vid_main.obj : error LNK2019: unresolved external symbol "int __cdecl uiRun(void)" (?uiRun@@YAHXZ) referenced in function _main vid_main.obj : error LNK2019: unresolved external symbol "int __cdecl apExit(void)" (?apExit@@YAHXZ) referenced in function _main vid_main.obj : error LNK2019: unresolved external symbol "int __cdecl uiBusyCursor(int)" (?uiBusyCursor@@YAHH@Z) referenced in function _main vid_main.obj : error LNK2019: unresolved external symbol "int __cdecl vidInit(void)" (?vidInit@@YAHXZ) referenced in function _main
all diese Funktionen (uiRun() z.b.) sind Funktionen, die aus der mit dem Programm Robcad mitgelieferten rose_uil.dll stammen. Diese werden ja in der .lib Datei, die ich eingebunden habe, deklariert. Dennoch findet der Linker sie nicht, also keine einzige der Funktionen aus der rose_uil.dll kann von mir benutzt werden. Was mache ich falsch, und wie löse ich dieses Problem? Wäre nett, wenn jemand Ideen hat, ich bin für alles dankbar!
der Code, in dem ich die Funktionen aufrufe, sollte ja an sich unwichtig sein, dennoch:
#include <aptypes.h> #include <appublic.h> #include <uipublic.h> #include <uierr.h> #include "../inc/vid_prot.h" #ifdef R_ROUTINE #undef R_ROUTINE #endif #define R_ROUTINE "main" int main ( int argc, char **argv) { /* app_name = Name der Applikation */ /* rsrc_name = Name von dem UIL-Modul Dateinamen ohne .uil Endung. */ /* top_menu = Name des Haupmenues, das im UIL-Modul deklariert wurde. */ char *app_name = "testing"; char *rsrc_name = "testing"; char *top_menu = "AppME"; /* Initialisierung der ROBUIL Umgebung */ if (!uiInitApp(app_name, rsrc_name, top_menu, uiTermCommand, vidSwitchIn, vidSwitchOut)){ erWrite(ER_INIT_UIL); return C_FALSE; } /* Initialisierung der ROBAPI Struktur */ if (!apInit()){ erWrite(ER_INIT_APP); return C_FALSE; } /* Setzen der Icons und einiger Grundeinstellungen (Setup) */ if ( !vidInit()) { (void)uiBusyCursor( C_FALSE );/* System ist untätig */ (void)apExit(); return C_FALSE; } uiRun(); return C_TRUE; } #undef R_ROUTINE
-
Bezeichner wie "?uiRun@@YAHXZ" (den Namen erzeugt der Compiler aus "int __cdecl uiRun(void)")hören sich aber nicht nach extern "C" Bindung an. Wie sieht denn der Header aus, in dem die Funktion dekalriert ist?
-
zu den funktionen habe ich wie gesagt keine sourcen oder header, sie stammen wie gesagt alle aus der
rose_uil.dll bzw rose_uil.lib - die ich dem compiler mitgebe..
die wurde eben zu developer-benutzung mit dem programm robcad mitgeliefert. diese bibliothek bietet eben mit den funktionen die schnittstelle zur kommunikation mit dem hauptprogramm - diese sind natürlich auch nicht per extern "C" ummantelt, die möglichkeit habe ich ja gar nicht (da keine sourcen vorhanden)
-
Hallo,
der Header in dem die Funktionen wie uiRun und apExit deklariert sind muss wie folgt auf gebaut sein:#ifdef _cplusplus extern "C" { #endif // Funktionsdeklarationen #ifdef _cplusplus } #endif
Ist er das?
-
Sorry, zu spät
-
Zu jeder .lib-Datei braucht man in C++ (und eigentlich auch in C) unbedingt eine .h-Datei, sonst hagelt es Fehler
. Ein richtiger C++-Compiler wird für jegliche undeklarierte (oder nicht korrekt deklarierte) Bezeichner Fehler ausgeben
. Also ist schon für das Kompilieren mind. 1 Header(.h)-Datei erforderlich. Der Linker beschwert sich, wenn Funktionen mit der falschen Linkage (z. B. C++-Linkage statt C-Linkage) verwendet werden, da dann u. a. die Aufrufkonventionen/Namen der Funktionen nicht passen. Ich hoffe, diese Information ist hilfreich zur Lösung Deines/Ihres Problems.
-
DrOetker schrieb:
zu den funktionen habe ich wie gesagt keine sourcen oder header
Zumindest die Header benötigst du schon, schließlich muß der Compiler irgendwoher wissen, wie die Funktion deklariert ist. Wenn er das nicht hat, würde ein vernünftiger Compiler einen Fehler melden wegen nichtdeklarierten Bezeichnern.
(ein unvernünftiger Compiler nimmt an, daß du irgendwo eine int xyz(void) Funktion hast - allerdings mit C++ Linkage)PS: Notfalls schreibst du dir selber einen Header, in dem du alle Bibliotheksfunktionen deklarierst. Die Vorlage dazu hat HumeSikkins ja geliefert.
-
HumeSikkins schrieb:
Sorry, zu spät
Warum ?
Heißt das Präprozessorsymbol, das C++-Kompilation anzeigt, nicht__cplusplus
(mit doppltem Unterstrich am Anfang, also reserviert für Compiler-Spezifika)
?
-
zuerst: du ist ok
zweitens: eine header datei existiert leider nicht! die dokumentation der schnittstelle beschreibt jedoch, dass die library für c++ und c benutzbar ist / geschrieben wurde.
wie komme ich weiter? wie gesagt, kompiliere ich die datei als C-code, werden die links korrekt gesetzt!die stelle, an der ich die .lib einbinde, ist wie gesagt in den einstellungen des linkers:
Additional Dependencies: (...), $(ROBCAD)/bin/rose_uil.lib
kann ich die header datei ggf. selbst erstellen, oder automatisiert erstellen lassen mittels eines externen tools?
_________________
EDIT:da ich ja weiss, wie die funktion deklariert sein muss, habe ich auch bereits versucht, die funktion in einem header selbst zu deklarieren. jedoch meldet mir der compiler dann einen Error, und zwar, dass ein konflikt bestünde, da die funktion bereits an vorhergehender stelle deklariert worden sei (was ich ziemlich paradox in hinblick auf das problem empfinde)...
-
Du kannst ihn selbst erstellen, indem du alle Funktionsdeklarationen aus deiner Dokumentation raussuchst und in eine Datei reinpackst (vergiss "das extern "C"{...}" drumherum nicht). Oder du fragst (wenn möglich) den Autor der Bibliothek, ob er dir den Header gibt.
-
okay. also konkret dazu:
ich habe nun noch einmal eine header datei erstellt mit folgendem inhalt:
#ifdef __cplusplus extern "C"{ #endif extern int uiRun ( void ); #ifdef __cplusplus } #endif
uiRun ist wie oben beschrieben zu deklarieren.
wenn ich jetzt kompiliere, meldet der compiler (nicht der linker) einen fehler, und zwar:error C2732: linkage specification contradicts earlier specification for 'uiRun'
interpretiere ich das richtig, wenn das bedeutet:
1. die funktion uiRun() wurde von mir falsch deklariert?
-> der fehler in meinem ersten posting lautet dochunresolved external symbol "int __cdecl uiRun(void)" (?uiRun@@YAHXZ) referenced in function _main
- daraus schliesse ich (und auch aus der benutzung im sourcecode), dass meine hier stehende deklaration richtig sein muss?
2. die deklaration fand bereits zuvor einmal statt, nur wo?? ich denke, die funktionsdeklarationen werden nicht gefunden??
-
@Linux-und-Win32-User
Das "zu spät" schrieb ich, da meine Antwort *nach* der Antwort des OPs kam, in der er schrieb, dass er keinen Header hat. Insofern hilft es nicht, wenn ich sage, was in den Header (den er ja nicht hat) zusätzlich rein muss.
-
okay, also der tip mit der header datei hat mich mal auf die suche durch das interne netzwerk geschickt, und siehe da, ich habe doch einige header dateien, die zu der dll gehren, gefunden! (obwohl angeblich keine vorhanden sein sollten
)
ich habe dabei auch eine header datei
ui_prot.h
gefunden, in der besagte funktionen deklariert sind! die deklarationen sind dabei auch schon mit
extern "C"
ummantelt. die schlechte nachricht: leider, wenn ich diese nun einbinde, verändert sich an den fehlermeldungen überhaupt nichts. die funktionen sind angeblich noch immer nicht deklariert. weiss jemand weiter?
-
Offenbar hast du die Funktion doch schon irgendwo in einem anderen Header eingetragen. Klick mal mit der rechten Maustaste auf 'uiRun' und dann auf "gehe zu Deklaration...", um herauszufinden, wo das ist.
-
erstmal danke für eure geduld.
also, ich habe mich nun noch einmal durch das projekt durchgewühlt und etwas bemerkt..
ich versuche, das noch einmal strukturiert wiederzugeben, plus dem, was ich vorher übersehen habe.1. im compiler ist folgendes eingetragen:
C/C++ Compiler/General/Additional include Directories: $(ROBCAD)/rose/inc2. zuvor nicht gesehen: in diesem Verzeichnis befindet sich die besagte Datei "ui_prot.h". Auszug:
#ifndef _ui_prot_h_ #define _ui_prot_h_ #ifdef _cplusplus extern "C" { # ifdef IN # undef IN # define IN const #endif #endif /* _cplusplus */ #ifdef ANSI # define PROTO(s) s # define VA_PROTO(s) s #elif defined(__mips) && (__mips>2) # define PROTO(s) () # define VA_PROTO(s) s #else # define PROTO(s) () # define VA_PROTO(s) () #endif /* init.c */ PUBLIC tBool uiRun PROTO((void )); //<-------------------- hier wird sie deklariert! (...) #undef PROTO #undef VA_PROTO #ifdef _cplusplus # undef IN # define IN } #endif /* _cplusplus */ #endif /* _ui_prot_h_ */
damit muss ich zugeben, bei meiner vorherigen analyse geschlampt zu haben, ihr hattet recht, der header wird eingebunden.
3. in meiner mail.cpp habe ich oben den eintrag:
#include <uipublic.h>
inhalt der uipublic.h:
#include "uitypes.h" #include "ui_prot.h"
damit schliesst sich ja der kreis.
4. zu guter letzt: im linker ist eingetragen (wie bereits vorher genannt):
Input: $(ROBCAD)/bin/rose_uil.lib
Also, zusammenfassend: der Header mit Funktionsdeklarationen wird eingebunden,
die .lib wird eingebunden,
die Code-Kapselung mit "extern "C" " ist auch vorhanden.CStoll hatte damit natürlich recht, die Funktion wurde deklariert, und zwar wie oben beschrieben in der "ui_prot.h", eingebunden durch die "uipublic.h" in meine "main.cpp".
@CStoll: zu deiner bitte, ich klicke mit der rechten maustaste auf die funktion, und dann auf "go to definition", bekomme jedoch die meldung, dass das Symbol uiRun nicht definiert sei (dasselbe wenn ich auf "go to declaration" klicke).
Ideen???
-
-
#ifdef _cplusplus
Ändere das mal nach:
#ifdef __cplusplus
(zwei Unterstriche). Das ist der richtige Namen und auch nur den kennt z.B. der VC 2005.
-
ah, danke erstmal, kann ich erst morgen probieren. ich hoffe, das wirds sein!