Jakie czynniki społeczne lub techniczne doprowadziły do wzrostu mentalności CIY?
Przyczyną jest oczywiście przyczyna techniczna: Przenośność binarna jest trudniejsza niż przenośność źródła . Poza pakietami dystrybucyjnymi większość Wolnego oprogramowania jest nadal dostępna tylko w formie źródłowej, ponieważ jest to znacznie wygodniejsze dla autora (autorów) / opiekunów.
Dopóki dystrybucje Linuksa nie zaczęły pakować większości rzeczy, z których przeciętni ludzie chcieliby korzystać, jedyną opcją było zdobycie źródła i skompilowanie go dla własnego systemu. Dostawcy komercyjnych systemów uniksowych zwykle nie zawierali rzeczy, które prawie wszyscy chcieli (np. Ładnej powłoki, takiej jak GNU bash
lub podobna), tylko ich własną implementację sh
i / lub csh
, więc trzeba było zbudować coś samodzielnie, jeśli (jako administrator systemu) chciałeś aby zapewnić użytkownikom przyjemne środowisko uniksowe do interaktywnego użytku.
Obecna sytuacja, w której większość ludzi jest jedynym administratorem i jedynym użytkownikiem maszyny siedzącej na pulpicie, różni się znacznie od tradycyjnego modelu Uniksa. Sysadmin utrzymywał oprogramowanie w systemie centralnym i na pulpicie wszystkich. (Często wystarczy, że stacje robocze są po prostu podłączane do systemu plików NFS /opt
i /usr/local/
z serwera centralnego, i instalują tam rzeczy.)
Przed rzeczami takimi jak .NET i Java prawdziwa przenośność binarna w różnych architekturach procesorów była niemożliwa. Kultura uniksowa ewoluowała z domyślną przenośnością źródła z tego powodu, przy niewielkim wysiłku, nawet próbując włączyć przenośność binarną aż do ostatnich wysiłków Linuksa, takich jak LSB. Na przykład, POSIX ( głównym standardem Unix) próbuje jedynie w celu ujednolicenia przenoszenia źródłowego, nawet w najnowszych wersjach.
Powiązany czynnik kulturowy: wczesny komercyjny system AT&T Unix był dostarczany z kodem źródłowym (na taśmach). Nie musisz budować systemu ze źródła, było to na wypadek, gdybyś chciał zobaczyć, jak coś naprawdę działa, gdy dokumenty nie są wystarczające.
Wikipedia mówi :
„Polityka Uniksa dotycząca obszernej dokumentacji on-line i (przez wiele lat) łatwego dostępu do całego kodu źródłowego systemu podniosła oczekiwania programistów i przyczyniła się do uruchomienia w 1983 roku ruchu wolnego oprogramowania”.
Nie jestem pewien, co było przyczyną tej decyzji, ponieważ zapewnienie klientom dostępu do kodu źródłowego oprogramowania komercyjnego jest obecnie niespotykane. W tym kierunku wyraźnie widać pewne wczesne uprzedzenia kulturowe, ale być może wyrosły one z korzeni Unixa jako przenośnego systemu operacyjnego napisanego głównie w C (nie w asemblerze), który można skompilować dla innego sprzętu. Myślę, że wiele wcześniejszych systemów operacyjnych miało więcej kodu napisanego w asm dla konkretnego procesora, więc przenośność na poziomie źródła była jedną z mocnych stron wczesnego Uniksa. (Mogę się mylić; nie jestem ekspertem od wczesnego Uniksa, ale Unix i C są ze sobą powiązane).
Dystrybucja oprogramowania w formie źródłowej jest zdecydowanie najłatwiejszym sposobem, aby pozwolić ludziom na dostosowanie go do dowolnego systemu, na którym ma działać. (Użytkownicy końcowi lub osoby pakujące go dla dystrybucji Linuksa). Jeśli oprogramowanie zostało już spakowane przez / dla dystrybucji, użytkownicy końcowi mogą z niego korzystać.
Ale to zbyt wiele, by oczekiwać, że autorzy większości pakietów sami tworzą pliki binarne dla każdego możliwego systemu. Niektóre duże projekty zapewniają pliki binarne dla kilku typowych przypadków (szczególnie x86 / Windows, w których system operacyjny nie jest dostarczany ze środowiskiem kompilacji, a producent systemu operacyjnego położył duży nacisk na dystrybucję instalatorów zawierających tylko pliki binarne).
Uzyskanie oprogramowania do pracy w innym systemie niż ten, którego użył autor, może nawet wymagać niewielkich zmian, które są łatwe w przypadku źródła . Mały jednorazowy program, który ktoś napisał, aby podrapać swój własny świąd, prawdopodobnie nigdy nie był testowany na większości mało znanych systemów. Posiadanie źródła umożliwia dokonanie takich zmian. Oryginalny autor mógł coś przeoczyć lub celowo napisać mniej przenośny kod, ponieważ zaoszczędził wiele czasu. Nawet duże pakiety, takie jak Info-ZIP, nie miały od razu testerów na każdej platformie i wymagały od ludzi przesyłania poprawek przenośności w miarę wykrycia problemów.
(Istnieją inne rodzaje problemów przenośności źródło szczebla, które zdarzają się tylko z powodu różnic w kompilacji env i nie są bardzo istotne z punktu widzenia problem tutaj. Z Java stylu binarnej przenośności, automatyczne narzędzia ( autoconf
/ auto-make
) i podobne rzeczy jak cmake
Wouldn „t być potrzebne. i nie mielibyśmy rzeczy jak niektóre systemy wymagają włączenia <netinet/in.h>
zamiast<arpa/inet.h>
ontohl(3)
. (A może nie mielibyśmy ntohl()
ani jakiekolwiek inne rzeczy bajt rzędu na pierwszym miejscu!)
Regularnie rozwijam się w językach .NET, więc nie jestem analfabetą komputerową.
Jednorazowa kompilacja, uruchomienie w dowolnym miejscu jest jednym z głównych celów platformy .NET i Java, więc można śmiało powiedzieć, że całe języki zostały wymyślone w celu rozwiązania tego problemu , a twoje doświadczenie deweloperskie dotyczy jednego z nich. Dzięki .NET Twój plik binarny działa w przenośnym środowisku wykonawczym (CLR) . Java nazywa to środowisko wykonawcze Java Virtual Machine . Musisz tylko dystrybuować jeden plik binarny, który będzie działał w dowolnym systemie (przynajmniej w każdym systemie, w którym ktoś już zaimplementował JVM lub CLR). Nadal można mieć problemy przenośności jak, /
vs \
separatorów ścieżki, albo jak wydrukować lub GUI układ szczegóły, oczywiście.
Wiele programów jest napisanych w językach w pełni skompilowanych w natywnym kodzie . Nie ma .net
kodu bajtowego Java lub tylko natywny kod maszynowy dla procesora, na którym będzie on uruchomiony, przechowywany w nieprzenośnym formacie pliku wykonywalnego. C i C ++ są głównymi tego przykładami, szczególnie w świecie Uniksa. Oczywiście oznacza to, że plik binarny musi zostać skompilowany dla określonej architektury procesora.
Wersje bibliotek to kolejny problem . Biblioteki mogą i często utrzymują stabilność API na poziomie źródła podczas zmiany ABI na poziomie binarnym. (Zobacz Różnica między API i ABI .) Na przykład dodanie innego elementu do nieprzezroczystego struct
nadal zmienia jego rozmiar i wymaga ponownej kompilacji z nagłówkami dla nowej wersji biblioteki dla dowolnego kodu, który przydziela miejsce dla takiej struktury, czy to dynamicznej (malloc ), statyczny (globalny) lub automatyczny (lokalny na stosie).
Ważne są także systemy operacyjne . Inny smak Uniksa na tej samej architekturze procesora może mieć różne formaty plików binarnych, inny ABI do wykonywania połączeń systemowych i różnych wartości liczbowych dla stałych takich jak fopen(3)
„s O_RDONLY
, O_APPEND
,O_TRUNC
.
Zauważ, że nawet dynamicznie połączony plik binarny nadal ma jakiś kod startowy specyficzny dla systemu operacyjnego, który działał wcześniej main()
. W systemie Windows tak jest crt0
. Unix i Linux mają to samo, gdzie część kodu startowego C-Runtime jest statycznie połączona z każdym plikiem binarnym. Sądzę, że teoretycznie możesz zaprojektować system, w którym ten kod byłby również dynamicznie połączony, i był częścią libc lub samego dynamicznego linkera, ale nie wiem, jak to działa w praktyce w każdym systemie operacyjnym. To rozwiązałoby jedynie problem ABI wywołania systemowego, a nie problem wartości liczbowych dla stałych dla funkcji biblioteki standardowej. (Zwykle wywołania systemowe są wykonywane za pomocą funkcji opakowania libc: normalny plik binarny dla systemu Linux x86-64 dla źródła, który używa mmap()
, nie będzie zawierał syscall
instrukcji, a tylkocall
instrukcja do funkcji otoki libc o tej samej nazwie.
Jest to część tego, dlaczego nie można po prostu uruchamiać plików binarnych i386-FreeBSD w systemie i386-Linux. (Przez pewien czas jądro Linuksa miało warstwę kompatybilności z wywołaniami systemowymi. Myślę, że przynajmniej jeden z BSD może uruchamiać binaria Linuksa z podobną warstwą kompatybilności, ale oczywiście potrzebujesz bibliotek Linuksa.)
Jeśli chcesz dystrybuować pliki binarne, musisz utworzyć osobny dla każdej kombinacji CPU / OS-smak + wersja / wersja zainstalowanej biblioteki .
W latach 80. / 90. istniało wiele różnych rodzajów procesorów powszechnie używanych w systemach Unix (MIPS, SPARC, POWER, PA-RISC, m68k itp.) Oraz wiele różnych odmian Uniksa (IRIX, SunOS, Solaris, AIX, HP-UX, BSD itp.).
A to tylko systemy uniksowe . Wiele pakietów źródłowych również kompiluje się i działa na innych systemach, takich jak VAX / VMS, MacOS (m68k i PPC), Amiga, PC / MS-DOS, Atari ST itp.
Nadal istnieje wiele architektur procesorów i systemów operacyjnych, choć obecnie zdecydowana większość komputerów stacjonarnych to x86 z jednym z trzech głównych systemów operacyjnych.
Tak więc jest już więcej kombinacji procesora / systemu operacyjnego, niż można sobie wyobrazić, nawet zanim zaczniesz myśleć o zależnościach od bibliotek innych firm, które mogą być w różnych wersjach w różnych systemach. (Wszystko, co nie zostało spakowane przez dostawcę systemu operacyjnego, musiałoby zostać zainstalowane ręcznie).
Wszelkie ścieżki wkompilowane w plik binarny są również specyficzne dla systemu. (Oszczędza to pamięć RAM i czas w porównaniu do odczytu ich z pliku konfiguracyjnego przy uruchomieniu). Old-schoolowe systemy uniksowe zazwyczaj zawierały wiele ręcznie dostosowywanych rzeczy, więc nie ma sposobu, abyś mógł przyjąć jakiekolwiek uzasadnione założenia co do tego, gdzie jest.
Dystrybucja plików binarnych była całkowicie niemożliwa dla old-schoolowego Uniksa, z wyjątkiem dużych komercyjnych projektów, których stać na zbudowanie i przetestowanie wszystkich głównych kombinacji .
Nawet tworzenie binariów za słuszne i386-linux-gnu
i amd64-linux-gnu
jest trudne. Wiele czasu i wysiłku poświęcono na takie rzeczy jak Linux Standard Base, aby umożliwić przenośne pliki binarne . Nawet statycznie łączące pliki binarne nie rozwiązują wszystkiego. (np. jak program do edycji tekstu powinien drukować w systemie RedHat w porównaniu z systemem Debian? W jaki sposób instalator powinien dodać użytkownika lub grupę do demona i ustawić uruchamianie skryptu startowego po każdym ponownym uruchomieniu?) Nie są świetne przykłady, ponieważ ponowna kompilacja ze źródła ich nie rozwiązuje.
Poza tym wspomnienia w tamtych czasach były cenniejsze niż obecnie. Pozostawienie opcjonalnych funkcji w czasie kompilacji może stworzyć mniejsze pliki binarne (mniejszy rozmiar kodu), które również zużywają mniej pamięci dla swoich struktur danych. Jeśli funkcja wymagała dodatkowego elementu w każdym przypadku określonego elementu class
lub struct
do śledzenia czegoś, wyłączenie tej funkcji spowoduje zmniejszenie obiektu o 4 bajty (na przykład), co jest miłe, jeśli jest to obiekt, który program przydziela 100 tys.
Opcjonalne funkcje czasu kompilacji są obecnie najczęściej używane, aby dodatkowe biblioteki były opcjonalne. Na przykład można skompilować ffmpeg
z lub bez libx264
, libx265
, libvorbis
, i wiele innych bibliotek dla konkretnego filmu / kodery audio, obsługę napisów, itp itd. Częściej, wiele rzeczy może być skompilowany z lub bez libreadline
: jeśli jest ona dostępna po uruchomieniu ./configure
, wynikowy plik binarny będzie zależeć od biblioteki i zapewni fantazyjną edycję linii podczas czytania z terminala. Jeśli tak nie jest, program użyje wsparcia rezerwowego, aby po prostu odczytać linie ze standardowego wejścia fgets()
lub czegoś.)
Niektóre projekty nadal używają opcjonalnych funkcji, aby pominąć niepotrzebny kod ze względu na wydajność. np. samo jądro Linuksa można zbudować bez obsługi SMP (np. dla systemu osadzonego lub starożytnego pulpitu), w którym to przypadku wiele blokowania jest prostszych. Lub z wieloma innymi opcjonalnymi funkcjami, które wpływają na niektóre podstawowe kody, nie tylko pomijając sterowniki lub inne funkcje sprzętowe. (Chociaż opcje konfiguracji specyficzne dla architektury i sprzętu stanowią dużą część całego kodu źródłowego. Zobacz Dlaczego jądro Linuksa ma ponad 15 milionów linii kodu? )