Linkowanie statyczne – Qt SDK dla Windows

Jak już pisałem wcześniej, moim celem jest uzyskać aplikację, która składa się z jednego pliku wykonywalnego. Ten plik wykonywalny nie może zawierać żadnych odwołań ( zależności ) do innych bibliotek ( plików o rozszerzeniu dll ). By uzyskać taki efekt, należy z linkować statycznie z aplikacją bibliotekę Qt4 oraz MinGW ( plik mingwm10.dll ). Poniżej podaję co należy zrobić, by uzyskać jeden plik wykonywalny bez żadnych zależności od innych bibliotek.

  • Pobierz bibliotekę Qt4 z następującej lokalizacji: Qt SDK for Windows. Na dzień dzisiejszy jest to biblioteka w wersji 4.7.0.
  • Uruchom pobrany plik qt-sdk-win-opensource-2010.05.exe i zainstaluj bibliotekę w lokalizacji domyślnej. Jeśli nie zmieniono lokalizacji domyślnej to będzie to katalog: c:\Qt\2010.05
  • Wykonaj kopię katalogu c:\Qt\2010.05 do katalogu c:\Qt\static. Instalacja biblioteki Qt4 zabiera trochę czasu, więc czasami przyda się oryginał biblioteki, gdy przykładowo wyłoży się kompilacja
  • Przejdź do katalogu: c:\Qt\static\mingw\bin i skopiuj plik mingw32-make.exe do tego samego katalogu, lecz o nazwie make.exe. Zabieg ten uprości później wpisywanie komendy kompilacji w oknie cmd Windows. Zamiast komendy mingw32-make.exe wpiszesz make.exe, co jest przyjemniejsze w użyciu.
  • Teraz trzeba usunąć linkowanie dynamiczne pliku mingwm10.dll. W tym celu należy przejść do katalogu:
    c:\Qt\static\qt\mkspecs\win32-g++ i otworzyć plik qmake.conf do edycji. Znajdź frazę QMAKE_LFLAGS i dopisz switch -static. Poniżej przedstawiono linię z frazą QMAKE_LFLAGS po zmianie:

    QMAKE_LFLAGS = -static -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc

    Następnie wyszukaj w tym pliku wszystkie wystąpienia switch’a -mthreads i usuń wszystkie. Zapisz plik qmake.conf.

  • Otwórz konsolę Windows ( cmd ) i przejdź do katalogu: c:\Qt\static\qt, wpisując polecenie:
    cd c:\Qt\static\qt
  • Wpisz poniższe polecenie by skonfigurować bibliotekę Qt4 do kompilacji:
    configure -static -opensource -debug-and-release -exceptions -stl -qt-zlib -qt-gif -qt-libpng -qt-libjpeg -no-phonon -no-phonon-backend -no-qt3support -nomake examples -nomake demos

    Normalnie powyższe przełączniki są poprawne i kompilacja przebiega bez błędów. Czasami jednak kompilator wykłada się i po skompilowaniu projektu w Qt, nadal wymagany jest plik mingwm10.dll. Nie masz wtedy w pełni skompilowanej biblioteki statycznie. W takim przypadku bezpieczniej jest zastąpić przełącznik -exceptions na -no-exceptions. Poniżej linia z wprowadzoną modyfikacją:

    configure -static -opensource -debug-and-release -no-exceptions -stl -qt-zlib -qt-gif -qt-libpng -qt-libjpeg -no-phonon -no-phonon-backend -no-qt3support -nomake examples -nomake demos

  • Po zakończeniu kroku powyższego zamknij okno konsoli Windows ( cmd ) i otwórz je ponownie. Zaoszczędzisz w ten sposób frustracji, gdy kompilacja zakończy się niepowodzeniem. Przejdź ponownie do katalogu c:\Qt\static\qt
  • Rozpocznij kompilację wpisując następujące polecenie:
    make sub-src
  • Niestety kompilacja trwa długo

Jeśli kompilacja zakończyła się powodzeniem, to posiadasz wersję statyczną biblioteki Qt4 w wersji debug oraz release. Teraz wystarczy już tylko podpiąć bibliotekę statyczną Qt4 do QtCreator’a lub Eclipse’a.

8 komentarzy

  1. michal pisze:

    Zbudowałem Qt 4.6.3 wg tej instrukcji, próbowałem też na trochę inne sposoby znalezione w internecie, ale wygląda na to, że w tej wersji jest jakiś błąd. Więcej tutaj: http://www.qtcentre.org/threads/31684-Problems-creating-Qt-4.6.3-static-with-MinGw , jak widać jest coś na rzeczy.
    Zbudowanie Qt 4.6.2 pomogło, ale wciąż musiałem dołączać mingwm10.dll. Po paru próbach budowania Qt okazało się -no-exceptions rozwiązało problem.

  2. Ryszard Matuszyk pisze:

    Dziękuję za informację, bo nie spodziewałem się, że wersja biblioteki Qt 4.6.3 zachowuje się inaczej niż wersja 4.6.2. Gdy będę miał chwilkę czasu, to spojrzę na problem i wprowadzę odpowiednie poprawki do linkowania statycznego. Postaram się zrobić to jak najszybciej by inni użytkownicy zaoszczędzili czas i nie zastanawiali się co jest nie tak.

    Co do konieczności dołączania biblioteki mingwm10.dll, myśle, iz opcja -no-exceptions załatwiła sprawę wyłożenia się kompilatora podczas kompilacji biblioteki Qt bo najprawdopodobniej nie miałeś skompilowanej całej biblioteki Qt.

  3. Dawid pisze:

    witam, zastosowalem wszytskie kroki w probie kompilacji qt 4.7 i w momencie, kiedy potwierdzam ‚y’, zaczyna sie kompilacja, ale zaczyna sie od bledow i kilkadziesiat linii bledow i warn’ow leci, a proces konczy sie failed 🙁

    pierwszy wpis to error e2015 – cos o ambiguity between operator!=(QBool.bool) and QBool operator const…. in func QDebug::operator<<, pozniej warning w8084….i pare innych errorow, cala dluuuga lista, a kroki wykonuje jak w instrukcji napisane, kopia folderu do c:\Qt\static, pozniej ustawienie na -static, usuniecie switchow, wpisanie w konsoli wszytskiego (wpisane poprawnie, bo jak byl blad to od razu przerywalo, a jak poprawnie, to prosi o zaakcpetowanie … ) a pozniej nic tylko error i warning

    a zalezy mi, aby mozna bylo dolaczyc tylko potrzebne biblioteki do mojego projektu, bo teraz exe upomina sie o biblioteki, co maja nawet ponad 100MB (przykladowo chcac komus kalkulator napisany w qt przyslac, bede musial zalacznik +100MB, a chce tego wlasnie uniknac)

  4. johnyjj2 pisze:

    Witam,
    po wykonaniu komendy „configure” otrzymuję dużo komunikatów, rozpoczynają się one od: „Unable to detect the platform from environment. Use -platform command lineargument or set the QMAKESPEC environment variable and run configure again”.
    Następnie (w nowym cmd) wchodzę w D:\Qt\static\qt i wykonuję ‚make sub-src’. Niestety, „Nazwa ‚make’ nie jest rozpoznawana jako polecenie wewnętrzne lub zewnętrzne, program wykonywalny lub plik wsadowy”.
    Zatem próbuję ‚D:\Qt\static\qt>D:\Qt\static\mingq\bin\make.exe sub-src’. Tutaj jest inny problem: „make: *** No rule to make target ‚sub-src’. Stop”.
    Mam Qt Creator 2.0.1 zainstalowany jak normalnie, ale na dysku d. Według „Informacje o Qt Creator”: „Based on Qt 4.7.0 (32 bit)”.
    Pozdrawiam!

  5. Ryszard Matuszyk pisze:

    Myślę, iż nie masz ustawionej zmiennej środowiskowej:

    QMAKESPEC: win32-g++

  6. johnyjj2 pisze:

    Witam,

    dziękuję za odpowiedź! Próbując dowiedzieć się, jak ustawić zmienną środowiskową „QMAKESPEC: win32-g++” dowiedziałem się od jednego z użytkowników QT (http://forum.4programmers.net/Newbie/171969-c++qt_programowanie_obiektowe?p=703012#id703012), że linkowanie statyczne nie jest dobrym pomysłem, ponieważ uzyskam dużo większy plik wykonywalny i będę potrzebował wykupić licencję komercyjną, o czym nic nie było wspomniane w Pana artykule, a co nie wchodzi w grę. Programista ten poinformował mnie, że zawsze kompiluje ze źródeł i wtrakcie konfiguracji ustawia m.in. „-static”. Kompilacja trwa długo, a jedyne, co trzeba zrobić, to w pliku projektu (.pro) dodać „CONFIG += static” lub podobną komendę. Dowiedziałem się również, że najlepszym rozwiązaniem jest podobno wrzucić pliki dll do folderu z projektem i linkować dynamicznie.

    Raczej dużo czasu mi zajmuje zwykłe odpalenie pliku wykonywalnego poza środowiskiem QT Creator, ale trudno, muszę to i tak zrobić, więc dalej próbuję się dowiedzieć, jak skonfigurować projekt i środowisko. Poszukałem w internecie na temat linkowania dynamicznego i z pewnego tematu (http://peb.pl/programowanie/846219-c-qt-tworzenie-wlasnych-plikow-dll.html) dowiedziałem się, że moje pliki .h muszą zawierać jakieś nie znane mi deklaracje (__declspec (dllexport) itd.). Wygląda również na to, że występuje istotna różnica z używaniem include dla własnych plików i domyślnych plików z bibliotek QT. Ktoś inny zaś sugerował, że obecnie rozwiązuje się to przy pomocy wtyczek (http://doc.trolltech.com/4.6/plugins-howto.html).

    Która z tych metod jest w takim razie najlepsza: linkowanie statyczne, dynamiczne czy wtyczki? Jeśli rzeczywiście jest to linkowanie statyczne, to [b]jak ustawić zmienną środowiskową „QMAKESPEC: win32-g++”?[/b] Jeśli zaś ustawienie „CONFIG += static” to po co właściwie jest ten static, czy ta linijka jest prawidłowo zapisana i gdzie ją dodać do pliku projektu? Jeśli zaś linkowanie dynamiczne to w jaki sposób to zrobić? (Znalazłem dość różne opisy linkowania dynamicznego, a większość to były rozmowy na forach, z których nic w zasadzie nie wynikało). Dlaczego QT zaleca używanie wtyczek?

    Ja tylko chcę odpalić prosty projekt poza środowiskiem QT.

    Pozdrawiam!

  7. Ryszard Matuszyk pisze:

    Z licencja na Qt to nie jest tak jak piszesz. Qt jest dystrybuowane w kilku wersjach:

    GPL – należy udostępnić kod źródłowy
    LGPL – stworzoną aplikację można dystrybuować komercyjnie pod warunkiem llinkowania dynamicznego i wówczas nie trzeba udostępniać kodu źródłowego. Jeśli jednak nastąpi linkowanie statyczne, to jest to traktowane jak ingerencja w kod biblioteki a wówczas można dystrybuować komercyjne stworzoną aplikację pod warunkiem jednak udostępnienia kodu źródłowego

    Pisałem, że kod aplikacji jest większy, ale czasami trzeba zlinkować statycznie, gdyż czasami jest to konieczne. Weźmy pod uwagę aplikację aktualizatora plików. Gdy aktualizujemy różne pliki ale nie sam aktualizator to linkowanie dynamiczne jest oczywistą sprawą. Gdy jednak musimy zaktualizować sam plik aktualizatora, który korzysta z kilku plików dll to wówczas jest problem. Łatwiej w takiej sytuacji zarządzać jednym plikiem niż kilkoma. Dodatkowo odpada problem błędnej podmiany jednego z plików dll na wersję błędną a wtedy sam aktualizator może przestać działać.

    Opisywana przez Ciebie metoda nie załatwi sprawy pliku z MinGW o nazwie mingwm10.dll.

  8. do poczytania pisze:

    Hey very cool blog!! Man .. Beautiful .. Amazing .. I will bookmark your site and take the feeds also…I’m happy to find a lot of useful info here in the post, we need work out more techniques in this regard, thanks for sharing. . . . . .

Leave a Reply