23 października 2008

Dłubiemy w systemie - cz. 1: Kompilacja oprogramowania

Chciałbym tym wpisem rozpocząć krótką serie, w której opisywać będę najpopularniejsze metody dostrajania systemu i oprogramowania. Zaczynamy!

Ręczna kompilacja oprogramowania.
Zanim zaczniemy zastanówmy się dlaczego warto cokolwiek ręcznie kompilować. No właśnie - po co? Najczęstsze przyczyny to:

  • Brak danego programu/biblioteki repozytorium dystrybucji,
  • Chęć lepszego dostosowania oprogramowania do naszych potrzeb,
  • Optymalizacja kodu (flagi kompilatora, flagi linkera, stripowanie),
  • Chcemy zaingerować w kod programu/biblioteki (łaty, własne modyfikacje)
  • Gdy nie mamy dostępu do root'a, a koniecznie musimy zainstalować jakiś program, podczas gdy admin wypoczywa przy szklance soku w Pcimiu Dolnym.

Pierwszym krok""iem jest zaopatrzenie się w odpowiednie narzędzia - niezbędny będzie kompilator (gcc), linker (ld, wchodzi w skład binutils), biblioteki (przede wszystkim glibc-devel), automake, autoconf i inne. Skąd mieć pewność, że mamy wszystko co potrzebne - o tym za chwilę.

Następny krok to zaopatrzenie się w źródła (kod źródłowy) danego programu/biblioteki. W tym celu musimy udać się na stronę danego projektu lub zapytać wujka google'a. Najczęściej występują w postaci archiwum tar skompresowanych gzip'em/bzip'em (*.tar.gz, *.tar.bz2, czasem skracane do *.tgz, *.tbz2). Naukę najlepiej zacząć od niewielkich programów, np. irssi - konsolowy klient IRC.

W konsoli przechodzimy do katalogu, gdzie zapisaliśmy archiwum (zalecam wypakowywanie do pustego katalogu), następnie rozpakowujemy je poleceniem:

$ tar jxvf nazwa_archiwum.tar.bz2

lub

$ tar zxvf nazwa_archiwum.tar.gz

Flaga (opcja) 'z' informuje program tar, że mamy do czynienia z archiwum spakowanym gzipem, a w przypadku 'j' - bzipem. 'x' mówi że chcemy coś wypakować, 'v' oznacza tryb "gadatliwy" (ang. verbose), a 'f' wskazuje, że chcemy rozpakować plik, którego nazwa jest dalej. Szczegółowe opisy opcji polecenia tar można znaleźć w man tar

Jeśli w wyniku tego procesu otrzymamy nowy podkatalog - przechodzimy do niego (ok. 85% przypadków).

Na moment zostawię konsolę w spokoju, aby poruszyć kwestię optymalizacji. Informacje o tym jak ustawiać flagi, które z nich są 'bezpieczne', a które nie, można znaleźć w Hoppke Repo. Dodam tylko, że zauważyłem, iż w ostatnim czasie stosowanie flagi -fomit-frame-pointer dla C++ ($CXXFLAGS) przestało powodować problemy (sam używam tej flagi, korzystam z gcc serii 4.3).Nawet jeśli ktoś nie ma zamiaru skupiać się na studiowaniu flag kompilatora, to nie zaszkodzi na stałe ustawić popularnych i bezpiecznych flag dla konkretnego modelu procesora. Chyba, że zależy nam na przenośności (np. tworzymy paczkę, która ma być dostępna dla każdego użytkownika danej dystrybucji), wtedy najlepiej kompilować pod i686 (pentium pro i nowsze).

Wróćmy do procesu kompilacji. Etapem wstępnym do właściwej kompilacji jest konfiguracja. Odbywa się to poprzez wywołanie skryptu configure z odpowiednimi opcjami. Własnie - jakimi opcjami? Listę dostępnych opcji uzyskamy po wpisaniu:

$ ./configure --help

