Linker Problem unter Windows/Cygwin
-
Hallo!
Ich experimentiere gerade mit Klassenladern rum und versuche den Code von folgendem Artikel
http://www.linuxjournal.com/article/3687
unter Windows/Cygwin mit dem GCC Compiler (g++) zum laufen zu bringen. Hier die Codes:testdcl.cpp
#include <iostream> #include <map> #include <list> #include <vector> #include <string> #include <dlfcn.h> #include <stdio.h> #include <unistd.h> #include "shape.hpp" using namespace std; // size of buffer for reading in directory entries static unsigned int BUF_SIZE = 1024; // our global factory for making shapes map<string, maker_t *, less<string> > factory; int main(int argc, char **argv){ FILE *dl; // handle to read directory char *command_str = "ls *.so"; // command // string to get dynamic lib names char in_buf[BUF_SIZE]; // input buffer for lib // names list<void *> dl_list; // list to hold handles // for dynamic libs list<void *>::iterator itr; vector<string> shape_names; // vector of shape // types used to build menu list<shape *> shape_list; // list of shape // objects we create list<shape *>::iterator sitr; map<string, maker_t *, less<string> >::iterator fitr; // get the names of all the dynamic libs (.so // files) in the current dir dl = popen(command_str, "r"); if(!dl){ perror("popen"); exit(-1); } void *dlib; char name[1024]; while(fgets(in_buf, BUF_SIZE, dl)){ // trim off the whitespace char *ws = strpbrk(in_buf, " \t\n"); if(ws) *ws = '\0'; // append ./ to the front of the lib name sprintf(name, "./%s", in_buf); dlib = dlopen(name, RTLD_NOW); if(dlib == NULL){ cerr << dlerror() << endl; exit(-1); } // add the handle to our list dl_list.insert(dl_list.end(), dlib); } int i = 0; // create an array of the shape names for(fitr=factory.begin(); fitr!=factory.end(); fitr++){ shape_names.insert(shape_names.end(), fitr->first); i++; } int choice; // create a menu of possible shapes to create and let the user make some while(1){ i = 1; for(fitr=factory.begin(); fitr!=factory.end(); fitr++){ cout << i << " - Create " << fitr->first << endl; i++; } cout << i << " - Draw created shapes\n"; i++; cout << i << " - Exit\n"; cout << "> "; cin >> choice; if(choice == i){ // destroy any shapes we created for(sitr=shape_list.begin(); sitr!=shape_list.end();sitr++){ delete *sitr; } // close all the dynamic libs we opened for(itr=dl_list.begin(); itr!=dl_list.end(); itr++){ dlclose(*itr); } exit(1); } if(choice == i - 1){ // draw the shapes for(sitr=shape_list.begin(); sitr!=shape_list.end();sitr++){ (*sitr)->draw(); } } if(choice > 0 && choice < i - 1){ // add the appropriate shape to the shape list shape_list.insert(shape_list.end(), factory[shape_names[choice-1]]()); } } }
shape.hpp
#ifndef __SHAPE_H #define __SHAPE_H #include <map> #include <string> using namespace std; // base class for all shapes class shape { public: virtual void draw()=0; }; // typedef to make it easier to set up our factory typedef shape *maker_t(); // our global factory extern map<string, maker_t *, less<string> > factory; #endif // __SHAPE_H
square.hpp
#ifndef __SQUARE_H #define __SQUARE_H #include "shape.hpp" class square : public shape { public: void draw(); }; #endif // __SQUARE_H
sqare.cpp
#include <iostream> #include "square.hpp" void square::draw(){ // simple ascii square cout << "\n"; cout << " *********\n"; cout << " * *\n"; cout << " * *\n"; cout << " * *\n"; cout << " * *\n"; cout << " *********\n"; cout << "\n"; } extern "C" { shape *maker(){ return new square; } class proxy { public: proxy(){ // register the maker with the factory factory["square"] = maker; } }; // our one instance of the proxy proxy p; }
circle.hpp
#ifndef __CIRCLE_H #define __CIRCLE_H #include "shape.hpp" class circle : public shape { public: void draw(); }; #endif // __CIRCLE_H
circle.cpp
#include <iostream> #include "circle.hpp" void circle::draw(){ // simple ascii circle cout << "\n"; cout << " ****\n"; cout << " * *\n"; cout << " * *\n"; cout << " * *\n"; cout << " * *\n"; cout << " * *\n"; cout << " ****\n"; cout << "\n"; } extern "C" { shape *maker(){ return new circle; } class proxy { public: proxy(){ // register the maker with the factory factory["circle"] = maker; } }; // our one instance of the proxy proxy p; }
GNUmakefile
CC = g++ LIBS = -ldl %.o: %.cpp g++ -ggdb -c $< default: make testdcl OBJS = testdcl.o testdcl: testdcl.o $(CC) -rdynamic -o testdcl testdcl.o $(LIBS) libcircle.so: circle.o g++ -shared -Wl,-soname,libcircle.so -o libcircle.so circle.o libsquare.so: square.o g++ -shared -Wl,-soname,libsquare.so -o libsquare.so square.o all: testdcl libcircle.so libsquare.so clean: rm -f *.so *.o testdcl testdcl.exe
Wenn ich das nun unter Cygwin übersetzen will kommt als Ausgabe:
$ make all g++ -ggdb -c testdcl.cpp g++ -rdynamic -o testdcl testdcl.o -ldl g++: unrecognized option `-rdynamic' g++ -ggdb -c circle.cpp g++ -shared -Wl,-soname,libcircle.so -o libcircle.so circle.o circle.o: In function `proxy': /cygdrive/c/Dokumente und Einstellungen/Maik/Desktop/test1/circle.cpp:23: undefined reference to `_factory' collect2: ld returned 1 exit status make: *** [libcircle.so] Error 1
Offensichtlich sucht er halt beim linken die Variable factory, die es ja zu diesem Zeitpunkt nicht gibt, da sie ja erst zur Laufzeit zur Verfügung stehen wird. Das sollte ja eigentlich das "extern" in der shape.hpp erklären. Weiß jemand, wie ich das zum laufen bekommen kann? Liegt es vielleicht an dem unbekanten -rdynamic (zu dieser Option hab ich nirgends was gefunden).
Ich habe es heute auch einmal unter einem Debian-Linux probiert, da funktioniert alles wie es soll...
Vielen Dank und Grüße,
Maik