Umstellung von dynamischer auf statische Verlinkung funktioniert nicht



  • Hallo,

    eines vorweg, ich habe meine Frage schon hier auf ubuntuusers.de gestellt, aber da dort haben wir keine Lösung finden können.

    Ich habe habe ein kleines Testprogramm, dass die torrent-rasterbar-Bibliothek benutzt. Das kompiliert auch perfekt, wenn ich auf dynamische Verlinkung stelle.

    Mit diesem Befehl kompiliert er dynamisch verlinkt:

    g++ test.cpp -o own-torrent2 -ltorrent-rasterbar -lboost_filesystem -lboost_system
    

    Wenn ich nun ein "-static" einbaue, haut er mit 1 MB Fehlermeldungen raus. Die Fehlermeldungs-Ausgabe steht hier zum download bereit.

    Mein Problem ist glaube ich, dass ich die technischen Unterschiede der beiden Verlinkungsarten noch nicht verstanden habe. Also die Theorie ist klar, dass eben beim statischen verlinken die Bibliotheken in die neue Datei mit eingebaut werden. Aber was braucht der Kompiler dazu? Die libtorrent-rasterbar.a ist vorhanden.

    Grüße
    MPW


  • Mod

    Das sind Linkerfehlermeldungen, nicht der Compiler. "g++" ist eine eierlegende Wollmilchsau von einem Frontend, das automatisch Präprozessor, Compiler, Linker, usw. aufruft, je nach Bedarf.

    Geraten: -pthread Flag setzen?



  • Hallo,

    danke für deine Antwort. Das hatten wir in der anderen Diskussion schon probiert. Einmal vor und einmal nach "-static" gesetzt, hat leider nichts gebracht.

    Grüße
    MPW

    /edit: Hier übrigens mal der Quellcode. Das ist im wesentlichen das Beispiel aus der Doku von der Torrent-Rasterbar-Bibliothek

    //#define BOOST_ASIO_DYN_LINK
    #define BOOST_ASIO_SEPARATE_COMPILATION
    
    #include <iostream>
    #include <fstream>
    #include <iterator>
    #include <iomanip>
    
    #include "libtorrent/entry.hpp"
    #include "libtorrent/bencode.hpp"
    #include "libtorrent/torrent_info.hpp"
    #include "libtorrent/lazy_entry.hpp"
    #include <boost/filesystem/operations.hpp>
    #include "libtorrent/session.hpp"
    
    #include <dirent.h>
    #include <stdio.h>
    
    int main(int argc, char* argv[])
    {
            using namespace libtorrent;
    /*#if BOOST_VERSION < 103400
            namespace fs = boost::filesystem;
            fs::path::default_name_check(fs::no_check);
    #endif*/
    
    /* if (argc != 2)
    {
            std::cerr << "usage: ./simple_client torrent-file\n"
                    "to stop the client, press return.\n";
            return 1;
    } */
    
    #ifndef BOOST_NO_EXCEPTIONS
            try
    #endif
            {
                    session s;
                    s.listen_on(std::make_pair(6881, 6889));
                    add_torrent_params p;
                    p.save_path = "./";
                    p.ti = new torrent_info(argv[1]);
                    s.add_torrent(p);
    
                    // wait for the user to end
                    char a;
                    std::cin.unsetf(std::ios_base::skipws);
                    std::cin >> a;
            }
    #ifndef BOOST_NO_EXCEPTIONS
            catch (std::exception& e)
            {
                    std::cout << e.what() << "\n";
            }
    #endif
            return 0;
    }
    


  • statische Libs sind auch alle vorhanden? Auch für pthread?



  • Da genau fängt es schon an. Ich weiß nicht genau, welche das alle wären?

    Also die libtorrent-rasterbar.a aus dem libtorrent-rasterbar-dev-Package liegt in /usr/lib.

    Was für .a-Dateien brauche ich sonst noch?

    Grüße
    MPW


  • Mod

    Wie löst man so etwas? Nachschlagen (aka Google) woher eines der fehlenden Symbole stammt, sicherstellen, dass man die statische Version dieser Bibliothek hat, Bibliothek beim Linken angeben. Vorgang wiederholen, bis alle Fehler verschwunden sind. Auch immer auf die Reihenfolge achten, links stehen Bibliotheken, die von denen rechts abhängig sind (beachte, dass static und pthread selber Schalter für den Compiler/Linker sind, die können stehen, wo sie wollen). So etwas sollte auch in der Dokumentation zu den Bibliotheken stehen, aber meiner Erfahrung nach ist diese Methode schneller 🙂 .

    Ich habe dies ausnahmsweise mal für dich getan, versuch aber am Besten auch nachzuvollziehen, wie ich darauf gekommen bin. Das Endresultat ist folgender Compiler und Linkeraufruf:

    g++ test.cc -Wall -Wextra -pedantic -ltorrent-rasterbar -lboost_filesystem -lboost_system -lssl -lcrypto -ldl -lGeoIP -static -pthread
    

    Die entsprechenden Bibliotheken müssen, wie schon erwähnt, in ihrer Version für statisches Linken installiert sein. Bei Debian-basierten Distributionen (wie Ubuntu, welches du anscheinend benutzt) muss man beispielsweise die entsprechenden libXXX-dev Pakete installieren. Das Ergebnis dieses kombinierten Compiler- und Linkeraufrufs ist dann:

    test.cc: In function ‘int main(int, char**)’:
    test.cc:40:55: warning: ‘bool libtorrent::session::listen_on(const std::pair<int, int>&, const char*, int)’ is deprecated (declared at /usr/include/libtorrent/session.hpp:349) [-Wdeprecated-declarations]
                     s.listen_on(std::make_pair(6881, 6889));
                                                           ^
    test.cc: At global scope:
    test.cc:20:5: warning: unused parameter ‘argc’ [-Wunused-parameter]
     int main(int argc, char* argv[])
         ^
    /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libcrypto.a(dso_dlfcn.o): In function `dlfcn_globallookup':
    (.text+0x11): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
    /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/libtorrent-rasterbar.a(asio.o): In function `boost::asio::detail::socket_ops::getaddrinfo(char const*, char const*, addrinfo const&, addrinfo**, boost::system::error_code&)':
    (.text+0x523a): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
    /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libGeoIP.a(GeoIP.o): In function `_GeoIP_lookupaddress':
    (.text+0x1b5c): warning: Using 'gethostbyname_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
    

    Beachte vor allem die Warnungen des Linkers und verstehe sie!

    Verstanden? Dann herzlichen Glückwunsch! Du hast eine absolut unportable Executable erstellt. Vermutlich das genaue Gegenteil von dem was du erreichen wolltest. Darum (und auch aus anderen Gründen) linkt man normalerweise auch nicht statisch. Im Gegenteil zu dem, was man als Anfänger vielleicht denkt, ist das nämlich die weniger portable Variante.



  • Hallo,

    danke für deine Mühe. Ich wusste irgendwie nicht so recht, wo ich anfage.

    Dein Befehl kompiliert bei mir nicht, ich brauchte noch zwei Bibliotheken mehr:

    $ g++ test.cpp -Wall -Wextra -pedantic -ltorrent-rasterbar -lboost_filesystem -lboost_system -lssl -lcrypto -ldl -lGeoIP -static -pthread -lz -lrt
    

    Aber dann hab ich eine ähnliche Ausgabe wie du, nämlich, dass zur Laufzeit doch wieder irgendwelche dynamischen Dinge gebraucht werden. Und zwar scheinbar exakt die Version, gegen die kompiliert wurde. Ich nehme an, darauf wolltest du mit der extrem schlechten Portierbarkeit hinaus.

    Hast du da noch ein paar Hintergrundinfos für mich? Warum ist das so und wie könnte man das auch noch auflösen?

    Hier geht es nicht um ein praktisches Beispiel, sondern darum die Verlinkungen zu lernen. Daher macht es nichts, wenn es am Ende nichts taugt :).

    Grüße
    MPW

    /edit: Gerade gelesen, dass diese Warnungen Bugs sind.

    $ ldd a.out 
    	Das Programm ist nicht dynamisch gelinkt
    

    Auf die Ausgabe von ldd ist doch Verlass oder?

    /edit2: Gerade noch ein wenig mit den Optionen gespielt und die Größe von 7,4 auf 5,4 MB geschrumpft:

    $ g++ -s -Os -ffunction-sections -fdata-sections -Wl,-gc-sections test.cpp -Wall -Wextra -pedantic -ltorrent-rasterbar -lboost_filesystem -lboost_system -lssl -lcrypto -ldl -lGeoIP -static -pthread -lz -lrt
    

  • Mod

    Die Bibliotheken (das dürfte die Threadbibliothek sein) nutzen intern Funktionen, die andere Bibliotheken direkt öffnen und Code aus diesen nachladen (dlopen). Die dafür nötigen Dateien müssen logischerweise vorhanden sein und das enthalten, was der Aufrufer erwartet.
    Linkt man nun dynamisch gegen die Threadbibliothek, so wird ja letztlich die Threadbibliothek auf dem Zielsystem benutzt. Sofern diese korrekt installiert ist, sind die Dateien, die diese benötigt natürlich auch vorhanden. Linkt man aber statisch, so wird die Threadbibliothek vom Ursprungssystem genommen. Wenn deren Code nun auf einem anderen System versucht, dynamisch den Code für ihre Version nachzuladen, dann muss auf dem Zielsystem eben genau dieser Code an genau dieser Stelle vorhanden sein, sonst geht's schief.

    Wirklich etwas tun kann man nicht dagegen. Es gibt Gründe, warum das manche Bibliotheken so machen. Es gibt mWn einen Schalter, mit dem man zumindest die Threadbibliothek so erstellen kann, dass es diese Funktionen nicht benutzt. Mit dem Nachteil, dass dann einige Sachen eben einfach nicht gehen. Das könntest du machen und hoffen, dass dein Programm die so deaktivierten Features nicht benötigt.


Anmelden zum Antworten