Xwelltris to taki sympatyczny tetris w którym układa się klocki na dnie ,,studni''. Kolejny klon tej odmiany tetrisa. Nic specjalnego, ale jest całkiem porządnie wykonany, jest napisany w C++ i może używać SDL. Jego instalacja przysparza jednak pewnych kłopotów, a więc świetnie nadaje się na dziewiąty przykład :)

1. Źródła wystarczy pobrać i rozpakować.

2. Próbna instalacja
Pakiet rozpakowuje się do katalogu xwelltris-1.0.1, a więc konieczne będzie użycie opcji ,,-n'' w makrze %config. Nie ma zbyt wielu opcji konfiguracyjnych, prawdę mówiąc jedyne dostępne sprowadzają się do wyboru pomiędzy używaniem przez xwelltris ,,gołych'' X-ów a SDL, ja decyduję się na same X-y, bez SDL.
./configure --with-x --prefix=/usr
Konfiguracja przechodzi gładko, zaczynam kompilować, ale zauważam coś dziwnego - w wynikach kompilatora widzę cały czas flagę ,,-fomit-frame-pointer''... A kompilowane pliki to kod w C++ (używany kompilator to c++, a rozszerzenia plików to .cxx - czyli C++, jak nic). Tyle, że flaga -fomit-frame-pointer jest, w obecnym stadium rozwoju GCC, dla kodu w C++ szkodliwa i nie należy jej w takiej kombinacji za nic w świecie używać. I ja mam odpowiednio ustawione zmienne $CFLAGS i $CXXFLAGS. Najwidoczniej xwelltris zignorował $CXXFLAGS i wziął ustawienia z $CFLAGS. No dobra...