Część opcji występuje zawsze, lub bardzo często, natomiast spora część bywa unikatowa, tylko dla danego oprogramowania. Ich opisy znajdziemy po wywołaniu w.w. polecenia, ale pozwolę sobie opisać (moim zdaniem) najważniejszą, czyli --prefix=... Czym jest prefix? W Linuksie oraz Uniksie stosuje sie filozofię, iż biblioteki lądują w katalogu lib, binarki w bin lub sbin, pliki nagłówkowe w includes itd. Są to założenia standardu FHS
Prefix definuje ścieżkę gdzie umieszczona ma zostać w.w. struktura. Prosze zauważyć że podobne katalogi znajdziemy w /,
/usr, /usr/local, a czasem /opt/nazwa_programu/. Za pomocą prefiksu definiujemy gdzie zainstalujemy dany program. Ktoś teraz zapyta: "super, mamy wybór gdzie chcemy instalować oprogramowanie, ale co nam to daje i dlaczego ten nawiedzony człowiek nazwał to najwazniejsza opcją?" Otóż jest kilka istotnych powodów:

  • Wyobraźmy sobie sytuację, że posiadamy konto shellowe, bez uprawnień pozwalających na instalację pakietów binarnych, czy zapisu w /usr, /usr/local, czy /opt. W takim przypadku możemy ustawić prefix na miejsce, do którego mamy pełne prawa i gdzie nie zajrzy nam inny użytkownik - takim miejscem jest katalog domowy użytkownika, jednak by nie robic sobie balaganu proponuje utworzyc specjalny katalog na wlasne oprogramowanie i dodac go do sciezki podanej w prefixie. Przyklad użycia:

    $ ./configure --prefix=~/moje_programy [--inne-opcje]

    Przy zastosowaniu takiego egzotycznego prefiksu standardowo nie będziemy mogli uruchamiać programów poprzez samo wpisane ich nazwy. Musimy podawać pełną ścieżkę do binarki - czyli ~/moje_programy/bin/nazwa_programu. Da się to łatwo zmienić. Wystarczy zmodyfikować zmienną środowiskową $PATH przechowującą listę katalagów, gdzie powłoka ma szukać programów. Poszczególne ścieżki oddzielone są dwukropkami, a im wcześniej dana lokalizacja występuje tym wyższy ma priorytet. W praktyce wystarczy zmodyfikować/utworzyć ~/.bashrc (ukryty (kropka na początku nazwy) plik teksotwy, którego zawartość jest wykonywana podczas każdego uruchomienia powłoki BASH). Umieszczamy w nim następującą linijkę (najlepiej dopisać do końca):

    export PATH=~/moje_programy/bin:$PATH


    Jak widać nowa ściezka będzie miała najwyższy priorytet (jeśli w systemie jest już zainstalowany dany program, ale np. jego wersja/konfiguracja nam nie odpowiada, to mamy pewność, że po wpisaniu samej nazwy polecenia uruchomi się "nasz" program). Aby 'wczytać' nowe ustawienia wydajemy polecenie:

    $ source ~/.bashrc



  • Domyślną wartością opcji prefix jest /usr/local. Jak mówi FHS jest to specjalne miejsce na oprogramowanie instalowane lokalnie, wydzielone w celu uniknięcia 'kolizji' plików należących do pakietów binarnych (dla których przeznaczono /usr) z 'naszymi' podczas ew. aktualizacji systemu. Nie polecam instalacji z prefixem do /usr, chyba że wiemy co robimy (np. konfigurujemy żródła z myślą o budowie pakietu binarnego dla naszej ulubionej dystrybucji)

To właśnie ./configure i jego opcje są jedna z największych zalet własnoręcznej kompilacji i systemów typu source-based. Możemy zdecydowac, z których funkcji programu będziemy korzystać i (co za tym idzie) maja zostać wkompilowane, a które sa z naszego punktu zbędne i chcemy odchudzić z nich program.

Działanie skryptu możemy podzielic na 2 fazy - sprawdzającą i generującą. Podczas pierwszej sprawdzana jest dostępność niezbędnych bibliotek i narzędzi w systemie, im więcej ficzerów (opcji, funkcji - używam tutaj popularnego spolszczenia od ang. 'features') wybierzemy (--with-costam) tym większe zalezności ("wymagania software'owe") będzie miał nasz kompilat. Działa to również w drugą stronę - jeśli ./configure przerywa działanie i krzyczy że brakuje mu libcośtam najpierw sprawdzamy czy dana biblioteka/narzędzie nie ma związku z ficzerem, którego nie zamierzamy używać - jeśli tak to możemy spokojnie ogołocić nasz program z danej funkcji uruchamiając skrypt jeszcze raz, tym razem z dodatkową opcja --without-cośtam. W przeciwnym wypadku - musimy "spełnić zależności" czyli doinstalowac co trzeba. Jeśli mimo tego ./configure dalej nie 'widzi' biblioteki/narzędzia, to nie trzeba się załamywać - prawdopodobnie to wina nietypowego prefiksu i wystarczy odp. skonfigurować konsolidator dynamiczny/zmienną środowiskową $PATH aby rozwiązać problem, ale to już temat na osobny wpis.

