Quels facteurs sociaux ou techniques ont conduit à la montée de la mentalité CIY?
La cause première est bien évidemment la raison technique: la portabilité binaire est plus difficile que la portabilité source . En dehors des packages de distribution, la plupart des logiciels gratuits ne sont toujours disponibles que sous forme source, car cela est beaucoup plus pratique pour les auteurs / mainteneurs.
Jusqu'à ce que les distributions Linux commencent à empaqueter la plupart des choses que les gens ordinaires voudraient utiliser, votre seule option était d'obtenir la source et de la compiler pour votre propre système. Les fournisseurs commerciaux Unix n'incluaient généralement pas des éléments que presque tout le monde voulait (par exemple un joli shell comme GNU bash
ou similaire), juste leur propre implémentation de sh
et / ou csh
, donc vous deviez créer des éléments vous-même si vous (en tant qu'administrateur système) vouliez pour fournir un environnement Unix agréable à vos utilisateurs pour une utilisation interactive.
La situation actuelle, la plupart des gens étant le seul administrateur et le seul utilisateur de la machine assis sur leur bureau, est très différente du modèle Unix traditionnel. Un administrateur système a géré le logiciel sur le système central et sur le bureau de chacun. (Souvent , en installant simplement les postes de travail des gens sur NFS /opt
et à /usr/local/
partir du serveur central, et en y installant des éléments.)
Avant des choses comme .NET et Java, la véritable portabilité binaire entre différentes architectures CPU était impossible. La culture Unix a évolué avec la portabilité source comme valeur par défaut pour cette raison, avec peu d'efforts pour même essayer d'activer la portabilité binaire jusqu'aux récents efforts Linux comme LSB. Par exemple, POSIX ( le principal standard Unix) tente uniquement de standardiser la portabilité des sources, même dans les versions récentes.
Facteur culturel connexe: AT&T Unix commercial est venu avec le code source (sur bandes). Vous ne l' avez pas avoir à construire le système de la source, il était juste là au cas où vous vouliez voir comment quelque chose vraiment travaillé quand les documents ne suffisaient pas.
Wikipédia dit :
"La politique Unix de documentation en ligne complète et (pendant de nombreuses années) un accès rapide à tout le code source du système a suscité les attentes des programmeurs et a contribué au lancement en 1983 du mouvement du logiciel libre."
Je ne sais pas ce qui a motivé cette décision, car donner aux clients l'accès au code source des logiciels commerciaux est inconnu de nos jours. Il y a clairement quelques premiers biais culturels dans cette direction, mais cela est peut-être né des racines d'Unix en tant qu'OS portable écrit principalement en C (pas en langage assembleur) qui pourrait être compilé pour différents matériels. Je pense que de nombreux systèmes d'exploitation antérieurs avaient plus de code écrit en asm pour un processeur spécifique, donc la portabilité au niveau de la source était l'une des premières forces d'Unix. (Je peux me tromper à ce sujet; je ne suis pas un expert des premiers Unix, mais Unix et C sont liés.)
La distribution de logiciels sous forme source est de loin le moyen le plus simple de permettre aux utilisateurs de l'adapter au système sur lequel ils souhaitent fonctionner. (Soit les utilisateurs finaux, soit les personnes qui le conditionnent pour une distribution Linux). Si le logiciel a déjà été empaqueté par / pour une distribution, les utilisateurs finaux peuvent simplement l'utiliser.
Mais c'est beaucoup trop de s'attendre à ce que les auteurs de la plupart des packages créent eux-mêmes des fichiers binaires pour chaque système possible. Certains projets majeurs fournissent des binaires pour quelques cas courants (en particulier x86 / windows où le système d'exploitation n'est pas fourni avec un environnement de génération, et le fournisseur du système d'exploitation a mis l'accent sur la distribution des programmes d'installation uniquement binaires).
Faire fonctionner un logiciel sur un système différent de celui utilisé par l'auteur peut même nécessiter quelques petites modifications, qui sont faciles avec la source . Un petit programme unique que quelqu'un a écrit pour se gratter n'a probablement jamais été testé sur la plupart des systèmes obscurs. La possession de la source permet d'effectuer de tels changements. L'auteur d'origine a peut-être oublié quelque chose ou écrit intentionnellement du code moins portable, car cela a fait gagner beaucoup de temps. Même les principaux packages comme Info-ZIP n'avaient pas de testeurs sur chaque plate-forme tout de suite, et avaient besoin de personnes pour envoyer leurs correctifs de portabilité lorsque des problèmes étaient découverts.
(Il existe d'autres types de problèmes de portabilité au niveau de la source qui ne se produisent qu'en raison de différences dans la construction env, et ne sont pas vraiment pertinents pour le problème ici. Avec la portabilité binaire de style Java, les outils automatiques ( autoconf
/ auto-make
) et des choses similaires comme le cmake
ferait Et nous n'aurions pas de choses comme certains systèmes nécessitent l'inclusion de <netinet/in.h>
au lieu de<arpa/inet.h>
forntohl(3)
(et peut-être que nous n'aurions pas ntohl()
ou tout autre ordre des octets en premier lieu!)
Je développe régulièrement dans des langages .NET, donc je ne suis pas analphabète en informatique.
Compiler une fois, exécuter n'importe où est l'un des principaux objectifs de .NET et de Java, il est donc juste de dire que des langages entiers ont été inventés dans le but de résoudre ce problème , et votre expérience de développement est avec l'un d'eux. Avec .NET, votre binaire s'exécute sur un environnement d'exécution portable (CLR) . Java appelle son environnement d'exécution la machine virtuelle Java . Vous n'avez besoin de distribuer qu'un seul binaire qui fonctionnera sur n'importe quel système (au moins, tout système où quelqu'un a déjà implémenté une JVM ou CLR). Vous pouvez toujours avoir des problèmes de portabilité comme, par /
rapport aux \
séparateurs de chemin, ou comment imprimer, ou les détails de mise en page de l'interface graphique, bien sûr.
De nombreux logiciels sont écrits dans des langages entièrement compilés en code natif . Il n'y a pas .net
ou de bytecode java, juste du code machine natif pour le CPU sur lequel il fonctionnera, stocké dans un format de fichier exécutable non portable. C et C ++ en sont les principaux exemples, en particulier dans le monde Unix. Évidemment, cela signifie qu'un binaire doit être compilé pour une architecture CPU spécifique.
Les versions de bibliothèque sont un autre problème . Les bibliothèques peuvent et maintiennent souvent l'API au niveau source stable tout en modifiant l'ABI au niveau binaire. (Voir Différence entre l'API et l'ABI .) Par exemple, l'ajout d'un autre membre à un opaque struct
change toujours sa taille et nécessite une recompilation avec des en-têtes pour la nouvelle version de la bibliothèque pour tout code qui alloue de l'espace pour une telle structure, qu'elle soit dynamique (malloc ), statique (global) ou automatique (local sur la pile).
Les systèmes d'exploitation sont également importants . Une autre saveur d'Unix pour la même architecture CPU peut avoir différents formats de fichiers binaires, un autre ABI pour faire des appels système, et différentes valeurs numériques pour les constantes comme fopen(3)
« s O_RDONLY
, O_APPEND
,O_TRUNC
.
Notez que même un binaire lié dynamiquement a toujours du code de démarrage spécifique au système d'exploitation qui s'exécute avant main()
. Sous Windows, c'est le cas crt0
. Unix et Linux ont la même chose, où du code de démarrage C-Runtime est lié statiquement à chaque binaire. Je suppose qu'en théorie, vous pourriez concevoir un système où ce code était également lié dynamiquement, et une partie de libc ou de l'éditeur de liens dynamique lui-même, mais ce n'est pas ainsi que les choses fonctionnent dans la pratique sur n'importe quel système d'exploitation que je connaisse. Cela ne résoudrait que le problème ABI d'appel système, pas le problème des valeurs numériques pour les constantes des fonctions de bibliothèque standard. (Normalement, les appels système sont effectués via les fonctions de wrapper libc: un binaire Linux x86-64 normal pour la source qui utilise mmap()
n'inclura pas l' syscall
instruction, juste uncall
instruction à la fonction wrapper libc du même nom.
C'est en partie pourquoi vous ne pouvez pas simplement exécuter des binaires i386-FreeBSD sur i386-Linux. (Pendant un certain temps, le noyau Linux avait une couche de compatibilité des appels système. Je pense qu'au moins un des BSD peut exécuter des binaires Linux, avec une couche de compatibilité similaire, mais vous avez bien sûr besoin de bibliothèques Linux.)
Si vous souhaitez distribuer des binaires, vous devez en créer un distinct pour chaque combinaison de versions CPU / OS-version + saveur / bibliothèque-installée .
Dans les années 80 et 90, il existait de nombreux types différents de CPU couramment utilisés pour les systèmes Unix (MIPS, SPARC, POWER, PA-RISC, m68k, etc.), et de nombreuses versions différentes d'Unix (IRIX, SunOS, Solaris, AIX, HP-UX, BSD, etc.).
Et ce ne sont que des systèmes Unix . De nombreux packages source compileraient et fonctionneraient également sur d' autres systèmes, comme VAX / VMS, MacOS (m68k et PPC), Amiga, PC / MS-DOS, Atari ST, etc.
Il existe encore de nombreuses architectures CPU et OS, bien que maintenant une grande majorité des ordinateurs de bureau exécutent x86 l'un des trois principaux OS.
Il y a donc déjà plus de combinaisons CPU / OS que vous ne pouvez le faire, avant même de commencer à penser aux dépendances sur des bibliothèques tierces qui pourraient être dans différentes versions sur différents systèmes. (Tout ce qui n'est pas emballé par le fournisseur du système d'exploitation devrait être installé à la main.)
Tous les chemins qui sont compilés dans le binaire sont également spécifiques au système. (Cela économise de la RAM et du temps par rapport à leur lecture dans un fichier de configuration au démarrage). Les systèmes Unix de la vieille école comportaient généralement beaucoup de choses personnalisées à la main, il n'y a donc aucun moyen de faire des hypothèses valides sur où.
La distribution de binaires était totalement irréalisable pour la vieille école Unix, sauf pour les grands projets commerciaux qui peuvent se permettre de construire et de tester toutes les principales combinaisons .
Même faire des binaires juste i386-linux-gnu
et amd64-linux-gnu
c'est difficile. Beaucoup de temps et d'efforts ont été consacrés à des choses comme la base standard Linux pour rendre les binaires portables possibles . Même la liaison statique de fichiers binaires ne résout pas tout. (par exemple, comment un programme de traitement de texte devrait-il s'imprimer sur un système RedHat par rapport à un système Debian? Comment l'installation devrait-elle ajouter un utilisateur ou un groupe pour un démon et organiser l'exécution de son script de démarrage après chaque redémarrage?) exemples, car la recompilation à partir de la source ne les résout pas.
En plus de tout cela, la mémoire de l'époque était plus précieuse qu'elle ne l'est aujourd'hui. La suppression des fonctionnalités facultatives au moment de la compilation peut créer des binaires plus petits (moins de taille de code) qui utilisent également moins de mémoire pour leurs structures de données. Si une fonctionnalité nécessitait un membre supplémentaire dans chaque instance d'un certain class
ou struct
pour suivre quelque chose, la désactivation de cette fonctionnalité réduira l'objet de 4 octets (par exemple), ce qui est bien si c'est un objet dont le programme alloue 100k.
De nos jours, les fonctionnalités de compilation facultatives sont le plus souvent utilisées pour rendre les bibliothèques supplémentaires facultatives. par exemple , vous pouvez compiler ffmpeg
avec ou sans libx264
, libx265
, libvorbis
et beaucoup d' autres bibliothèques pour les codeurs vidéo / audio spécifiques, la gestion des sous - titres, etc. , etc. Plus généralement, beaucoup de choses peuvent être compilés avec ou sans libreadline
: si elle est disponible lorsque vous exécutez ./configure
, la le binaire résultant dépendra de la bibliothèque et fournira une édition de ligne sophistiquée lors de la lecture à partir d'un terminal. Si ce n'est pas le cas, le programme utilisera un support de secours pour lire simplement les lignes de la stdin avec fgets()
ou quelque chose.)
Certains projets utilisent toujours des fonctionnalités facultatives pour supprimer le code inutile pour des raisons de performances. Par exemple, le noyau Linux lui-même peut être construit sans prise en charge SMP (par exemple pour un système intégré ou un ancien bureau), auquel cas une grande partie du verrouillage est plus simple. Ou avec de nombreuses autres fonctionnalités facultatives qui affectent une partie du code principal, et pas seulement en laissant de côté les pilotes ou d'autres fonctionnalités matérielles. (Bien que les options de configuration spécifiques à l'archive et au matériel représentent une grande partie du code source total. Voir Pourquoi le noyau Linux compte-t-il plus de 15 millions de lignes de code? )