0 Linux – instalacja i kompilacja programów
Tomasz Zaworski edited this page 2020-11-15 02:28:24 +01:00
  1. Wprowadzenie
  2. Zadania do wykonania na zajęciach
  3. Konfiguracja nietypowych urządzeń
  4. Zadania domowe
  5. Materiały uzupełniające
  6. Przygotowanie do kolejnych zajęć

Wprowadzenie

W przypadku klasycznych systemów (desktop do pracy biurowej, prosty serwer WWW) istnieją gotowe rozwiązania, nie wymagające ręcznej konfiguracji, czy instalacji pakietów spoza domyślnie dostępnych. Model taki jest wystarczający dla większości instalacji. Czasami jednak potrzebny jest system, który będzie współpracował z nietypowym sprzętem lub zawierał oprogramowanie, które nie jest dostępne w formie pakietów (np. napisane specjalnie dla konkretnego systemu).

Zadania do wykonania na zajęciach

Konfiguracja nietypowych urządzeń

Zadanie 1

Większość "sterowników" urządzeń jest albo wkompilowana w jądro systemu (choćby te, które są niezbędne do uruchomienia), albo jako moduły ładowane dynamicznie, gdy dane urządzenie zostanie wykryte. Aby zobaczyć jakie moduły zostały załadowane, wystarczy użyć polecenia lsmod (większość linii została wycięta, lista jest zwykle dłuższa).

$ lsmod
Module                  Size  Used by
xt_mac                 16384  1
xt_tcpudp              16384  1
dccp_diag              16384  0
snd_pcm               106496  0
snd_timer              32768  1 snd_pcm
snd                    86016  2 snd_timer,snd_pcm
soundcore              16384  1 snd

Z powyższego możemy odczytać: nazwę modułu, zajmowaną przez niego pamięć oraz jakie inne moduły są od niego zależne (np. snd jest używany przez snd_timer).

Aby załadować moduł wraz z zależnościami możemy wykorzystać polecenie modprobe nazwa_modułu (np. arc4 -- nie zadziała to jednak na Proxmox!). Aby usunąć moduł (także niemożliwe na Proxmoksie) wystarczy wpisać rmmod nazwa_modułu. Usunięcie nie powiedzie się, jeżeli moduł jest używany.

Konfiguracja modułów (np. domyślne opcje) znajduje się w pliku

/etc/modules

oraz w plikach znajdujących się w katalogu

/etc/modprobe.d

Sprawdź jakie moduły są załadowane w systemie na którym pracujesz.

Zadanie 2

Aby wykonać następne zadanie, należy zainstalować pakiety gcc i make:

sudo apt-get install gcc make lzip

Stwórzmy plik tekstowy o nazwie program.c z następującą zawartością.

#include <stdio.h>

int main(){
	printf("Something\n");
	return 0;
}

a następnie skompilujmy poleceniem:

gcc -Wall -ansi -o program program.c

(przełącznik -Wall wyświetla wszystkie ostrzeżenia, a -ansi sprawdza, czy program jest zgodny z ANSI C; opcja -o pozwala podać nazwę pliku wynikowego, domyśną nazwą jest a.out).

Jeżeli kompilacja zakończyła się sukcesem (tzn. kompilator nie zgłosił błędów), to możemy wykonać nasz program

$ ./program
Something
Zadanie 3

Jako, że większość pakietów dostępnych wyłącznie w postaci źródeł (nie w pakietach) stanowią duże projekty (kompilacja byłaby problemem na dostępnej platformie; zarówno ze względu na dostępną pamięć, jak i czas kompilacji), do demonstracji wybieramy prosty edytor ed (dostępny także w pakiecie, ale domyślnie niezainstalowany).

Na początku pobieramy kod ze strony, rozpakowujemy i przechodzimy do katalogu projektu

$ wget https://ftp.gnu.org/gnu/ed/ed-1.14.2.tar.lz
$ tar xavf ed-1.14.2.tar.lz
$ cd ed-1.14.2
$ ls
AUTHORS  COPYING  ChangeLog  INSTALL  Makefile.in  NEWS  README  TODO  buffer.c  carg_parser.c  carg_parser.h  
configure  doc  ed.h  global.c  io.c  main.c  main_loop.c  red.in  regex.c  signal.c  testsuite

W pliku INSTALL (czasami w README) jest opisany proces instalacji. W tym przypadku należy wywołać skrypt configure (dostępne opcje po wywołaniu z parametrem --help), make (zbudowanie całości), make install (w naszym przypadku sudo make install, bo do instalacji potrzebne są uprawnienia użytkownika root).

$ ./configure
$ make
$ sudo make install

Uwaga: w przypadku systemów mających swój system pakietów instalacja programów zewnętrznych może powodować problemy i powinna być stosowana wyłącznie w przypadku, gdy nie ma innej możliwości.

Zadanie 4