Drugą fazą procesu jest automatyczne tworzenie plików makefile, które są fundamentem kolejnego etapu, czyli właściwej kompilacji. I tu niespodzianka bo..

..właściwa kompilacja sprowadza się tylko do jednego polecenia:

$ make [opcje]

Warto wspomnieć o opcji -jN (gdzie N to liczba procesorów + 1). Definiuje ona maksymalną ilość operacji wykonywanych jednocześnie.
Jeśli zdefiniowaliśmy własne flagi kompilatora i eksportujemy je globalnie (np. w
/etc/profile albo /etc/make.conf) lub lokalnie (np. w ~/.bashrc) wystarczy nam samo polecenie make. W przeciwnym wypadku właśnie w tej chwili możemy podać nasze flagi kompilatora. Przykład:

$ CFLAGS="-march=athlon-xp -O2 -fomit-frame-pointer -DNDEBUG" CXXFLAGS=$CFLAGS LDFLAGS="-s -z combreloc" make -j2

Jeśli otrzymamy komunikat informujący o 'braku celu do wykonania' oznacza to, że pliki makefile, z których korzysta make nie zostały utworzone. Prawdopodobnie przeoczyliśmy, że ./configure zakończyło się niepowodzeniem.

Ostatnim krokiem jest instalacja. Służy do tego proste polecenie:

# make install

Prosze zwrócić uwagę na znak zachęty - jest to #, ponieważ tę operację wykonujemy z root'a (tzn. wykonujemy ją z poziomu tego użytkownika, który ma prawo zapisu w katalogu podanym jako prefiks. Jeśli instalujemy oprogramowanie w naszym katalogu domowym, możemy ten krok wykonać z poziomu zwykłego użytkownika).

Co prawda mamy możliwość odinstalowania programu poprzez wywołanie polecenia make uninstall w katalogu, jednak nie jest to najwygodniejsze rozwiązanie ponieważ:

  • w przypadku instalacji kilku wersji, z tym samym prefiksem, może dojść do usunięcia plików, których nie chcielibyśmy stracić
  • musimy trzymać katalog 'roboczy', lub pamiętać jakich opcji/prefiksów używaliśmy aby w celu usunięcia programu z systemu wypakować źródła, uruchomić ./configure jeszcze raz, a zaraz po nim make uninstall

Lepsze metody? Tworzenie pakietów! I wcale nie trzeba studiować dokumentacji, a potem wklepywać poleceń jedno po drugim - istnieje automat, zastępujący polecenie make install. Ten automat to checkinstall

Jego użycie nie powino sprawiać większych problemów, można tworzyć zarówno pakiety TGZ (Slackware, Zenwalk i pochodne), DEB (Debian, Ubuntu i pochodne) oraz RPM (Red Hat, CentOS, Fedora Core i pochodne).

Mimo wszystko jeśli chce się zostać developerem "pełną gębą" (dokładniej opiekunem kilku pakietów) jakiejś dystrybucji, założyć własne repozytorium, czy 'paczkować' programy z poza repozytorium i umieszczać np. na linuxpackages.net, wypada poznać natywne (klasyczne) metody tworzenia pakietów. Checkinstall jest świetnym narzędziem, ale nie oferuje 100% kontroli nad tym co się dzieje. Jeśli tworzymy pakiety binarne tylko dla siebie, będzie niezastąpiony.

W następnej części cyklu opiszę klasyczną metodę tworzenia pakietów TGZ dla Slackware. Podstawy już są ;) Zapraszam do komentowania.

22 października 2008

Maple12 i Wolne Oprogramowanie

