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


Anmelden zum Antworten