Nauka kompilacji rzeczy ze źródła (na Unix / Linux / OSX)

47

Podczas gdy instaluję oprogramowanie z pakietów (MacPorts / apt-get) tam, gdzie to możliwe, często muszę skompilować pakiety ze źródła. ./configure && make && sudo make installzwykle wystarcza, ale czasami to nie działa - a kiedy nie, często utknąłem. To prawie zawsze w jakiś sposób odnosi się do innych zależności bibliotek.

Chciałbym nauczyć się następujących rzeczy:

  • Jak dowiedzieć się, jakie argumenty przekazać ./configure?
  • Jak biblioteki współdzielone działają w systemie OS X / Linux - gdzie znajdują się w systemie plików, jak ./configure && makeje znajdują, co faktycznie dzieje się, gdy są połączone
  • Jakie są rzeczywiste różnice między biblioteką współdzieloną a statycznie połączoną? Dlaczego nie mogę po prostu połączyć statycznie wszystkiego (obecnie pamięć RAM i miejsce na dysku są tanie), a tym samym uniknąć dziwnych konfliktów wersji bibliotek?
  • Jak mogę sprawdzić, jakie biblioteki zainstalowałem i jakie wersje?
  • Jak mogę zainstalować więcej niż jedną wersję biblioteki bez uszkodzenia mojego normalnego systemu?
  • Jeśli ja jestem instalacji materiał ze źródła w systemie, który jest inaczej zarządzany przy użyciu pakietów, co jest najczystszym sposobem robić to?
  • Zakładając, że uda mi się skompilować coś ze źródła, jak mogę to spakować, aby inni ludzie nie musieli przeskakiwać przez te same obręcze? Szczególnie w OS X ....
  • Jakie narzędzia wiersza poleceń muszę opanować, aby być w tym dobrym? Rzeczy takie jak otool, pkg-config itp.

Jestem skłonny zainwestować tutaj sporo czasu i wysiłku - niekoniecznie chcę bezpośrednich odpowiedzi na powyższe pytania, wolałbym raczej uzyskać rekomendacje na temat książek / samouczków / najczęściej zadawanych pytań, które mogę przeczytać, które dadzą mi Wiedzę, że muszę zrozumieć, co się właściwie dzieje, a więc samodzielnie rozwiązać problemy.

Simon Willison
źródło

Odpowiedzi:

40

Przepraszam za bezpośrednie odpowiadanie na wszystko, ale nie znam żadnych przydatnych samouczków, często zadawanych pytań itp. Zasadniczo po 8 latach tworzenia aplikacji komputerowych (które pomagam w dystrybucji), frustracji i googlowania:

1. Jak dowiedzieć się, jakie argumenty przekazać do ./configure?

Ćwicz naprawdę. Automatyczne narzędzia są dość łatwe, ponieważ są spójne. Ale jest wiele rzeczy za pomocą cmake lub niestandardowych skryptów kompilacji. Zasadniczo nie trzeba przekazywać niczego do skonfigurowania, powinno się dowiedzieć, czy system może zbudować narzędzie foo, czy nie.

Narzędzia do konfigurowania i GNU sprawdzają zależności w /, / usr i / usr / local. Jeśli zainstalujesz coś gdzie indziej (co sprawia, że ​​bolesne jest, jeśli zależność została zainstalowana przez MacPorts lub Fink), będziesz musiał przekazać flagę, aby skonfigurować lub zmodyfikować środowisko powłoki, aby pomóc narzędziom GNU znaleźć te zależności.

2. Jak działają biblioteki współdzielone w systemie OS X / Linux - gdzie znajdują się w systemie plików, w jaki sposób ./configure && sprawia, że ​​je odnajduje, co faktycznie dzieje się, gdy są połączone

W systemie Linux należy je zainstalować w ścieżce, którą może znaleźć dynamiczny linker, jest to zdefiniowane przez LD_LIBRARY_PATHzmienną środowiskową i zawartość pliku /etc/ld.conf. Na Macu prawie zawsze jest tak samo w przypadku większości programów open source (chyba że jest to projekt Xcode). Tyle że zmienna env jest DYLD_LIBRARY_PATHzamiast tego.

Istnieje domyślna ścieżka, którą konsolidator szuka bibliotek. Jest to / lib: / usr / lib: / usr / local / lib

Możesz to uzupełnić za pomocą zmiennej CPATH lub CFLAGS lub dowolnej liczby innych zmiennych środowiskowych naprawdę (wygodnie skomplikowanych). Sugeruję CFLAGS tak:

export CFLAGS = "$ CFLAGS -L / new / path"

Parametr -L dodaje się do ścieżki łącza.

Nowoczesne rzeczy używają narzędzia pkg-config. Nowoczesne rzeczy, które instalujesz, instalują również plik .pc, który opisuje bibliotekę, gdzie jest i jak się do niej dowiązać. To może ułatwić życie. Ale nie ma go w systemie OS X 10.5, więc musisz go również zainstalować. Również wiele podstawowych operacji nie obsługuje tego.

Linkowanie polega na „rozwiązaniu tej funkcji w czasie wykonywania”, tak naprawdę jest to duża tablica ciągów znaków.

3. Jakie są rzeczywiste różnice między biblioteką współdzieloną a statycznie połączoną? Dlaczego nie mogę po prostu połączyć statycznie wszystkiego (obecnie pamięć RAM i miejsce na dysku są tanie), a tym samym uniknąć dziwnych konfliktów wersji bibliotek?