Robię
export CFLAGS="$CXXFLAGS"
./configure --with-x --prefix=/usr
tak, teraz widzę na ekranie poprawne flagi. Czekam na zakończenie kompilacji...
OK, skończył. Teraz instalacja: make install DESTDIR=/shm... kończy się błędem.
/usr/bin/install -c -d -m 755 /usr/share/xwelltris
/usr/bin/install:
cannot change permissions of `/usr/share/xwelltris': Operacja niedozwolona
make: *** [install] Błąd 1
No tak. Najwidoczniej xwelltris ignoruje też zmienną DESTDIR. Hmm, więc może ma jakąś własną zmienną? Czasem tak bywa. W pliku INSTALL nie znajduję jednak żadnych informacji o tym. Przeglądnięcie Makefile upewnia mnie, że xwelltris nie używa żadnych zmiennych by przekierować instalację.

Jest to bez wątpienia jedna z najgorszych rzeczy, jakie mogą się przydarzyć. Wyjścia są tutaj dwa:
1.
Ignoruje się to, kompiluje normalnie program, a w sekcji %install olewa mechanizmy programu i ręcznie kopiuje wybrane kąski z katalogu ze źródłami do %{buildroot}. Można sobie na to pozwolić gdy zna się listę plików które należy zainstalować, no i gdy lista ta nie jest specjalnie długa (wpisywanie dwustu regułek dla ,,cp'' i ,,mkdir'' czy też ,,install'' w pliku .spec może zabić człowieka, zostało to naukowo udowodnione!)
2.
Zmienia się pliki Makefile i pochodne tak, aby zaczęły respektować jakąś zmienną. Może i wymaga większego wysiłku, ale okazuje się być ,,tym właściwym'' rozwiązaniem jeśli poruszamy się na ,,nieznanym terytorium'' (nowy program), lub lista instalowanych plików przekracza choćby kilkanaście/kilkadziesiąt. Ta technika wymaga z pewnością pewnego doświadczenia. Należy znaleźć w plikach Makefile te linijki, które faktycznie instalują pliki, następnie znaleźć ich źródło, bowiem pliki Makefile są często tylko czubkiem góry lodowej i swoje ustawienia czerpią z innych plików. Na dodatek takie rzeczy rozwiązuje się indywidualnie, bo jeśli pakiet nie respektuje $DESTDIR to zwykle jest napisany niestandardowo. Jeśli jest napisany niestandardowo, to znaczy, że jego autor napisał go tak, jak jemu się wydawało, że ,,będzie dobrze''. Czyli istnieje spora szansa, że każdy zrąbany pakiet będzie absolutnie odmienny od innego zrąbanego pakietu, że będzie miał inaczej rozplanowaną sekwencję instalacyjną itp. W tym przypadku (xwelltris) irytujące jest to, że autor użył mechanizmów autoconf... ale nieumiejętnie, popełniając parę istotnych błędów.

W tym przypadku niestety w grę wchodzi tylko sposób nr 2. Niestety. Nie znam listy plików xwelltris, więc muszę go ,,naprawić''.
Notka: Powyższe jest oczywiście kłamstwem :) Spis instalowanych plików jest łatwo poznać. Wystarczyłoby mi skompilować xwelltris z jakimś ,,bezpiecznym'' prefiksem, np. ''--prefix=/shm'', skompilować i zainstalować przez make install. Potem obejrzeć co też xwelltris natworzył w /shm i użyć tego jako wzornika dla pliku .spec. Na potrzeby tego artykułu jednak muszę wciskać miejscami kit w żywe oczy :)

Po paru minutach śledzenia różnych plików dochodzę do wniosku, że winny jest plik Makefile.in (w przypadku pakietów używających autoconf to akurat normalne, autoconf oznacza równocześnie używanie automake. A automake tworzy pliki Makefile z plików Makefile.in. Więc chcąc poprawić plik Makefile modyfikuje się plik Makefile.in, a ./configure przy następnym uruchomieniu je zaktualizuje (w świetle tego modyfikowanie bezpośrednio plików Makefile to w przypadku automake robota głupiego, walka z wiatrakami).

Wydaje mi się, że zmieniając bloczek
install:
        $(INSD) $(INSTLIB)
        $(INSTALL_DATA) $(DATAFILES) $(INSTLIB)
        $(INSTALL_SHARE_DATA) $(SHARE_DATAFILES) $(INSTLIB)
        $(INSTALL_PROGRAM) $(PROGRAM) $(INSTDIR)
na
install:
        $(INSD) ${DESTDIR}$(INSTLIB)
        $(INSTALL_DATA) $(DATAFILES) ${DESTDIR}$(INSTLIB)
        $(INSTALL_SHARE_DATA) $(SHARE_DATAFILES) ${DESTDIR}$(INSTLIB)
        $(INSTALL_PROGRAM) $(PROGRAM) ${DESTDIR}$(INSTDIR)
coś mi się uda zdziałać. Wprowadzam te poprawki, jeszcze raz uruchamiam
./configure --prefix=/usr
kompiluję i instaluję za pomocą
make install DESTDIR=/shm
... i, co ciekawe, udaje się :)
Przynajmniej częściowo. Bo zawartość /shm wygląda tak:
usr/
 |-bin
 \-share/
     \-xwelltris/
          |-board2.gif
          |-polyomino.dat
          |-wellcuts.gif
          |-welltris.scores
          |-font2.gif
          |-topnine.gif
          \-wellintro.gif
chodzi mi o ten plik usr/bin. Tak, to plik, a nie katalog. Plik wykonywalny. Wiem, co się stało: ten głupi xwelltris próbował kopiować binarkę do /usr/bin bez określenia, że chce ją wkopiować do katalogu. Założył, że katalog bin będzie istniał, więc wykonał coś w stylu
cp xwelltris /usr/bin
I to był błąd. Bo w przypadku gdy bin nie istniało w chwili kopiowania, to cp (lub inny program kopiujący, np. install) umieściło binarkę w /usr/bin. Gdyby autor skryptów zapisał to hiper-poprawnie jako
cp xwelltris /usr/bin/
(chodzi o ten ukośnik na końcu linii), to wtedy program kopiujący by zgłosił błąd. Pamiętaj: jeśli piszesz skrypty kopiujące coś do jakiegoś katalogu i masz zamiar udostępniać te skrypty innym ludziom, to wyraźnie oznaczaj typy plików. Bywają różne systemy, różne układy katalogów itp. Lepiej jeśli program od razu się wyłoży, niż gdyby miał po cichu zmasakrować binarkę umieszczając ją w dziwnym miejscu.

Dobra, ten błąd nie jest groźny, wystarczy w pliku .spec utworzyć odpowiedni katalog %{buildroot}%{_bindir} przed rozpoczęciem instalacji.

Ale jest jeszcze jedna rzecz która mnie zastanawia - brak manuali. Hmm. Dla pewności przeglądam katalog ze źródłami... Nie, najwidzoczniej xwelltris nie ma dokumentacji innej, niż te parę luźnych plików README na krzyż. No dobra, to czas wygenerować patcha. Eee, ale ja nie mam już oryginalnego pliku Makefile.in. W ferworze walki nadpisałem go tym zmienionym. Dobra, kopiuję Makefile.in do Makefile.in.new i jeszcze raz rozpakowuję źródła. Uruchamiam
diff -u Makefile.in Makefile.in.new >~/rpm/SOURCES/xwelltris-destdir.patch
i już mam patcha (którego możesz obejrzeć). Teraz można przejść do rpm-owania.

3. Plik .spec
Summary: Kolejny klon tetrisa
Name: xwelltris
Version: 1.0.1
Release: 1
License: GPL
Group: Rozrywka
Source: %{name}-%{version}.src.tar.bz2
BuildRoot: /var/tmp/%{name}-%{version}
Patch0: %{name}-destdir.patch

%description
Tetris w konwencji 2,5D ;)

%prep
%setup -q
%patch0 -p0

%build
export CFLAGS=$CXXFLAGS
%configure --with-x
make

%install
rm -rf %{buildroot}
mkdir -p %{buildroot}%{_bindir}
make install DESTDIR=%{buildroot}

%files
%defattr(0644,root,root,0755)
%attr(0755,root,root)%{_bindir}/*
%{_datadir}/xwelltris

%clean
rm -rf %{buildroot} %{_builddir}/%{buildsubdir}
W zasadzie tutaj nie ma już co wyjaśniać - normalna preambuła, z deklaracją jednego patcha. Sekcja %setup z nałożeniem patcha. W sekcji %build najpierw ustawiam $CFLAGS na wartość $CXXFLAGS (bo xwelltris ma ten dziwny błąd z braniem flag kompilatora C do kompilacji C++). W sekcji %install najpierw zakładam katalog %{buildroot}%{_bindir} (bo xwelltris ma ten dziwny błąd... zresztą, sam wiesz :). Aha, opcja ,,-p'' podana mkdir powoduje, że będzie on zakładał ,,łańcuch'' katalogów, tak jak polecenie mkdirhier.
Sekcja %files też w normie. Jedyne zmiany to wywalenie linijki dla manuali i dodanie linijki dla %{_datadir}/xwelltris.

4. Budowanie pakietu zaczęło się, podziałało, skończyło. Pakiet wynikowy powstał - czyli sukces na całej linii. Teraz tylko uruchamiam sobie
rpmbuild -bs --rmspec --rmsource xwelltris.spec
a rpm tworzy w ~/rpm/SRPMS pakiet źródłowy zawierający speca, patcha i źródła w jednej milutkiej paczuszce. A ta wędruje do mojego składowiska Rzeczy Absolutnie Wartych Przechowywania. Teraz mogę w prosty sposób ponownie przekompilować cały pakiet, w razie upgrade'u wystarczy podmienić paczkę ze źródłami - plik .spec i patch nie powinny się zdezaktualizować.