Ostatnio używałem narzędzi do budowania projektu Nodejs w pracy, kiedy zdałem sobie sprawę, że główne narzędzie / system do budowania większości języków używa innego języka niż sam podstawowy język programowania.
Na przykład make nie używa C lub C ++ do pisania skryptów, a mrówka (ani Maven) nie używa Java jako języka skryptowego.
Nowsze języki, takie jak Ruby, używają tego samego języka do tworzenia narzędzi, takich jak rake , co ma dla mnie sens. Ale dlaczego nie zawsze tak było? Jakie są zalety posiadania narzędzia do budowania, które używa innego języka niż język podstawowy?
programming-languages
history
build-system
joshin4colours
źródło
źródło
make
ponownie (co zresztą jest zaimplementowane w C)?Odpowiedzi:
Wybór języka programowania do wykonania czegokolwiek musi zależeć od konkretnych cech tego celu, a nie od innych zadań związanych z tym projektem.
Narzędzie do budowania wykonuje bardzo specyficzną pracę i bez względu na język używany w głównym projekcie, narzędzie do budowania jest samo w sobie oprogramowaniem.
Próba powiązania głównego projektu i jego narzędzia kompilacji może być bardzo złą decyzją. To, czego powinieneś potrzebować z narzędziem do budowania, to przede wszystkim szybki proces prostych reguł, z szybkim zarządzaniem plikami i IO.
Jeśli języki takie jak Ruby same używają do implementacji swojego narzędzia do budowania, jest to bardziej związane z funkcjami tego języka niż z założoną potrzebą zachowania wszystkiego w tym samym języku.
źródło
Nie jest niemożliwe napisanie narzędzia do kompilacji, które używa języka takiego jak C lub Java jako języka skryptowego. Jednak narzędzia do budowania korzystają z bardziej deklaratywnych języków skryptowych. Wyobraź sobie, jak trudno jest napisać plik makefile (lub build.xml lub cokolwiek innego) w C.
Narzędzia do budowania korzystają z korzystania z DSL, zadania, dla których C nie jest szczególnie dobrym wyborem. C jest zbyt ogólny dla narzędzia do kompilacji i zbyt zainteresowany szczegółami podatnymi na błędy i niskopoziomowymi. Na przykład nie chcesz zajmować się jawnym zarządzaniem pamięcią w narzędziu kompilacyjnym! Więc nawet jeśli używasz składni podobnej do C, prawdopodobnie użyjesz funkcji wyrzucania elementów bezużytecznych w narzędziu skryptowym, w którym momencie możesz po prostu użyć dedykowanej DSL?
Ma to sens, że można do tego użyć Ruby, ponieważ jest to język wyższego poziomu, bardziej deklaratywny niż C lub Java. Zobacz także: Gradle, sbt.
źródło
Imagine the pain and boilerplate of writing a makefile (or build.xml, or whatever) in C.
Wyobraź sobie ból i bałagan związany z próbą wyrażenia nietrywialnej logiki warunkowej (no wiesz, standardowe imperatywne rzeczy) w deklaratywnym skrypcie XML. Och, czekaj, nie musisz sobie wyobrażać; prawdopodobnie musiałeś sobie z tym poradzić, i prawdopodobnie był to półtora bałagan, prawda? Kompilacje są jednym z najgorszych możliwych wyborów dla deklaratywnego języka skryptowego, ponieważ poważne problemy szybko kończą się na granicy deklaratywności, a te, które nie są wystarczająco proste, aby nie potrzebować narzędzia do kompilacji.Podajmy przykład z prawdziwego świata.
Około 15 lat temu pracowałem nad przeniesieniem dużego systemu napisanego w C z Unixa na Windows, było to około 3 milionów linii kodu. Aby dać ci wyobrażenie o skali, kompilacja na niektórych naszych systemach uniksowych (RS6000) zajęła 24 godziny, Windows mógł skompilować system w około 4 godziny.
(Mieliśmy również 2 miliony linii kodu w naszym własnym interpretowanym języku, ale postanowiliśmy nie używać naszego języka dla systemów kompilacji, ponieważ nigdy nie był przeznaczony do przetwarzania plików. Potrzebowaliśmy także systemu kompilacji do kompilacji kodu C, który implementował nasz język .)
W czasie, gdy system kompilacji był napisany jako mieszanka skryptów powłoki i tworzących pliki, nie były one przenośne dla systemu Windows - dlatego postanowiliśmy napisać własny system kompilacji.
Mogliśmy użyć C, jednak zdecydowaliśmy się na użycie Pythona, było kilka powodów. (W tym samym czasie przepisaliśmy również nasz system kontroli kodu źródłowego w pythonie, był to bardzo zintegrowany z systemem kompilacji, więc programiści mogli udostępniać pliki obiektowe dla modułów wtajemniczonych).
Większość naszego kodu można zbudować za pomocą kilku prostych reguł (tylko kilka tysięcy wierszy Pythona dla wszystkich platform, Windows, VMS i 6 wersji Uniksa), które zostały wyparte z konwencji nazewnictwa plików.
W tym czasie RegEx nie był bardzo standardem między systemami C na różnych platformach, Python wbudował w RegEx.
Kilka modułów wymagało niestandardowych kroków kompilacji, Python pozwalał na dynamiczne ładowanie plików klas. Zezwalaliśmy na użycie niestandardowej klasy do zbudowania modułu (lib), w oparciu o to, że w folderze znajduje się plik python o magicznej nazwie. To był powód zabójcy do używania Pythona.
Rozważaliśmy Javę, ale w tym momencie nie była ona wysyłana na wszystkie platformy.
(Interfejs użytkownika naszego systemu kontroli kodu źródłowego korzystał z przeglądarki internetowej, ponieważ była przenośna na całej platformie. To było 6 miesięcy przed połączeniem internetowym. Musieliśmy pobrać przeglądarkę przez X25!)
źródło
Krótka odpowiedź na to pytanie brzmi: właśnie tym jest narzędzie do budowania . Narzędzie, które automatyzuje korzystanie z innych narzędzi w celu zbudowania produktu końcowego z niektórych plików źródłowych. Jeśli piszemy skrypt kompilacji w tym samym języku, co sam produkt, wkraczamy w sferę narzędzi specyficznych dla języka, których nie można by uznać za narzędzia kompilacji w ten sam sposób.
Rodzi to pytanie - dlaczego kompilatory nie zapewniają automatyzacji kompilacji, do której jesteśmy przyzwyczajeni z narzędzi takich jak make? Na którą odpowiedź brzmi po prostu dlatego, że istnieje make . Filozofia Uniksa: „zrób jedną rzecz i zrób to dobrze” sugeruje, że dostarczenie tego * nie jest obowiązkiem kompilatora. To powiedziawszy, osobiście brałem udział w wywoływaniu bólów głowy i chciałbym wypróbować kompilator, który zapewnia własny „natywny” system kompilacji bez cudzysłowu.
Na przykład kompilatora zaprojektowanego w ten sposób, zobacz Jai Jona Blow'a (jeszcze nie wydany), język przeznaczony jako zamiennik C ++. Łącza do dyskusji i prezentacji kompilatora znajdują się tutaj . Ten język kompiluje się do kodu bajtowego, który działa w kompilatorze, przy czym kompilacja do pliku binarnego jest standardową funkcją udostępnianą przez bibliotekę, dostępną z kodu bajtowego. Celem jest umożliwienie zarówno automatyzacji budowy, jak i metaprogramowania w natywnej składni języka.
* Spojrzenie na Visual Studio Microsoftu pokaże przykład przeciwnej filozofii. :)
źródło
Narzędzie do budowania jest przede wszystkim narzędziem, podobnie jak „gcc”, „ls”, „awk” lub „git”. Podajesz narzędziu dane wejściowe (nazwę pliku, parametry itp.) I odpowiednio zrobi on pewne rzeczy.
Wszystkie te narzędzia umożliwiają przekazywanie danych wejściowych w sposób, który powinien być wystarczająco prosty do napisania i zrozumienia. W szczególnym przypadku narzędzi do kompilacji dane wejściowe to plik receptury, plik opisujący, w jaki sposób projekt przechodzi z plików źródłowych do gotowego produktu.
Jeśli Twój przepis jest tak prosty, jak przekazanie folderu zawierającego projekt i kompilator do użycia, wystarczy deklaratywny „język”. Gdy przepis staje się coraz bardziej skomplikowany, z większą logiką, kłopotliwe staje się posługiwanie się nim przy użyciu języków deklaratywnych i używa się bardziej ogólnych języków.
Teraz powinno być oczywiste, że nie ma związku między językiem używanym do pisania receptur kompilacji a językami używanymi do pisania kodu produktu, ponieważ mają one różne cele i wymagania. Nie ma żadnego związku nawet między językiem, w którym napisane jest narzędzie kompilacji, a „językiem”, w którym powinny zostać zapisane przepisy kompilacji. Zawsze używaj najlepszego narzędzia do pracy!
źródło