Po utworzeniu łącza do statycznego pliku biblioteki kod staje się częścią aplikacji. To tak, jakby dla tej biblioteki był jeden gigantyczny plik .c, a ty skompilowałeś go w swojej aplikacji.

Biblioteki dynamiczne mają ten sam kod, ale gdy aplikacja jest uruchomiona, kod jest ładowany do aplikacji w czasie wykonywania (uproszczone wyjaśnienie).

Możesz połączyć statycznie ze wszystkim, jednak niestety żaden system kompilacji nie ułatwia tego. Trzeba będzie ręcznie edytować pliki systemowe kompilacji (np. Makefile.am lub CMakeLists.txt). Jednak prawdopodobnie warto się tego nauczyć, jeśli regularnie instalujesz rzeczy wymagające różnych wersji bibliotek i równolegle trudno jest zainstalować zależności.

Sztuczka polega na zmianie linii łącza z -lfoo na -l / path / na / static / foo.a

Prawdopodobnie możesz znaleźć i wymienić. Następnie sprawdź, czy narzędzie nie łączy się z .so ani dylib przy użyciu ldd foo lub otool -L foo

Kolejnym problemem jest to, że nie wszystkie biblioteki kompilują się z bibliotekami statycznymi. Wielu tak. Ale wtedy MacPorts lub Debian mogli zdecydować, że nie zostaną wysłane.

4. Jak mogę sprawdzić, jakie biblioteki zainstalowałem i jakie wersje?

Jeśli masz pliki pkg-config dla tych bibliotek, jest to łatwe:

pkg-config --list-all

W przeciwnym razie często nie możesz łatwo. Dylib może mieć soname (tj. Foo.0.1.dylib, soname to 0.1), która jest taka sama jak wersja biblioteki. Nie jest to jednak wymagane. Soname jest funkcją binarnego obliczania, musisz zmienić większą część soname, jeśli zmienisz format funkcji w bibliotece. Możesz dostać np. wersja 14.0.5 soname dla biblioteki 2.0. Chociaż nie jest to powszechne.

Byłem sfrustrowany tego rodzaju rzeczami i opracowałem rozwiązanie tego problemu na Macu, a teraz o tym mówię.

5. Jak mogę zainstalować więcej niż jedną wersję biblioteki bez uszkodzenia mojego normalnego systemu?

Moje rozwiązanie tego problemu znajduje się tutaj: http://github.com/mxcl/homebrew/

Lubię instalować ze źródła i chciałem narzędzia, które to ułatwi, ale z pewnym zarządzaniem pakietami. Więc dzięki Homebrew buduję np. wget się ze źródła, ale zainstaluj specjalny prefiks:

/usr/local/Cellar/wget/1.1.4

Następnie używam narzędzia homebrew do symlinkowania tego wszystkiego do / usr / local, więc nadal mam / usr / local / bin / wget i /usr/local/lib/libwget.dylib

Później, jeśli potrzebuję innej wersji wget, mogę zainstalować ją równolegle i po prostu zmienić wersję, która jest połączona z drzewem / usr / local.

6. Jeśli instaluję rzeczy ze źródła w systemie, który w innym przypadku jest zarządzany za pomocą pakietów, jaki jest najczystszy sposób?

Uważam, że sposób Homebrew jest najczystszy, więc użyj go lub zrób odpowiednik. Zainstaluj w / usr / local / pkgs / name / version i dowiązaniu symbolicznym lub twardym dowiązaj resztę.

Użyj / usr / local. Każde istniejące narzędzie do kompilacji szuka tam zależności i nagłówków. Twoje życie będzie znacznie łatwiejsze.

7. Zakładając, że uda mi się skompilować coś ze źródła, jak mogę to spakować, aby inni ludzie nie musieli przeskakiwać przez te same obręcze? Szczególnie w OS X ....

Jeśli nie ma żadnych zależności, możesz spakować katalog kompilacji i przekazać go komuś innemu, kto może wtedy dokonać instalacji. Jednak możesz to zrobić niezawodnie tylko dla tych samych wersji systemu OS X. W systemie Linux prawdopodobnie będzie działał dla podobnego systemu Linux (np. Ubuntu) z tą samą wersją jądra i wersją podrzędną libc.

Dystrybucja plików binarnych w systemie Unix nie jest łatwa z powodu zgodności binarnej. Ludzie GNU i wszyscy inni często zmieniają swoje binarne interfejsy.

Zasadniczo nie rozpowszechniaj plików binarnych. Prawdopodobnie wszystko się zepsuje w bardzo dziwny sposób.

Na Macu najlepszą opcją jest utworzenie pakietu Macports. Wszyscy korzystają z Macports. W Linuksie jest tak wiele różnych systemów kompilacji i kombinacji, nie sądzę, że jest jakaś lepsza porada niż napisanie wpisu na blogu o tym, jak udało ci się zbudować narzędzie x w tak dziwnej konfiguracji.

Jeśli stworzysz opis pakietu (dla Macports lub Homebrew), każdy może go zainstalować, co rozwiąże również problemy z zależnościami. Jednak często nie jest to łatwe, a przepisanie makportów nie jest łatwe w głównym drzewie makportów. Również Macports nie obsługuje egzotycznych typów instalacji, oferuje jeden wybór dla wszystkich pakietów.