W trakcie wykładu z Metod Obliczeniowych prowadzący ogłosił mały konkurs polegający na opisaniu i ew. prezentacji sposobu eksportu animowanych 'plotów' wygenerowanych w programie Maple (został napisany w Javie i jest w pełni przenośny między wszystkimi platformami, na których działa JRE) do dowolnego formatu (animowana grafika, wideo). Postanowiłem podjąć się wyzwania i przy okazji pokazać jakie możliwości niesie ze sobą wolne oprogramowanie.

Pierwszym pomysłem było zastosowanie pętli for w której przy każdym wykonaniu bloku instrukcji rysowany byłby plot dla konkretnej klatki a następnie eksportowany do formatu gif. W trakcie prac zupełnie przypadkowo odkryłem, że Maple w wersji 12 ma zaimplementowany eksport do animowaych gif'ów. Nie było sensu dalszych prac nad wynajdowaniem koła od nowa. Pierwszy próg pokonany.

Poniżej prezentuję małe HOWTO które stworzyłem przy okazji zabawy:

  1. Eksport do GIF'a (animowana grafika):
    Klikamy prawym przyciskiem myszy na danym plocie, wybieramy export -> Graphics Interchange Format, definiujemy ścieżkę do której ma nastąpić eksport i zapisujemy. Dla ułatwienia następnych kroków zalecam eksportować do pustego katalogu.

  2. Eksport do MPEG (video):
    a) Korzystając z instrukcji zawartych w punkcie 1, eksportujemy animacje w Maple'u do formatu gif, do pustego katalogu (aby ułatwić sobie dalsze kroki).

    b) Otwieramy okno terminalu i przechodzimy do katalogu gdzie zapisalismy naszą animację w formacie gif. Konwertujemy animowanego gif'a na pliki w formacie jpg, gdzie każdy z nich zawiera 1 klatkę animacji. Ilość plików jest zależna od ilości klatek. Do tego celu używamy narzędzia convert dostępnego w pakiecie ImageMagick:

    $ convert nazwa.gif nazwa_%05d.jpg

    W wyniku otrzymamy serie plików graficznych w formacie jpg zawierajacych numer klatki w nazwie (nazwa_00001.jpg, nazwa_00002.jpg itd.)

    c) Za pomocą narzędzia ffmpeg sklejamy pliki jpg w film mpg:

    $ ffmpeg -r `ls -l *.jpg | wc -l` -i nazwa_%05d.jpg -y -an nazwa.mpg

    (`ls -l *.jpg | wc -l` zwraca nam ilosc plików z rozsz. jpg w danym katalogu)

  3. Eksport do innych formatów video sprowadza sie do encodingu przy pomocy np. mencodera (kuzyn mplayer'a) filmu w formacie mpg.
    Bardzo interesującym rozwiązaniem są nowoczesne kontenery audio/video, dzięki którym możemy np. stworzyć 1 plik video z zaimplementowanymi kilkoma ścieżkami dzwiękowymi/napisami (np. tłumaczenia w przypadku międzynarodowej konferencji naukowej - każdy otrzymuje ten sam plik z filmem i samodzielnie decyduje w jakim języku chce go oglądać).

20 października 2008

Zlecenie dla Politechniki Śląskiej wykonane.

Jakiś czas temu dostałem propozycję stworzenia skórki dla Plone (systemu zarządzania treścią (CMS) stworzonym w języku Python) dla pewnego instytutu Politechniki Śląskiej. Zlecenie w głównej mierze polegało na stworzeniu nowego kaskadowego arkuszu styli (CSS) oraz przygotowaniu odpowiednich elementów graficznych. Ponieważ dłubanie w samym silniku systemu nie należało do moich kompetencji musiałem kombinowac w jaki sposób wpleść specjalnie przygotowane elementy graficzne w określony układ. Nieocenionym narzędziem w pracy okazała się wtyczka dla Firefoxa i pochodnych - Firebug. Cała oprawa graficzna została stworzona w wolnym i darmowym (licencja GNU GPL) GIMPie. Poznałem kilka nowych sztuczek i wzbogaciłem swoje portfolio o kolejne zlecenie dla PŚ - skromna inwestycja w przyszłość.
Jeśli zleceniodawca również wyrazi zgodę - opublikuje motyw graficzny na jednej z wolnych licencji.

Link do strony wkrótce.

18 października 2008

Slax i tworzenie własnych modułów

Swego czasu zastanawiałem się nad stworzeniem swojej dystrybucji LiveCD lub modyfikacją istniejącej, tak aby odpowiadała moim wymaganiom - tzn. posiadało to co jest mi niezbędne i tylko to. Całkiem niedawno na jednym z for linuksowych napotkałem na pytanie początkującego użytkownika o sposób tworzenia własnych modułów w postaci archiwum LZM dla dystrybucji SLAX 6.x. Postanowiłem poszerzyć swoje horyzonty i poszperać za dobrym manualem i udało mi się spłodzić małe howto. Z góry zaznaczam, że bardzo przydatna (niezbędna?) przy tworzeniu własnych modułów jest wiedza i doświadczenie nt. budowy pakietów *.tgz wykorzystywanych w Slackware (o tym może kiedyś napiszę).

Tyle słowem wstępu, przejdźmy do właściwej części wpisu.
Mamy do wyboru kilka dróg:
  • od zera:

    1. tworzymy paczkę *.tgz z plikami konfiguracyjnymi i dodatkowym oprogramowaniem - wszystko wrzucamy w 1 pakiet
    2. konwertujemy paczkę na archiwum lzma:

      tgz2lzm pakiet.tgz moduł.lzm



  • łączymy różne pakiety tgz i ew. dołączamy własne pliki konfiguracyjne:

    1. rozpakowujemy paczki *.tgz do wcześniej utworzonego katalogu, np. /tmp/my_lzm_package/

      installpkg -root /tmp/my_lzm_package pakiet.tgz

      W ten sposób otrzymujemy drzewko katalogów w /tmp/my_lzm_package zawierające binarki, biblioteki itp. składniki danego pakietu.
    2. Jeśli trzeba to wprowadzamy własne modyfikacje
    3. konwertujemy drzewko katalogów na archiwum (moduł) lzma:

      dir2lzm /tmp/my_lzm_package paczka.lzm



  • modyfikacja istniejącego modułu (*.lzm):

    1. Rozpakowujemy archiwum lzm

      lzm2dir modul.lzm /tmp/my_lzm_package


    2. Postępujemy jak przy sposobie wyżej, z tym że 1 punkt mamy już z głowy. Możemy np. podmienić splashscreen wyświtlany podczas uruchamiania gimpa/xine lub dodać jakiś soft.

  • Przeglądanie zawartości modułów lzm pod dowolną dystrybucją (Uwaga! wymaga obsługi systemu plików squashfs w jądrze):

    1. Archiwa lzm możemy montować, tak jak obrazy *.iso, pendrive, czy płytki CD/DVD. Tworzymy katalog gdzie zamontujemy moduł:

      mkdir /mnt/moduly


    2. ... i montujemy:

      >mount -t squashfs -o loop /sciezka/do/modulu.lzm /mnt/moduly


    3. Pamiętajmy, że gdy skończymy przeglądanie zawartości i/lub będziemy chcieli podmontować inny moduł, należy najpierw odmontować dotychczas zamontowane archiwum lzm:

      umount /mnt/moduly

Jeśli masz doświadczenie z tworzeniem pakietów binarnych dla slackware to pewnie już się domyślasz w jaki sposób kompilować soft ze źródeł i od razu tworzyć z niego moduły. Jeśli nie - to w przyszłości zamierzam napisać co nieco na ten temat.


Jako wychowanemu na Slackware bardzo podoba mi się Slax oraz sposób tworzenia modułów. Myślę, ze to dobra alternatywa dla tworzenia własnego przenośnego distro od zera. Wystarczy utworzyć odpowiedni moduł zawierający certyfikat sieci eduroam i bez własnego komputera można cieszyć się uczelnianym WiFi, wykorzystując swoje ulubione narzędzia ;)

Hello World!

Witam,
Jakis czas temu zdarzyło mi się popełnić kilka komentarzy, o charakterze uzupełniającym treść wpisu na pewnym blogu, a raczej stronie domowej.. Pomyślałem, że może warto zacząć spisywać na bieżąco swoje doświadczenia oraz przemyslenia zwiazane z systemem operacyjnym czy realizają przeróżnych projektów.
Co z tego wyjdzie? Zobaczymy..