Quali fattori sociali o tecnici hanno portato all'ascesa della mentalità CIY?
La causa principale è ovviamente la ragione tecnica: la portabilità binaria è più difficile della portabilità della fonte . Al di fuori dei pacchetti di distribuzione, la maggior parte dei software gratuiti è ancora disponibile solo in formato sorgente perché è molto più conveniente per gli autori / manutentori.
Fino a quando le distribuzioni Linux non hanno iniziato a impacchettare la maggior parte delle cose che la gente media vorrebbe usare, l'unica opzione era quella di ottenere il sorgente e compilarlo per il proprio sistema. I venditori di Unix commerciali in genere non includevano roba che quasi tutti volevano (ad esempio una bella shell come GNU bash
o simile), solo la propria implementazione di sh
e / o csh
, quindi era necessario creare roba da soli se tu (come amministratore di sistema) volevi per fornire un piacevole ambiente Unix ai tuoi utenti per un uso interattivo.
La situazione ora, con la maggior parte delle persone che è l'unico amministratore e unico utente della macchina seduta sul desktop, è molto diversa dal tradizionale modello Unix. Un amministratore di sistema ha mantenuto il software sul sistema centrale e sul desktop di tutti. (Spesso avendo le workstation delle persone semplicemente montate su NFS /opt
e /usr/local/
dal server centrale e installando roba lì.)
Prima di cose come .NET e Java, la vera portabilità binaria su diverse architetture CPU era impossibile. La cultura di Unix si è evoluta con la portabilità dei sorgenti come impostazione predefinita per questo motivo, con pochi sforzi anche per provare ad abilitare la portabilità binaria fino ai recenti sforzi di Linux come LSB. Ad esempio, POSIX ( il principale standard Unix) tenta solo di standardizzare la portabilità del codice sorgente, anche nelle versioni recenti.
Fattore culturale correlato: I primi AT&T commerciali Unix venivano forniti con il codice sorgente (sui nastri). Non hai hai per costruire il sistema dai sorgenti, è stato solo lì nel caso in cui si voleva vedere come qualcosa di veramente funzionato quando i documenti non erano sufficienti.
Wikipedia dice :
"La politica Unix di ampia documentazione online e (per molti anni) pronto accesso a tutto il codice sorgente del sistema ha sollevato le aspettative del programmatore e ha contribuito al lancio del 1983 del movimento di software libero".
Non sono sicuro di cosa abbia motivato questa decisione, dal momento che dare ai clienti l'accesso al codice sorgente del software commerciale è inaudito in questi giorni. Esistono chiaramente alcuni preconcetti culturali in questa direzione, ma forse ciò è nato dalle radici di Unix come sistema operativo portatile scritto principalmente in C (non linguaggio assembly) che poteva essere compilato per hardware diverso. Penso che molti sistemi operativi precedenti avessero scritto più codice per una CPU specifica, quindi la portabilità a livello di sorgente era uno dei punti di forza di Unix. (Potrei sbagliarmi su questo; non sono un esperto dei primi Unix, ma Unix e C sono correlati.)
La distribuzione di software in formato sorgente è di gran lunga il modo più semplice per consentire alle persone di adattarlo al sistema su cui vogliono che funzioni. (Utenti finali o persone che lo confezionano per una distribuzione Linux). Se il software è già stato impacchettato da / per una distribuzione, gli utenti finali possono semplicemente utilizzarlo.
Ma è troppo aspettarsi che gli autori della maggior parte dei pacchetti facciano binari per ogni possibile sistema. Alcuni importanti progetti forniscono file binari per alcuni casi comuni (in particolare x86 / windows in cui il sistema operativo non viene fornito con un ambiente di compilazione e il fornitore del sistema operativo ha posto l'accento sulla distribuzione di programmi di installazione solo binari).
Far funzionare un software su un sistema diverso da quello utilizzato dall'autore potrebbe anche richiedere alcune piccole modifiche, che sono facili con l'origine . Un piccolo programma unico che qualcuno ha scritto per grattarsi il prurito probabilmente non è mai stato testato sulla maggior parte dei sistemi oscuri. Avere la fonte rende possibile apportare tali modifiche. L'autore originale potrebbe aver trascurato qualcosa o intenzionalmente scritto meno codice portatile perché ha risparmiato molto tempo. Anche i principali pacchetti come Info-ZIP non avevano subito tester su ogni piattaforma e avevano bisogno che le persone inviassero le loro patch di portabilità quando i problemi venivano scoperti.
(Ci sono altri tipi di problemi di portabilità a livello di sorgente che solo accadere a causa di differenze nella costruzione env, e non sono davvero rilevanti per il problema qui. Con stile Java portabilità binario, auto-strumenti ( autoconf
/ auto-make
) e cose simili come cmake
wouldn sarebbe necessario. E non avremmo cose come alcuni sistemi richiedono l'inclusione <netinet/in.h>
invece di<arpa/inet.h>
perntohl(3)
. (E forse non avremmo ntohl()
o qualsiasi altra roba di ordine byte in primo luogo!)
Sviluppo regolarmente in linguaggi .NET, quindi non sono analfabeta per computer.
Compilare una volta, correre ovunque è uno degli obiettivi principali di .NET e anche di Java, quindi è giusto dire che interi linguaggi sono stati inventati nel tentativo di risolvere questo problema e la tua esperienza di sviluppo è con uno di essi. Con .NET, il tuo binario viene eseguito su un ambiente di runtime portatile (CLR) . Java chiama il suo ambiente di runtime Java Virtual Machine . Devi solo distribuire un binario che funzionerà su qualsiasi sistema (almeno, qualsiasi sistema in cui qualcuno ha già implementato una JVM o CLR). Puoi ancora avere problemi di portabilità come, /
vs \
separatori di percorso, o come stampare, o dettagli del layout della GUI, ovviamente.
Un sacco di software è scritto in lingue che sono completamente compilate in codice nativo . Non esiste un .net
bytecode o java, solo un codice macchina nativo per la CPU su cui verrà eseguito, memorizzato in un formato di file eseguibile non portatile. C e C ++ ne sono il principale esempio, specialmente nel mondo Unix. Ovviamente questo significa che un binario deve essere compilato per una specifica architettura della CPU.
Le versioni della libreria sono un altro problema . Le librerie possono e spesso mantengono stabile l'API a livello di sorgente durante la modifica dell'ABI a livello binario. (Vedi Differenza tra API e ABI .) Ad esempio, l'aggiunta di un altro membro a un opaco struct
modifica comunque le sue dimensioni e richiede una ricompilazione con le intestazioni per la nuova versione della libreria per qualsiasi codice che alloca spazio per tale struttura, sia esso dinamico (malloc ), statico (globale) o automatico (locale nello stack).
Anche i sistemi operativi sono importanti . Un sapore diverso di Unix per la stessa architettura CPU può avere diversi formati di file binari, un ABI differente per le chiamate di sistema e differenti valori numerici per le costanti come fopen(3)
's O_RDONLY
, O_APPEND
,O_TRUNC
.
Si noti che anche un binario collegato dinamicamente ha ancora un codice di avvio specifico del sistema operativo che viene eseguito in precedenza main()
. Su Windows, questo è crt0
. Unix e Linux hanno la stessa cosa, in cui un po 'di codice C-Runtime Startup è staticamente collegato in ogni binario. Immagino che in teoria potresti progettare un sistema in cui anche quel codice era collegato dinamicamente e parte di libc o del linker stesso, ma non è così che funzionano in pratica su qualsiasi sistema operativo di cui sono a conoscenza. Ciò risolverebbe solo il problema ABI delle chiamate di sistema, non il problema dei valori numerici per le costanti per le funzioni di libreria standard. (Normalmente le chiamate di sistema vengono fatte tramite le funzioni wrapper libc: un normale binario Linux x86-64 per il sorgente che usa mmap()
non includerà l' syscall
istruzione, solo uncall
istruzioni per la funzione wrapper libc con lo stesso nome.
Questo è uno dei motivi per cui non puoi semplicemente eseguire i binari i386-FreeBSD su i386-Linux. (Per un po ', il kernel Linux ha avuto un livello di compatibilità delle chiamate di sistema. Penso che almeno uno dei BSD possa eseguire binari Linux, con un livello di compatibilità simile, ma ovviamente sono necessarie librerie Linux.)
Se si desidera distribuire i binari, è necessario crearne uno separato per ogni combinazione di CPU / sistema operativo + versione / versione installata-libreria-versioni .
Negli anni '80 / '90, c'erano molti diversi tipi di CPU di uso comune per i sistemi Unix (MIPS, SPARC, POWER, PA-RISC, m68k, ecc.) E molti tipi diversi di Unix (IRIX, SunOS, Solaris, AIX, HP-UX, BSD, ecc.).
E questo è solo un sistema Unix . Molti pacchetti sorgente compilerebbero e funzionerebbero anche su altri sistemi, come VAX / VMS, MacOS (m68k e PPC), Amiga, PC / MS-DOS, Atari ST, ecc.
Esistono ancora molte architetture e sistemi operativi della CPU, sebbene ora gran parte dei desktop sia x86 con uno dei tre sistemi operativi principali.
Quindi ci sono già più combinazioni CPU / OS di quelle a cui puoi agitare, anche prima di iniziare a pensare alle dipendenze da librerie di terze parti che potrebbero trovarsi in versioni diverse su sistemi diversi. (Tutto ciò che non è confezionato dal fornitore del sistema operativo dovrebbe essere installato a mano.)
Anche i percorsi compilati nel file binario sono specifici del sistema. (Ciò consente di risparmiare RAM e tempo rispetto alla lettura da un file di configurazione all'avvio). I sistemi Unix della vecchia scuola avevano in genere un sacco di cose personalizzate a mano, quindi non c'è modo di fare ipotesi valide su cosa sia dove.
La distribuzione di file binari era totalmente impossibile per Unix di vecchia scuola, tranne per i grandi progetti commerciali che possono permettersi di costruire e testare su tutte le principali combinazioni .
Anche fare binari per giusto i386-linux-gnu
ed amd64-linux-gnu
è difficile. Molto tempo e sforzi sono stati spesi in cose come Linux Standard Base per rendere possibili i binari portatili . Anche il collegamento statico dei binari non risolve tutto. (es. come dovrebbe stampare un programma di elaborazione testi su un sistema RedHat rispetto a un sistema Debian? In che modo l'installazione dovrebbe aggiungere un utente o un gruppo per un demone e organizzare l'esecuzione dello script di avvio dopo ogni riavvio?) esempi, perché la ricompilazione dalla fonte non li risolve.
Oltre a tutto ciò, ai giorni nostri la memoria era più preziosa di quanto non sia ora. Tralasciando le funzionalità opzionali in fase di compilazione è possibile creare file binari più piccoli (meno dimensioni del codice) che utilizzano anche meno memoria per le loro strutture di dati. Se una funzione richiede un membro aggiuntivo in ogni istanza di un determinato class
o struct
per tracciare qualcosa, la disabilitazione di tale funzione ridurrà l'oggetto di 4 byte (ad esempio), il che è utile se si tratta di un oggetto di cui il programma alloca 100k.
Oggigiorno, le funzioni opzionali di compilazione vengono spesso utilizzate per rendere opzionali librerie extra. ad esempio, è possibile compilare ffmpeg
con o senza libx264
, libx265
, libvorbis
, e molte altre librerie per specifiche video / encoder audio, la gestione dei sottotitoli, ecc ecc Più comunemente, un sacco di cose possono essere compilati con o senza libreadline
: se è disponibile quando si esegue ./configure
, il il binario risultante dipenderà dalla libreria e fornirà un editing di riga di fantasia durante la lettura da un terminale. In caso contrario, il programma utilizzerà un supporto di fallback per leggere le righe dallo stdin con fgets()
o qualcosa del genere.)
Alcuni progetti utilizzano ancora funzionalità opzionali per tralasciare il codice non necessario per motivi di prestazioni. ad es. il kernel Linux stesso può essere compilato senza il supporto SMP (ad es. per un sistema incorporato o un desktop antico), nel qual caso gran parte del blocco è più semplice. O con molte altre funzionalità opzionali che influiscono su alcuni dei codici core, non solo tralasciando i driver o altre funzionalità hardware. (Sebbene le opzioni di configurazione specifiche dell'arco e dell'hardware rappresentino gran parte del codice sorgente totale. Vedi Perché il kernel Linux ha oltre 15 milioni di righe di codice? )