Jednym z moich przyszłych celów w Homebrew jest umożliwienie kliknięcia linku na stronie internetowej (np. Homebrew: // bla) i pobierze ten skrypt Ruby, zainstaluję deps dla tego pakietu, a następnie zbuduję aplikację. Ale tak, jeszcze nie zrobione, ale niezbyt trudne, biorąc pod uwagę projekt, który wybrałem.

8. Jakie narzędzia wiersza poleceń muszę opanować, aby być w tym dobrym? Rzeczy takie jak otool, pkg-config itp.

otool jest naprawdę przydatny dopiero później. Mówi ci, do czego wbudowane linki binarne. Kiedy zastanawiasz się nad zależnościami narzędzia, które musisz zbudować, jest ono bezużyteczne. To samo dotyczy pkg-config, ponieważ zależność została już zainstalowana, zanim będzie można jej użyć.

Mój łańcuch narzędzi to, czytaj pliki README i INSTALL i wykonaj konfigurację --help. Obejrzyj wynik kompilacji, aby sprawdzić, czy jest rozsądny. Analizuj błędy kompilacji. Może w przyszłości zapytaj o błąd serwera :)

Max Howell
źródło
2
Ciekawe, Homebrew przypomina Portage (menedżer pakietów z Gentoo Linux). Brzmi jak niezła robota.
David Z
12

To ogromny temat, więc zacznijmy od bibliotek współdzielonych w Linuksie (ELF w Linuksie i Mach-O w OS X), Ulrich Drepper ma dobre wprowadzenie do pisania DSO (dynamicznych obiektów współdzielonych), które obejmuje pewną historię bibliotek współdzielonych dostępnych w Linuksie tutaj, w tym dlaczego są ważne

Ulrich opisuje również, dlaczego łączenie statyczne jest uważane za szkodliwe, jednym z kluczowych punktów są aktualizacje zabezpieczeń. Przepełnienia buforów we wspólnej bibliotece (np. Zlib), która jest silnie powiązana statycznie, może powodować ogromne obciążenie dla dystrybucji - miało to miejsce w przypadku zlib 1.1.3 ( zalecenie Red Hat )

ELF

Strona manuala linkera ld.so

man ld.so 

objaśnia podstawowe ścieżki i pliki związane z dynamicznym łączeniem środowiska wykonawczego. W nowoczesnych systemach Linux zobaczysz dodatkowe ścieżki dodane za pomocą /etc/ld.so.conf.d/ dodane zwykle za pomocą glob globu w /etc/ld.so.conf.

Jeśli chcesz zobaczyć, co jest dynamicznie dostępne w konfiguracji ld.so, możesz uruchomić

ldconfig -v -N -X

Przeczytanie instrukcji DSO powinno dać ci dobry podstawowy poziom wiedzy, aby następnie zrozumieć, w jaki sposób te zasady mają zastosowanie do Mach-O w OS X.

Mach-O

W systemie OS X format binarny to Mach-O. Dokumentacja lokalnego systemu dla linkera to

man dyld

Dokumentacja w formacie Mach jest dostępna w Apple

Narzędzia do budowania UNIX

Wspólna configure, make, make installproces jest zazwyczaj dostarczane przez autotools GNU który ma takie książki online, który obejmuje niektóre z historii configure / build rozłamu i toolchain GNU. Autoconf używa testów, aby określić dostępność funkcji w docelowym systemie kompilacji, do obsługi tego używa języka makr M4 . Automake jest w zasadzie metodą szablonów dla plików Makefile, przy czym szablon nazywa się Makefile.am, który generuje plik Makefile.in, który generuje plik autoconf (skrypt konfiguracyjny) do pliku Makefile.

Program GNU hello działa jako dobry przykład zrozumienia łańcucha narzędzi GNU - a instrukcja zawiera dokumentację autotools.


źródło
10

Szymon! Wiem, jak się czujesz; Zmagałem się również z tą częścią uczenia się Linuksa. Opierając się na własnych doświadczeniach, napisałem samouczek na temat niektórych elementów, które poruszasz (głównie jako odniesienie dla mnie!): Http://easyaspy.blogspot.com/2008/12/buildinginstalling-application-from.html . Myślę, że docenisz moją notatkę o tym, jak proste są aplikacje do budowania / instalowania w języku Python. :)

Mam nadzieję, że to pomaga! I szczęśliwej kompilacji.

Tim Jones


Budowanie / instalowanie aplikacji ze źródła w systemie Ubuntu Linux

Podczas gdy repozytoria Ubuntu są pełne wspaniałych aplikacji, w pewnym momencie z pewnością natkniesz się na to „niezbędne” narzędzie, którego nie ma w repozytoriach (lub nie ma pakietu Debiana) lub potrzebujesz nowsza wersja niż w repozytoriach. Co robisz? Cóż, musisz zbudować aplikację ze źródła! Nie martw się, to naprawdę nie jest tak skomplikowane, jak się wydaje. Oto kilka wskazówek, opartych na moich doświadczeniach z zostania rangą amatorem! (Podczas gdy używam Ubuntu w tym przykładzie, ogólne pojęcia powinny mieć zastosowanie do większości dystrybucji Unix / Linux, takich jak Fedora, a nawet platforma Cygwin w systemie Windows).