Kolejnym etapem jest budowa własnego pakietu. Zamiast tworzyć skrypt generującego konfigurację (configure), stworzymy tylko plik dla programu make. Domyślnie sprawdzane są nazwy GNUmakefile, Makefile, makefile. W naszym przykładzie niech się nazywa Makefile, jest to najbardziej popularny wybór, a ze względu na domyślny porządek sortowania będzie jednym z pierwszych plików wyświetlanych przez polecenie ls, bo większość plików ma nazwy rozpoczynające się od małej litery.

Plik Makefile w podstawowej wersji wygląda następująco:

cel: zależność1 zależność2
	polecenie_do_zbudowania_celu

gdzie zależność może być innym celem lub plikiem. Uwaga: wcięcie w powyższym pliku to jeden znak tabulacji, a nie kilka spacji!

Konstrukcja taka gwarantuje, że podczas kolejnych wywołań programu make ponownie zostaną przebudowane wyłącznie te cele, których zależności się zmieniły. Dla programu z Zadania 2 plik mógłby wyglądać następująco:

program: program.c
	gcc -Wall -ansi -o program program.c

Wywołanie programu make zbuduje program tylko wtedy, gdy czas utworzenia/zmiany pliku program.c jest późniejszy niż wynikowego pliku program

$ make
gcc -Wall -ansi -o program program.c
$ make
make: 'program' is up to date.

Zauważmy, że polecenie touch program.c zaktualizuje datę dostępu do pliku, przez co make przekompiluje program.

Zadanie 5

Funkcjonalności (np. zapis pliku na dysk, przeskalowanie okienka) powtarzają się w wielu programach. Aby nie pisać ich dla każdego projektu od początku, stworzone zostały tzw. biblioteki. W przypadku bibliotek linkowanych statycznie odpowiednie funkcje są w trakcie kompilacji (linkowania) dołączane do pliku z programem wynikowym.

Powyższa metoda powoduje jednak pewien problem. Naprawa błędu znalezionego w bibliotece wymaga powtórnej kompilacji wszystkich powiązanych aplikacji, a kod wynikowy zajmuje miejsce (na dysku, jak i w pamięci) wielokrotnie. Rozwiązaniem są biblioteki łączone dynamicznie. W tym przypadku w pliku programu są zapisywane wyłącznie odwołania, a same funkcje znajdują się w bibliotece (w przypadku Linuksa są to zwykle pliki z rozszerzeniem .so, znajdujące się w katalogu lib, a w przypadku Windows są to pliki z rozszerzeniem .DLL).

W przypadku programów zlinkowanych dynamicznie możemy sprawdzić od jakich bibliotek zależy (i czy wszystkie są dostępne):

$ ldd  /bin/bash 
	linux-vdso.so.1 (0x00007ffd6f155000)
	libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f08d9934000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f08d9730000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f08d9391000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f08d9b5e000)

Z powyższego wynika, że program bash jest połączony dynamicznie m.in. z biblioteką C (libc.so.6). Aby dołączyć do własnego programu bibliotekę, dodajemy do wywołania kompilatora opcję -lnazwaBiblioteki, np.

gcc -Wall -ansi -lm -o program program.c

dołączy do naszego programu bibliotekę matematyczną (jeżeli dodalibyśmy jeszcze nagłówek math.h, to moglibyśmy korzystać z funkcji tej biblioteki).

Sprawdź rozmiar pliku program przed i po dołączeniu biblioteki libm.

Uwaga: Niektóre programy muszą (a co najmniej powinny) być jednak łączone statycznie. Przykładem takiego polecenia jest m.in. ldconfig służący do konfiguracji linkera dynamicznego. Innym przykładem mogą być polecenia (np. powłoka) trybu awaryjnego, które w przypadku braku dostępu do dysku, nie mogłyby załadować podczas startu zależności (np. busybox - programik zastępujący praktycznie wszystkie podstawowe polecenia systemowe).

Zadania domowe

Zadanie domowe 1

Napisz program dodaj.c (w języku ANSI C), który po wywołaniu z parametrami będącymi dwoma liczbami całkowitymi zwróci ich sumę, np.

$ ./dodaj 10 20
30

Uwaga: w programie użyj argc i argv.

Zadanie domowe 2

Do programu z poprzedniego zadania stwórz plik Makefile (taki, jak w Zadaniu 4 z ćwiczeń).

Zadanie domowe 3

Napisz kolejny plik Makefile, który stworzy pakiet .tar.gz zawierający źródła programu dodaj wraz z plikiem Makefile (tym z zadania 2) w taki sposób, by odpowiednie archiwum (dodaj.tar.gz) było ponownie tworzone wyłącznie w przypadku, gdy któryś z plików uległ zmianie). Uwaga na dwa różne pliki Makefile o tej samej nazwie!

Struktura katalogów:

dodaj-numer_indeksu/
|-- dodaj.c
|-- Makefile

Materiały uzupełniające

Dodatkowe informacje można znaleźć na stronie mgra Przybylskiego w module 6 i 7.1.

Przygotowanie do kolejnych zajęć

W ramach przygotowania do kolejnych zajęć proszę przerobić: