Pierwsze co mi przychodzi do głowy w związku z "dodatkami" do RPM to stripowanie. Plików wykonywalnych i bibliotek. Tak, jak to opisałem w artykule o kompilowaniu programów. Tutaj jednak pojawia się pewna niedogodność - w pakietach RPM całość procesu budowania jest zautomatyzowana. Powstały pakiet nie będzie zawierał tak silnie zestripowanych binarek. Można oczywiście potem (po instalacji) wejść np. do /usr/bin czy /usr/lib i ręcznie zestripować pliki, ale po takim zabiegu zmieni się ich rozmiar, data modyfikacji itp., przez co rpm zacznie uważać te pliki za "zmienione" (no i słusznie) co może być irytujące przy weryfikowaniu zainstalowanych pakietów za pomocą "rpm -V".
RPM jest jednak silnie zautomatyzowanym procesem i po odrobinie dłubania doszedłem do wniosku, że to może stać się zaletą. Można mianowicie zmusić rpmbuild do stripowania plików za nas - ba, przy odrobinie "magii" może być to dla użytkownika rpmbuild niezauważalne (nie musi nic dodatkowego robić), pakiety będą powstawały od razu odpowiednio zestripowane, a ponieważ będzie to robił automat z samego użytkownika zostanie zdjęte brzemię wyszukiwania plików do stripowania i dobierania innych flag do bibliotek statycznych a innych do plików wykonywalnych.
Aby coś takiego uzyskać konieczna będzie jednak pewna modyfikacja systemu RPM. Nic wielkiego, nie wiąże się to z rekompilowaniem RPM-a ani niczym takim. Nawet nie trzeba mieć do tego uprawnień root-a. Ot, poprawka kilku makrodefinicji a każdy następny zbudowany pakiet będzie doświadczał radosnego cudu agresywnego stripowania.
rpmbuild operuje przy budowaniu pakietu w kilku fazach, nie chcę się teraz w żadną z nich zagłębiać więc wystarczy jeśli powiem, że przy każdym momencie, na początku i na końcu "wykonywania" każdej z sekcji pliku .spec istnieje możliwość podpięcia globalnie swoich działań, w formie skryptów shellowych. Proces stripowania musi znaleźć się gdzieś pomiędzy sekcją %install a %files - po %install wszystkie pliki są już na miejscu i można je zacząć zmieniać, a przed %files jeszcze nie są one wliczane w skład pakietu, jeszcze można zmieniać ich rozmiar itp. Logiczne byłoby podpięcie się na końcu fazy instalacyjnej (%install). I, prawdę mówiąc, RPM (myślę cały czas o "waniliowej" wersji 4.1, bo takiej aktualnie używam) tak robi. Ma tam podpięte np. kompresowanie stron manuali czy info oraz właśnie... stripowanie. Ale stripowanie bardzo słabe (IMO). Stripuje tylko binarne pliki wykonywalne, a i to nie zawsze. Pomija w ogóle stripowanie bibliotek, na dodatek flagi stripujące można uczynić bardziej "pazernymi", jeszcze bardziej redukując rozmiar plików.
Ja stawiam na prosty sposób postępowania: binarki stripować tak bardzo, jak tylko się da. Biblioteki dynamiczne, niezależnie od tego czy są wykonywalne (mają bit +x), czy też nie, należy tak samo potraktować. Z bibliotekami statycznymi jest nieco trudniej, bo trzeba użyć nieco innych flag przy stripowaniu - ale również należy to zrobić. Do rozpoznawania plików należy używać połączonej logiki rozpoznawania atrybutów plików jak również, kontrowersyjnie kosztownego, wywoływania "file" - bowiem nie każdy plik wykonywalny jest binarką ELF którą można stripować, nie każdy plik z rozszerzeniem *.so jest biblioteką dynamiczną, nie można też ograniczać się do "standardowych" lokacji takich jak np. /usr/lib i /usr/bin, bo równie dobrze stripować można też np. pluginy w różnych programach, które zwykle są bardzo podobne do bibliotek i mogą być jak takowe traktowane (np. pluginy xmms czy gaim-a). Po uwzględnieniu tych wszystkich warunków jak też analizie błędów popełnionych w oryginalnych, rpm-owych mechanizmach stripujących zestawiłem własny podsystem dla rpm, podsystem który stripuje silniej, agresywniej, jeszcze lepiej usuwa plamy z tłuszczu a jego ActivPiana® wnika teraz w każde włókno :)
Ta modyfikacja RPM-a opiera się na pojedynczym skrypcie shellowym i ustawieniach makr aktywujących ten skrypt w odpowiednim momencie. Wpis zmieniający makra można wykonać w lokalnym ~/.rpmmacros danego użytkownika, można też umieścić go globalnie w głównym pliku makr rpm-a (zapewne w /usr/lib/rpm/macros), ale tego bym nie polecał - lepiej jest zachowywać "główną" instalację rpm tak bardzo "nienaruszoną", jak to tylko możliwe. Ewentualne modyfikacje proponuję wprowadzać lokalnie - poza tym łatwiej później tym zarządzać. Skrypt można umieścić w dowolnym miejscu, w makrach podaje się potem ścieżkę dostępu do niego. Skrypt jednak polecam umieścić w /usr/lib/rpm, ze względu na to, że w /usr/bin raczej nie ma czego szukać (nie jest "programem" który samodzielnie coś wykonuje), no i umieszczenie go tam, gdzie inne skrypty tej klasy lądują wydaje mi się dosyć eleganckim wyjściem. Ma unikatową nazwę, więc łatwo można go potem znaleźć i ew. usunąć.
Ze względów "bezpieczeństwa" potrzebne modyfikacje zamieszczam w formie plików do pobrania - nie ma sensu ich przeklejać na WWW, poza tym składnia tych akurat makr jest bardzo wrażliwa na jakiekolwiek przypadkowe złamanie wierszy itp., więc lepiej nie ryzykować.
Do pobrania: skrypt stripujący "brp-strip-max"
#!/bin/sh
if [ -z "$RPM_BUILD_ROOT" -o "$RPM_BUILD_ROOT" = "/" ]; then
exit 0
fi
# Stripowanie wykonywalnych binarek ELF.
for f in `find $RPM_BUILD_ROOT -type f \( -perm -0100 -or -perm -0010 -or -perm -0001 \) -exec file {} \; | \
grep -v ' shared object,' | sed -n -e 's/^\(.*\):[ ]*ELF.*/\1/p'` ; do
strip -R .comment -R .note -R .note.ABI-tag $f || :
done
# Stripowanie dynamicznych obiektów ELF z rozszerzeniem .so (prawdopodobnie biblioteki lub pluginy)
for f in `find $RPM_BUILD_ROOT -type f -regex '.*\.so\(\(\.[0-9]*\)*\)*' -exec file {} \; | \
grep ' shared object,'|sed -n -e 's/^\(.*\):[ ]*ELF.*/\1/p'` ; do
strip -R .comment -R .note -R .note.ABI-tag $f || :
done
# Stripowanie statycznych bibliotek
for f in `find $RPM_BUILD_ROOT -type f -name '*.a' -exec file {} \; | \
grep ' current ar archive'|sed -n -e 's/^\(.*\):[ ]*current ar archive.*/\1/p'`; do
strip -g -X -x $f || :
done
oraz : modyfikacja makr "rpmmacros-strip-addon"
%__os_install_post \
/usr/lib/rpm/brp-compress \
%{?_no_powerstrip:/usr/lib/rpm/brp-strip; /usr/lib/rpm/brp-strip-comment-note} \
%{!?_no_powerstrip:/usr/lib/rpm/brp-strip-max}\
%{nil}
Po skopiowaniu skrypt stripujący umieść w /usr/lib/rpm (i nadaj mu ew. prawa do wykonywania przez wszystkich zainteresowanych), a zawartość rpmmacros-strip-addon dodaj do swojego lokalnego pliku ~/.rpmmacros. I to by była cała "instalacja". Zastosowanie jest proste: buduj pakiety jak zwykle, całość "automagicznie" wejdzie do gry i zestripuje wszystkie pliki tak, by maksymalnie pomniejszyć biblioteki, pluginy i binarki. Nie trzeba tego już w żaden sposób uaktywniać (robi to ta mała modyfikacja makr w ~/.rpmmacros)
Nieco bardziej technicznie: modyfikacja wyłącza domyślne, rpm-owe mechanizmy stripujące, jako że sama działa IMO dużo lepiej - uruchamianie jeszcze tych "standardowych" redhatowych stripperów nie popsułoby nic, ale też nic by już nie dało, więc nie ma sensu uruchamiać tych skryptów na darmo. Tak agresywne stripowanie potencjalnie może mieć nieznane skutki uboczne. Potencjalnie, bo ja go używam już od długiego czasu i jak do tej pory wszystko działa nienagannie, a modyfikacja ta brała już udział w budowaniu przeróżnych pakietów, takich jak np. gcc, XFree86 czy glibc - więc można uznać, że działa zgodnie ze specyfikacją i jest całkowicie bezpieczna. Jeśli jednak zechesz ją wyłączyć, załóżmy że nie w przypadku awarii, ale np.... o, mam, np. gdy chcesz jednak zbudować jakiś pakiet z pełnym "debug info" w bibliotekach i binarkach, zaimplementowałem od razu tylne wyjście - całą tę modyfikację można łatwo deaktywować definiując makro o nazwie '_no_powerstrip'. Jeśli w jakimś pliku .spec umieścisz linijkę:
%define _no_powerstrip 1
to przy budowaniu tego speca modyfikacja pozostanie pasywna, w zamian robiąc "fallback" do domyślnych, rpm-owych mechanizmów stripujących. To chyba rozsądne rozwiązanie.