Podstawowy proces budowania (kompilowania) większości aplikacji ze źródła odbywa się w następującej kolejności: configure -> compile -> install. Typowe polecenia Unix / Linux do wykonywania tych czynności to: config-> make-> make install. W niektórych przypadkach znajdziesz nawet strony internetowe, które pokazują, że wszystkie z nich można połączyć w jedno polecenie:

$ config && make && make install

Oczywiście to polecenie zakłada, że ​​w żadnym z tych kroków nie występują problemy. Tutaj zaczyna się zabawa!

Pierwsze kroki

Jeśli wcześniej nie skompilowałeś aplikacji ze źródła w systemie, prawdopodobnie będziesz musiał ją skonfigurować za pomocą kilku ogólnych narzędzi programistycznych, takich jak gccpakiet kompilatora, niektóre popularne pliki nagłówkowe (pomyśl o tym jak o kodzie, który został już napisany przez inną osobę, która jest używana przez program, który instalujesz) oraz narzędzie do tworzenia. Na szczęście w Ubuntu istnieje tak zwany metapakiet, build-essentialktóry to zainstaluje. Aby go zainstalować (lub po prostu upewnić się, że już go masz!), Uruchom polecenie w terminalu:

$ sudo apt-get install build-essential

Teraz, gdy masz już podstawową konfigurację, pobierz pliki źródłowe aplikacji i zapisz je w katalogu, do którego masz uprawnienia do odczytu / zapisu, takim jak katalog „domowy”. Zazwyczaj będą one znajdować się w pliku archiwum z rozszerzeniem pliku .tar.gzlub .tar.bz2. .tarOznacza po prostu, że jest to „archiwum taśm”, która jest grupowanie plików, które zachowuje ich względną strukturę katalogów. .gzOznacza gzip (GNU zip), który jest popularnym formatem kompresji Unix / Linux. Podobnie .bz2oznacza bzip2, który jest nowszym formatem kompresji, który zapewnia wyższą kompresję (mniejszy rozmiar skompresowanego pliku) niż gzip.

Po pobraniu pliku źródłowego otwórz okno terminala (Terminal systemowy z menu Ubuntu) i przejdź do katalogu, w którym zapisałeś plik. (Użyję ~/downloadw tym przykładzie. Tutaj „~” jest skrótem do katalogu „domowego”). Użyj polecenia tar, aby wyodrębnić pliki z pobranego pliku archiwum:

Jeśli plik jest archiwum gzip (np. Kończy się na .tar.gz), użyj polecenia:

            $ tar -zxvf filename.tar.gz

Jeśli plik jest archiwum bzip2 (np. Kończy się na .tar.bz2), użyj polecenia:

            $ tar -jxvf filename.tar.gz

Wskazówka: jeśli nie chcesz pamiętać wszystkich przełączników wiersza polecenia do wyodrębniania archiwów, zalecamy pobranie jednego (lub obu) tych narzędzi: dtrx (mój ulubiony!) Lub deco (bardziej popularny). Za pomocą jednego z tych narzędzi wystarczy wpisać nazwę narzędzia (dtrx lub deco) i nazwę pliku, to zrobi resztę. Obie te „wiedzą”, jak obsłużyć większość formatów archiwów, z którymi możesz się zetknąć i mają doskonałą obsługę błędów.

Podczas budowania ze źródła istnieją dwa typowe typy błędów, które mogą wystąpić:

  1. Błędy konfiguracji występują po uruchomieniu skryptu konfiguracyjnego (zwykle o nazwie config lub config) w celu utworzenia pliku makefile specyficznego dla instalacji.
  2. Błędy kompilatora występują, gdy uruchomisz komendę make (po wygenerowaniu pliku makefile), a kompilator nie może znaleźć potrzebnego kodu.

Przyjrzymy się każdemu z nich i omówimy, jak je rozwiązać.

Konfiguracja i błędy konfiguracji

Po rozpakowaniu pliku archiwum kodu źródłowego w terminalu należy przejść do katalogu zawierającego wyodrębnione pliki. Zazwyczaj ta nazwa katalogu będzie taka sama jak nazwa pliku (bez rozszerzenia .tar.gzlub .tar.bz2). Czasami jednak nazwa katalogu to tylko nazwa aplikacji, bez żadnych informacji o wersji.

W katalogu źródłowym poszukaj READMEpliku i / lub INSTALLpliku (lub czegoś o podobnych nazwach). Pliki te zazwyczaj zawierają użyteczne informacje o tym, jak zbudować / skompilować aplikację i zainstalować ją, w tym informacje o zależnościach. „Zależności” to tylko wymyślna nazwa dla innych komponentów lub bibliotek wymaganych do pomyślnej kompilacji.

Po przeczytaniu pliku READMEi / lub INSTALLpliku (i, miejmy nadzieję, przejrzeniu odpowiedniej dokumentacji online dla aplikacji), poszukaj pliku wykonywalnego (z ustawionym w pliku uprawnieniem „x”) o nazwie configlub configure. Czasami plik może mieć rozszerzenie, takie jak .sh(np config.sh.). Zwykle jest to skrypt powłoki, który uruchamia inne narzędzia, aby potwierdzić, że masz „rozsądne” środowisko do kompilacji. Innymi słowy, sprawdzi, czy masz zainstalowane wszystko, czego potrzebujesz.

Wskazówka: Jeśli jest to aplikacja oparta na języku Python, zamiast pliku konfiguracyjnego powinieneś znaleźć plik o nazwie setup.py. Aplikacje w języku Python są zazwyczaj bardzo proste w instalacji. Aby zainstalować tę aplikację, jako root (np. Umieść sudo przed następującą komendą w Ubuntu), uruchom tę komendę:

    $ python setup.py install

