Probleme mit dlopen()



  • Dlopen lädt mein modul nicht:

    modul.cpp

    /*
    Writen by Jan Koster releade under lgpl
    
    */
    #include <iostream>
    #include <dlfcn.h>
    #include <string>
    #include "module.h"
    
    using namespace std;
    
    extern string readconf();
    
    bool modul(string modulpath){
    
    char* tmp = new char[modulpath.size() + 1];
    modulpath.copy(tmp,string::npos);
    tmp[modulpath.size()] = 0;
    
    using std::cout;
    using std::cerr;
    
    void* modul = dlopen(tmp, RTLD_LAZY);
    if (!modul) {
            cerr << "Cannot load library: " << dlerror() << '\n';
            return 1;
    }
    
    dlerror();
    
    create_t* create_modul = (create_t*) dlsym(modul, "create");
    const char* dlsym_error = dlerror();
    	if (dlsym_error) {
            	cerr << "Cannot load symbol create: " << dlsym_error << '\n';
    		return 1;
        	}
    
    destroy_t* destroy_modul = (destroy_t*) dlsym(modul, "destroy");
    dlsym_error = dlerror();
    	if (dlsym_error) {
            	cerr << "Cannot load symbol destroy: " << dlsym_error << '\n';
            	return 1;
    	}
    
        module* module = create_modul();
    
        module->sqloptions = readconf();
    
        module->htmlout();
    
        destroy_modul(module);
    
        dlclose(modul);
    
    }
    

    modul.h

    #ifndef module_H
    #define module_H
    
    class module {
    protected:
    
    public:
    virtual ~module() {}
    virtual void htmlout();
    std::string sqloptions;
    
    };
    
    typedef module* create_t();
    typedef void destroy_t(module*);
    
    #endif
    
    bool modul(std::string modulpath);
    

    news.h

    #include <map>
    #include "../../modul/module.h"
    class news : public module
    {
    private:
    int rows;
    typedef std::multimap<int, std::string> News;
    typedef std::pair<int, std::string> NewsPair;
    void getnews(int row);
    void newsrows();
    void writenews();
    public:
    
    void htmlout();
    
    std::string sqloptions; 
    };
    
    extern "C" module* create() {
        return new news;
    }
    
    extern "C" void destroy(module* p) {
        delete p;
    }
    

    news.cpp

    #include <iostream>
    #include <string>
    #include <pqxx/connection>
    #include <pqxx/transaction>
    #include <pqxx/result>
    #include "news.h"
    #include "../../tuxcms.h"
    #include <html.h>
    #include <vector>
    #include <map>
    
    using namespace std;
    using namespace PGSTD;
    using namespace pqxx;
    
    void news::getnews(int row)
    {
    
    	News news;
    	result R;
            connection *conn = new connection(sqloptions);
    
            work T(*conn);
    
            R = T.exec("SELECT * FROM NEWS");
            T.commit();
    
            if(R.size() > 0)
            {
    		news.insert(NewsPair(R[row]["n_id"].as<int>(), R[row]["titel"].as<std::string>()));
    		news.insert(NewsPair(R[row]["n_id"].as<int>(), R[row]["autor"].as<std::string>()));
    		news.insert(NewsPair(R[row]["n_id"].as<int>(), R[row]["datum"].as<std::string>()));
    		news.insert(NewsPair(R[row]["n_id"].as<int>(), R[row]["zeit"].as<std::string>()));
    		news.insert(NewsPair(R[row]["n_id"].as<int>(), R[row]["inhalt"].as<std::string>()));
            }
            else
            {
                    cout << "Datenbank hat keine Daten" << endl;
            }
    
    	html newshtml;
    	News::iterator pos;
    
    	newshtml.createlayer("inhalt","main");
    
    		for (pos = news.begin(); pos != news.end(); ++pos) {
    			std::cout << pos->second <<"<p></p>" << endl;
    			}
    	newshtml.endlayer();	
    
            conn->disconnect();
            delete conn;
    }
    
    void news::newsrows()
    {
    
    	result R;
            connection *conn = new connection(sqloptions);
    
            work T(*conn);
    
            R = T.exec("select count(*) from news");
    	T.commit();
    	R[0][0].to(rows);
    	conn->disconnect();
            delete conn;
    
    	do
    	{
    	rows--;
    	getnews(rows);
    	}
    	while(rows>=0);
    }
    
    void news::writenews()
    {
    
    };
    
    void news::htmlout()
    {
    std::cout << "test" << std::endl;
    newsrows();
    };
    

    error.log

    [Thu Dec 27 18:46:29 2007] [error] [client 192.168.123.21] module/news.so: undefined symbol: _ZTI6module, referer: http://tuxwebdev.wehrwolf/?+nav=module/news.so
    

    Finde nicht heraus wo der fehler liegt 😞



  • einmal echo _ZTI6module | c++filt eingetippt, sagt das uns, dass unter diesem symbol die rtti der klasse module zu finden ist (bzw. zu finden sein sollte). es scheint, als dass diese fehlt. zeig bitte, wie du die ganzen dateien compilierst und linkst.
    außerdem solltest du dir überlegen, ob es nicht sinn machen würde, module::htmlout() pure virtual zu machen und den code für den virtuellen destruktor in eine eigene code datei zu stecken. ich denk, dass dann auch dein rtti problem verschwinden sollte.

    hab noch was gefunden:
    erzeuge eben die code datei für die klasse module. diese linkst du in dein programm. das programm linkst du mit der option --export-dynamic. damit werden die symbole des programm (und damit auch die der klasse module) deinem plugin zur verfügung gestellt.



  • Wenn ich das richtig sehe fehlt der Körper von module::htmlout - der gcc packt die vtable soweit ich weiss dorthin wo die Implementierung der ersten virtuellen, nicht-inline Methode der Klasse auftaucht. Das aber nur zur Erklärung des Phänomens, Du solltest namenlos Rat folgen und den Destruktor in einer cpp-Datei implementieren (dann liegt die vtable dort, weil der Destruktor die erste virtuelle nicht-inline Methode ist) und htmlout abstrakt machen.



  • Mir fällt noch ein kleiner Schönheitsfehler ein. Per C++-Standard lässt sich ein void*, wie er von dlsym geliefert wird, nicht in einen Funktionszeiger casten. Das geht zwar, ist aber nicht zwangsweise portabel. Besser ist es, eine statische Instanz einer factory-Klasse zu exportieren. Etwa so:

    In einem Header-file:

    class IFactory
    {
    public:
      virtual IModul* create() = 0;
      virtual void destroy(IModul*) = 0;
    };
    

    Ein Modul:

    class MyModulFactory : public IFactory
    {
    public:
      virtual IModul* create() = 0;
      virtual void destroy(IModul*) = 0;
    };
    
    IModul* MyModulFactory::create()
    { return new MyModul(); }
    
    void MyModulFactory::destroy(IModul* inst)
    { delete inst; }
    
    extern "C" MyModulFactory factory;
    

    Jetzt bekommst Du mit dlsym(lib, "factory") einen Zeiger auf eine IFactory, mit der Du IModul-Instanzen erzeugen kannst.

    Etwa so mache ich das auch in meinen tntnet und tntdb. Wobei Du für eine Webapplikation mit C++ auch gleich tntnet nehmen kannst 😉





  • sollen wir uns das runterladen und ansehen?



  • ist glaube ich besser wenn ich die ganzen makefiles und header dateien hier poste gibt es chaos.



  • das mag sein, aber bedeutet das, dass dein problem noch weiter besteht? oder is vielleicht ein neues dazugekommen?



  • Habe es hinbekommen habe als virtual gemacht wie es namenlos gesagt hat und eine neuere version vom g++ ;-).


Anmelden zum Antworten