Kompilujeme po síti
Začal jsem si hrát s paralelním výpočtem pomocí technologie CUDA, kterou podporují grafické karty nVidia. Pracuji ovšem na Macbooku Pro, který má grafickou kartu Intel Iris, a tudíž žádná CUDA. Naštěstí můj starý Acer má grafickou kartu nVidia a běží na něm Linux, takže jsem zachráněn.
Ovšem abych mohl s CUDA pracovat, musím veškeré zdrojáky dostat na starý Acer (který mám dostupný na síti), tam je zkompilovat a spustit. Což je proces, který je během vývoje dost otravný.
Díky tomu, že OS X a Linux jsou POSIXové systémy, napsal jsem si tedy bashový script, který tento proces kompletně automatizuje přes SSH a s pomocí pár utilit.
Výsledný script je uveden na konci příspěvku.
#Začínáme
Vytvoříme si bashový script, nejlépe do /usr/bin
nebo jiného adresáře, který máme v systémové cestě.
1 | touch /usr/bin/rbuild |
A do souboru zapíšeme hlavičku, která nám říka, aby se script spustil pod interpretem BASH:
1 |
#Konfigurace
Konfiguraci jsem nechtěl řešit nijak složitě, a proto jen načteme další bashový soubor ./rbuild.conf
, ve kterém zapíšeme konfigurační proměnné. V případě, že soubor neexistuje, vyhodíme chybu a zobrazíme usage. Náš bashový script budeme spuštět vždy z adresáře projektu, a proto konfigurační soubor vytvoříme v něm, a ve scriptu k němu budeme přistupovat pomocí relativní cesty.
rbuild
1 | #Read config |
Všiměte si zvláštní sekvence znaků \x1B[91m
, ty nám do výpisu dávají trochu barev :)
./rbuild.conf
1 | USERNAME=user |
#Parsování argumentů z příkazové řádky
Jelikož náš script je trochu sofistikovanější, je potřeba vyparsovat argumenty scriptu. To provedeme pomocí utility getopts.
rbuild
1 | #Parse args |
Příkaz shift
nám posune seznam argumentů, které se vyparsovaly, a díky tomu proměnná $1
bude obsahovat argumenty, které zůstaly (tedy náchází se za těmi vyparsovanými).
Dále si do proměnné MAKE_ARG
uložíme další argument, jelikož funkce (kterou později napíšeme) k němu nebude mít přístup.
#Seznam ignorovaných souborů a adresářů
Zdrojové kódy potřebujeme synchronizovat na vzdálený stroj, ale zároveň bychom rádi některé soubory vynechali, např. ty, které jsme si zkompilovali lokálně. Proto si vytvoříme soubor ./rbuild.ignore
, který bude na každém řádku obsahovat soubory, které chceme vynechat.
Jelikož utilita rsync, kterou budeme používat, vyhodí chybu pokud soubor neexistuje, scriptem jej projistotu vytvoříme.
1 | #Create exclude file list |
#Nápověda
Jsme zvyklí na to, že pokud příkaz spustíme s neplatnými parametry, vypíše se nám nápověda (tzv. usage). Proto si na začátek scriptu (pod hlavičku) vytvoříme funkci usage, na kterou jsme se již odkazovali výše, a která nám vypíše nápovědu.
1 | function usage { |
#Synchronizace, kompilace a spuštění
Nyní si pod usage
vytvoříme funkci remote_build
.
1 | function remote_build { |
Do funkce zapíšeme volání utility rsync, která nám zařídí synchronizaci lokálních souborů projektu s těmi vzdálenými a to velmi efektivně (jen rozdíly + komprese).
Můžete si všimnout uvedených přepínačů –exclude
a –exclude-from
, kterými říkáme, jaké soubory a adresáře chceme vynechat.
1 | #Start sync |
Nyní se přes SSH přesuneme do vzdáleného adresáře projektu, zavoláme make
a případně spustíme příkaz, který jsme nastavili přepínačem -c
.
1 | #Build and run |
Nakonec celého scriptu přidáme následující řádku, která nám zavolá funkci remote_build
, pokud konfigurace šla hladce.
1 | #Build |
POZOR: Script počítá s použitím utility make a souboru Makefile
#Použití
Mějme testovací projekt s následující souborovou strukturou:
1 | ./projekt |
Soubor rbuild.conf
vytvoříme dle výše uvedeného příkladu.
Do souboru rbuild.ignore
zapíšeme následující řádky, abychom vynechali lokálně zkompilované soubory:
1 | build/* |
#Makefile
Vytvoříme si jednoduchý Makefile
s targety build
a clean
:
POZOR: Makefile strikně využívá indentaci tabelátory, takže pokud následující kód zkopírujete, musíte jej přeformátovat.
1 | .PHONY: build |
#main.cpp
Vytvoříme jednoduchý C++ hello world soubor ./src/main.cpp
:
1 |
|
#Kompilace
Zkusíme si projekt zkompilovat lokálně a následně spustit:
1 | projekt user$ make |
A nyní projekt zkusíme zkompilovat vzdáleně a výsledný program spustit:
1 | projekt user$ rbuild -c ./build/main |
Hotovo, projekt zkompilován a aplikace úspěšně spuštěna!
Nakonec si ještě ukážeme, jak utilitě make předat target clean:
1 | projekt user$ rbuild clean |
#Závěrem
Doufám, že vám tento příspěvek byl k něčemu užitečný. Mě script ušetřil spoustu času a navíc jsem se naučil zajímavé věci:
#Výsledný script
1 |
|