To powinno być wszystko, co musisz zrobić. Możesz pominąć pozostałą część tego samouczka i przejść bezpośrednio do korzystania z aplikacji.

Uruchom skrypt konfiguracyjny w terminalu. Zazwyczaj możesz (i powinieneś!) Uruchomić skrypt konfiguracyjny za pomocą zwykłego konta użytkownika.

$ ./config

Skrypt wyświetli niektóre komunikaty, aby dać ci wyobrażenie o tym, co robi. Często skrypt podaje informację o tym, czy się powiódł, czy nie, a jeśli nie, pewne informacje o przyczynie niepowodzenia. Jeśli nie otrzymasz żadnych komunikatów o błędach, zazwyczaj możesz założyć, że wszystko poszło dobrze.

Jeśli nie znajdziesz żadnego skryptu, który wygląda jak skrypt konfiguracyjny, oznacza to zwykle, że aplikacja jest bardzo prosta i niezależna od platformy. Oznacza to, że możesz po prostu przejść do kroku kompilacji / kompilacji poniżej, ponieważ pod warunkiem Makefilepowinien działać na dowolnym systemie.

Przykład

W tym samouczku wykorzystam tekstowy czytnik RSS o nazwie Newsbeuter jako przykład rodzajów błędów, które możesz napotkać podczas tworzenia aplikacji. W przypadku Newsbeuter nazwa skryptu konfiguracyjnego to config.sh. W moim systemie po uruchomieniu config.shpojawiają się następujące błędy:

tester@sitlabcpu22:~/download/newsbeuter-1.3$ ./config.sh
Checking for package sqlite3... not found

You need package sqlite3 in order to compile this program.
Please make sure it is installed.

Po przeprowadzeniu niektórych badań odkryłem, że w rzeczywistości sqlite3aplikacja została zainstalowana. Ponieważ jednak próbuję budować ze źródła, jest to wskazówka, której config.shtak naprawdę szukają biblioteki programistyczne (nagłówki) sqlite3. W Ubuntu większość pakietów ma powiązany pakiet programistyczny, który kończy się na -dev. (Inne platformy, takie jak Fedora, często używają sufiksu pakietu -develdla pakietów programistycznych).

Aby znaleźć odpowiedni pakiet dla pakietu sqlite3programistycznego, możemy użyć apt-cachenarzędzia w Ubuntu (i podobnie yumnarzędzie w Fedorze):

tester@sitlabcpu22:~/download/newsbeuter-1.3$ sudo apt-cache search sqlite

To polecenie zwraca dość dużą listę wyników, więc musimy wykonać trochę pracy detektywistycznej, aby ustalić, który pakiet jest odpowiedni. W takim przypadku okazuje się odpowiedni pakiet libsqlite3-dev. Zauważ, że czasami pakiet, którego szukamy, będzie miał libprefiks, a nie tylko tę samą nazwę plus -dev. Wynika to z faktu, że czasami szukamy tylko wspólnej biblioteki, z której może korzystać wiele różnych aplikacji. Aby zainstalować libsqlite3-dev, uruchom typową komendę apt-get install w terminalu:

tester@sitlabcpu22:~/download/newsbeuter-1.3$ sudo apt-get install libsqlite3-dev

Teraz musimy uruchomić config.shponownie, aby upewnić się, że rozwiązaliśmy ten problem zależności i że nie mamy już żadnych problemów z zależnością. (Chociaż nie pokażę go tutaj, w przypadku Newsbeuter również musiałem zainstalować libcurl4-openssl-devpakiet.) Ponadto, jeśli zainstalujesz pakiet programistyczny (jak libsqlite3-dev) i powiązany pakiet aplikacji (np. sqlite3) Nie jest już zainstalowany, większość systemów automatycznie zainstaluje skojarzony pakiet aplikacji w tym samym czasie.

Gdy konfiguracja przebiegnie pomyślnie, wynikiem będzie utworzenie jednego lub więcej plików make. Pliki te mają zwykle nazwy Makefile(pamiętaj, że wielkość liter ma znaczenie w systemach Unix / Linux!). Jeśli pakiet kompilacji zawiera podkatalogi, takie jak srcitp., Każdy z tych podkatalogów również będzie zawierał Makefile.

Błędy kompilacji i kompilacji

Teraz jesteśmy gotowi do faktycznej kompilacji aplikacji. Nazywa się to często budowaniem, a nazwa pochodzi od rzeczywistego procesu konstruowania czegoś. Różne „elementy” aplikacji, które są zwykle wieloma plikami kodu źródłowego, są łączone razem, tworząc ogólną aplikację. Narzędzie make zarządza procesem kompilacji i wywołuje inne aplikacje, takie jak kompilator i linker, w celu wykonania pracy. W większości przypadków po prostu uruchamiasz make (ze zwykłym kontem użytkownika) z katalogu, w którym uruchomiłeś konfigurację. (W kilku przypadkach, takich jak kompilowanie aplikacji napisanych przy użyciu biblioteki Qt, konieczne będzie uruchomienie innej aplikacji „otokowej”, takiej jak qmake. Ponownie zawsze sprawdź szczegóły READMEi / lub INSTALLdokumenty).

Podobnie jak w powyższym skrypcie konfiguracyjnym, po uruchomieniu make (lub podobnego narzędzia) w terminalu, wyświetli on niektóre komunikaty o tym, co jest wykonywane oraz wszelkie ostrzeżenia i błędy. Zazwyczaj można zignorować ostrzeżenia, ponieważ są one głównie dla programistów aplikacji i informują ich, że istnieją pewne standardowe praktyki, które są łamane. Zazwyczaj te ostrzeżenia nie wpływają na funkcję aplikacji. Z drugiej strony należy poradzić sobie z błędami kompilatora. Z Newsbeuter, kiedy uruchomiłem make, przez jakiś czas wszystko szło dobrze, ale potem wystąpił błąd:

tester@sitlabcpu22:~/download/newsbeuter-1.3$ make
...
c++ -ggdb -I/sw/include -I./include -I./stfl -I./filter -I. -I./xmlrss -Wall -Wextra -DLOCALEDIR=\"/usr/local/share/locale\" -o src/configparser.o -c src/configparser.cpp
c++ -ggdb -I/sw/include -I./include -I./stfl -I./filter -I. -I./xmlrss -Wall -Wextra -DLOCALEDIR=\"/usr/local/share/locale\" -o src/colormanager.o -c src/colormanager.cpp
In file included from ./include/pb_view.h:5,
from src/colormanager.cpp:4:
./include/stflpp.h:5:18: error: stfl.h: No such file or directory
In file included from ./include/pb_view.h:5,
from src/colormanager.cpp:4:
./include/stflpp.h:33: error: ISO C++ forbids declaration of \u2018stfl_form\u2019 with no type
./include/stflpp.h:33: error: expected \u2018;\u2019 before \u2018*\u2019 token
./include/stflpp.h:34: error: ISO C++ forbids declaration of \u2018stfl_ipool\u2019 with no type
./include/stflpp.h:34: error: expected \u2018;\u2019 before \u2018*\u2019 token
make: *** [src/colormanager.o] Error 1

Proces tworzenia zostanie zatrzymany, gdy tylko wystąpi pierwszy błąd. Obsługa błędów kompilatora może czasem być trudna. Musisz spojrzeć na błędy, aby uzyskać wskazówki na temat problemu. Zazwyczaj problem polega na tym, że brakuje niektórych plików nagłówkowych, które zwykle mają rozszerzenie .hlub .hpp. W przypadku powyższego błędu jest (lub powinno być!) Jasne, że problem polega na tym, że stfl.hnie można znaleźć pliku nagłówka. Jak pokazuje ten przykład, chcesz spojrzeć na pierwsze wiersze komunikatu o błędzie i zejść w dół, aby znaleźć podstawową przyczynę problemu.

Po przejrzeniu dokumentacji Newsbeuter (co powinienem był zrobić, zanim zacząłem, ale wtedy ta część samouczka nie byłaby bardzo znacząca!), Stwierdziłem, że wymaga ona biblioteki innej firmy o nazwie STFL. Co więc robimy w tym przypadku? Cóż, w zasadzie powtarzamy dokładnie ten sam proces dla wymaganej biblioteki: uzyskaj bibliotekę i wykonaj dla niej proces konfiguracji-kompilacji-instalacji, a następnie wznów budowanie żądanej aplikacji. Na przykład w przypadku STFL musiałem zainstalować libncursesw5-devpakiet, aby poprawnie się skompilował. (Zwykle nie trzeba powtarzać kroku konfiguracji w naszej oryginalnej aplikacji po zainstalowaniu innej wymaganej aplikacji, ale to też nigdy nie boli).

Po pomyślnym zainstalowaniu zestawu narzędzi STFL proces tworzenia Newsbeuter przebiegał pomyślnie. Proces tworzenia zwykle rozpoczyna się tam, gdzie kończy (w momencie wystąpienia błędu). Dlatego wszelkie pliki, które zostały już pomyślnie skompilowane, nie zostaną ponownie skompilowane. Jeśli chcesz wszystko skompilować ponownie, możesz uruchomić make clean all, aby usunąć skompilowane obiekty, a następnie ponownie uruchomić make.

Instalowanie

Po pomyślnym zakończeniu procesu kompilacji będziesz gotowy do zainstalowania aplikacji. W większości przypadków, aby zainstalować aplikację we wspólnych obszarach systemu plików (np. /usr/binLub /usr/share/binitp.), Musisz uruchomić instalację jako root. Instalacja jest naprawdę najprostszym krokiem w całym procesie. Aby zainstalować, w terminalu uruchom:

$ make install

Sprawdź dane wyjściowe tego procesu pod kątem błędów. Jeśli wszystko się powiedzie, powinieneś być w stanie uruchomić nazwę polecenia w terminalu i to się uruchomi. (Dołącz & na końcu wiersza polecenia, jeśli jest to aplikacja GUI, inaczej nie będziesz mógł używać sesji terminalu, dopóki aplikacja nie zakończy działania).

Gdy budujesz aplikację ze źródła, zwykle nie dodaje ikony ani skrótu do menu GUI w Ubuntu. Musisz dodać to ręcznie.

Jest to w zasadzie proces, aczkolwiek potencjalnie iteracyjny, polegający na zbudowaniu i zainstalowaniu aplikacji ze źródła w systemie Ubuntu. Gdy zrobisz to kilka razy, stanie się dla ciebie drugą naturą!

Tim Jones
źródło
Tim, chciałbym przeczytać twój samouczek, ale opublikowany link nie działa.
gareth_bowles
6

Cóż, ./configure --help da ci wiele informacji, dla plików konfiguracyjnych generowanych przez narzędzia GNU. Większość z nich sprowadza się do --with / - bez włączania funkcji (może to wymagać dodatkowego parametru, takiego jak „udostępniony”, aby powiedzieć, gdzie znaleźć bibliotekę).

Inne ważne to --prefix (który domyślnie to / usr / local / przez większość czasu), aby powiedzieć, gdzie zainstalować (jeśli budujesz pakiety, zwykle chcesz to jako --prefix = / usr lub może --prefix = / opt / YourPackage).

W Linuksie, / lib, / usr / lib i / usr / local / lib są przeszukiwane w mojej gcc i są uwzględniane w domyślnej konfiguracji ldconfig. Chyba że masz dobry powód, tutaj właśnie chcesz swoich bibliotek. /etc/ld.so.conf może jednak wyświetlać dodatkowe wpisy.

Skonfiguruj i znajdź je, próbując uruchomić polecenie „gcc -l” i sprawdzić, czy wystąpił błąd. Możesz dodać „-L” do parametru CFLAGS, aby dodać dodatkowe ścieżki do wyszukiwania.

Możesz mieć zainstalowanych wiele wersji, a oprogramowanie połączone ze starszą wersją pozostanie z nią połączone (uruchom ldd, aby dowiedzieć się o powiązaniu z Linuksem), ale nowe kompilacje zazwyczaj dotyczą najnowszej wersji biblioteki dynamicznej w twoim systemie.

Większość programów zakłada dynamiczne biblioteki lib, zwłaszcza jeśli korzysta z libtool, więc może się okazać, że nietrywialne aplikacje nie są poprawnie budowane statycznie.

ls -l to najlepszy wybór, aby znaleźć zainstalowane biblioteki.

I tutaj nie mam informacji; jak dobrze grać z pakietami: nie wiem. Jeśli to możliwe, próbuję owinąć wszystko w pakiet, aby uniknąć problemu.

Aaron Brady
źródło
4

„Jak dowiedzieć się, jakie argumenty przekazać ./configure?”

zwykle: ./configure --help powie ci, czego tam chcesz.

„Jak mogę stwierdzić, jakie biblioteki zainstalowałem i jakie wersje?”

To zależy od systemu. Jednym ze sposobów jest po prostu wykonanie, find /|grep libname|lessponieważ ogólnie pliki bibliotek mają wersję w nazwie pliku.

„Jak mogę zainstalować więcej niż jedną wersję biblioteki bez uszkodzenia mojego normalnego systemu?”

Znowu zależy od systemu i biblioteki. sudo make altinstallutworzy dla ciebie wersjonowaną nazwę. Pliki bibliotek zwykle jednak same się zmieniają. Pamiętaj jednak; ponieważ wersje często tworzą dowiązania symboliczne do „znormalizowanej” nazwy, może to coś zepsuć.

„Jeśli instaluję rzeczy ze źródła w systemie, który w innym przypadku jest zarządzany za pomocą pakietów, jaki jest najczystszy sposób?”

/optDobrym zwyczajem jest używanie parametrów --prefix w ./configure i umieszczanie ich gdzieś w nich .

Oświadczenie: W żadnym wypadku nie jestem ekspertem, ale korzystałem z Linuksa od ponad 5 lat od linii cmd (slackware, CentOS, redhat, ubuntu, różne inne i OS X).

Phillip B Oldham
źródło
4

Aby odpowiedzieć na trochę z twojego pytania, znalazłem dobry sposób, aby zobaczyć, jakie biblioteki zainstalowałeś i jakie wersje (to jest w systemie Linux Debian, więc powinno działać również z innymi wersjami).

dpkg --list

Powinieneś dostać naprawdę długą listę z takimi wyjściami jak ta

ii  libssl0.9.8    0.9.8c-4etch5  SSL shared libraries
ii  libssp0        4.1.1-21       GCC stack smashing protection library
ii  libstdc++5     3.3.6-15       The GNU Standard C++ Library v3
ii  libstdc++5-3.3 3.3.6-15       The GNU Standard C++ Library v3 (development
ii  libstdc++6     4.1.1-21       The GNU Standard C++ Library v3
Mark Davidson
źródło
4

Szymon,

1.) ./configure --help zapewnia dużą ilość informacji. Proponuję to sprawdzić. Zasadniczo ma opcje kompilowania bibliotek statycznych / dynamicznych, jeśli jest to właściwe.

2.) Biblioteki żyją na ścieżce dynamicznego linkera. Zazwyczaj jest to ustawione w /etc/ld.so.conf. Linker szuka odpowiednich bibliotek podobnych do zmiennej środowiskowej PATH pasującej do pierwszej znalezionej.

3.) Zasadniczo prowadzi to do problemów, ponieważ musisz ponownie skompilować wszystko, gdy zmieni się wersja biblioteki. Jeśli przeprowadzisz wyszukiwanie, prawdopodobnie znajdziesz mnóstwo powodów, dla których statyczne łączenie jest złym pomysłem. Nie robiłem tego tak długo, że tak naprawdę nie mogę tutaj rozwodzić się.

4.) To jest trochę trudne. Aby się upewnić, musisz sprawdzić ścieżkę do biblioteki. Biblioteki mają zazwyczaj symboliczne łącze do zainstalowanej wersji.

np. libssh2.so.1 -> libssh2.so.1.0.0

Zasadniczo ludzie zarządzają bibliotekami i programami, które instalują, albo rzucając swoje własne pakiety debian, albo używając innej techniki. Zarządzam zainstalowanym oprogramowaniem za pomocą stow ( http://www.gnu.org/software/stow/ ), co jest bardzo proste i instaluje bibliotekę za pomocą dowiązań symbolicznych. Jest mi łatwiej, ponieważ nie muszę budować / instalować / testować pakietu deb / rpm.

5.) W katalogach bibliotek można normalnie zainstalować wiele wersji bibliotek. Biblioteki powiązane z plikami wykonywalnymi pozostaną połączone z wersjami, z którymi zostały połączone. uruchomienie ldd na pliku wykonywalnym powie ci, z którymi bibliotekami jest powiązany plik wykonywalny.

6.) Jak wspomniałem wcześniej, tworzenie własnych pakietów Debiana lub używanie stow jest prawdopodobnie najczystszym rozwiązaniem.

7.) Naprawdę nie mogę mówić za Mac OSX, ale w przypadku Linuksa system pakowania jest najlepszym sposobem.

8.) Prawdopodobnie wiele frustracji zostanie rozwiązanych za pomocą ldd i dowiedzenia się, z którą wersją coś jest powiązane lub jakiej biblioteki połączonej z plikiem wykonywalnym nie można znaleźć. pkg-config bardzo ci pomoże, ale tylko dla oprogramowania, które go używa. To nie jest część domyślnego systemu kompilacji autotools, choć jest obecnie popularny.

Ian Lewis
źródło
4

Biblioteki statyczne nie są dobrym pomysłem - jeśli musisz zaktualizować bibliotekę (na przykład w celu rozwiązania problemu z bezpieczeństwem), musisz ponownie skompilować wszystko w zależności od tej biblioteki.

Nie podoba mi się pomysł, aby „dokonać instalacji” potencjalnie bałaganił mój system, ale jak powiedzieli inni, instalowanie rzeczy w / usr / local jest o wiele mniej uciążliwe niż używanie prefiksu do instalacji gdzie indziej. Więc zmieniłem / usr / local na mojego zwykłego (nieuprzywilejowanego) użytkownika. W ten sposób gwarantuje się, że „make install” nie zadziera z ważnymi plikami systemowymi. (To oczywiście nie działa na systemach z wieloma użytkownikami. Jest to jednak świetne dla serwerów wirtualnych.)

ithinkihaveacat
źródło
4

Chociaż nie było tego wyraźnie na twojej liście pytań, we wstępie wspominasz:

./configure && make && sudo make install zwykle wystarcza, ale czasami to nie działa - a kiedy nie, często utknąłem.

Kiedy utknę na Debianie lub Ubuntu, użyję auto-apt, który automatycznie zainstaluje pakiety zawierające pliki, których konfiguracja nie może znaleźć.

Widzieć:

Kolejnym narzędziem, które może ci się przydać, jest CheckInstall, który dodaje zainstalowane aplikacje make installdo listy zainstalowanych pakietów: https://help.ubuntu.com/community/CheckInstall

Swoogan
źródło
3

W przypadku OS X:

  • Jak dowiedzieć się, jakie argumenty przekazać do ./configure?

./configure --help

  • Jakie są rzeczywiste różnice między biblioteką współdzieloną a statycznie połączoną? Dlaczego nie mogę po prostu połączyć statycznie wszystkiego (obecnie pamięć RAM i miejsce na dysku są tanie), a tym samym uniknąć dziwnych konfliktów wersji bibliotek?

Korzystanie z bibliotek współużytkowanych umożliwia aktualizację biblioteki bez ponownej kompilacji wszystkiego, co z niej korzysta.

  • Jak biblioteki współdzielone działają w systemie OS X / Linux - gdzie znajdują się w systemie plików, jak ./configure && sprawiają, że je znajdują, co faktycznie dzieje się, gdy są połączone

Biblioteki systemowe działają w / usr / lib.

Biblioteki, które sam kompilujesz na żywo w / usr / local / lib (/ usr / local jest domyślną flagą --prefix dla ./configure).

Zmienne środowiskowe DYLD_FALLBACK_LIBRARY_PATH i LD_LIBRARY_PATH pozwalają określić, które foldery mają być wyszukiwane, więc / usr / local / lib powinien znajdować się na początku listy.

  • Jak mogę zainstalować więcej niż jedną wersję biblioteki bez uszkodzenia mojego normalnego systemu?

Zainstaluj wszystko w / usr / local - przy powyższych zmiennych środowiskowych wersja w / usr / local / lib ma pierwszeństwo przed wersją w / usr / lib w twoim środowisku.

  • Jeśli instaluję rzeczy ze źródła w systemie, który w innym przypadku jest zarządzany za pomocą pakietów, jaki jest najczystszy sposób?

Zainstaluj w / usr / local. W Ubuntu staram się najpierw użyć checkinstall, aby utworzyć pakiet deb.

  • Zakładając, że uda mi się skompilować coś ze źródła, jak mogę to spakować, aby inni ludzie nie musieli przeskakiwać przez te same obręcze? Szczególnie w OS X ....

Powiedziałbym, że udokumentuj kroki kompilacji w poście na blogu.

Alf Eaton
źródło