Welche sozialen oder technischen Faktoren haben zum Aufstieg der CIY-Mentalität geführt?
Die Hauptursache ist ganz offensichtlich der technische Grund: Die Binärportabilität ist schwieriger als die Quellportabilität . Außerhalb von Distributionspaketen ist die meiste freie Software immer noch nur in Quellform verfügbar, da dies für den Autor / die Betreuer wesentlich bequemer ist.
Bis Linux-Distributionen anfingen, die meisten Dinge zu verpacken, die Durchschnittsbürger verwenden möchten, bestand Ihre einzige Option darin, die Quelle abzurufen und für Ihr eigenes System zu kompilieren. Kommerzielle Unix-Anbieter enthielten normalerweise keine Inhalte, die fast jeder wollte (z. B. eine nette Shell wie GNU bashoder ähnliches), sondern nur ihre eigene Implementierung von shund / oder csh. Sie mussten also selbst Inhalte erstellen, wenn Sie (als Systemadministrator) dies wollten um Ihren Benutzern eine schöne Unix-Umgebung für die interaktive Verwendung bereitzustellen.
Die Situation, in der die meisten Benutzer der einzige Administrator und einzige Benutzer des Computers sind, der auf ihrem Desktop sitzt, unterscheidet sich erheblich vom traditionellen Unix-Modell. Ein Systemadministrator hat die Software auf dem zentralen System und auf jedem Desktop verwaltet. (Oft, indem die Workstations der Leute nur über NFS /optund /usr/local/vom zentralen Server bereitgestellt werden und dort Dinge installiert werden.)
Vor Dingen wie .NET und Java war eine echte Binärportabilität über verschiedene CPU-Architekturen hinweg unmöglich. Die Unix-Kultur hat sich aus diesem Grund mit der Quellportabilität als Standard entwickelt, wobei nur wenig Aufwand erforderlich war, um die Binärportabilität bis zu den jüngsten Linux-Bemühungen wie LSB zu aktivieren. Beispielsweise versucht POSIX ( der wichtigste Unix-Standard) nur, die Quellportabilität zu standardisieren, selbst in neueren Versionen.
Verwandter kultureller Faktor: Frühe kommerzielle AT & T Unix kam mit Quellcode (auf Bändern). Sie haben es nicht haben , um das System aus dem Quellcode zu bauen, war es dort nur, wenn Sie sehen wollte , wie etwas wirklich funktioniert , wenn die Dokumente nicht genug waren.
Wikipedia sagt :
"Die Unix-Richtlinie einer umfassenden Online-Dokumentation und (seit vielen Jahren) des sofortigen Zugriffs auf den gesamten Systemquellcode hat die Erwartungen der Programmierer geweckt und 1983 zur Einführung der Bewegung für freie Software beigetragen."
Ich bin mir nicht sicher, was diese Entscheidung motiviert hat, da es heutzutage unerhört ist, Kunden Zugriff auf den Quellcode kommerzieller Software zu gewähren. Es gibt eindeutig einige frühe kulturelle Vorurteile in diese Richtung, aber vielleicht ist dies auf Unix 'Wurzeln als tragbares Betriebssystem zurückzuführen, das hauptsächlich in C (nicht in Assemblersprache) geschrieben ist und für verschiedene Hardware kompiliert werden kann. Ich denke, viele frühere Betriebssysteme hatten mehr Code in asm für eine bestimmte CPU geschrieben, daher war die Portabilität auf Quellenebene eine der Stärken von Unix. (Ich kann mich irren; ich bin kein Experte für frühes Unix, aber Unix und C sind verwandt.)
Die Verteilung von Software in Quellform ist bei weitem die einfachste Möglichkeit, sie an das System anzupassen, auf dem sie ausgeführt werden soll. (Entweder Endbenutzer oder Leute, die es für eine Linux-Distribution verpacken). Wenn Software bereits von / für eine Distribution gepackt wurde, können Endbenutzer diese einfach verwenden.
Es ist jedoch viel zu viel zu erwarten, dass Autoren der meisten Pakete Binärdateien für jedes mögliche System selbst erstellen. Einige große Projekte bieten Binärdateien für einige häufige Fälle (insbesondere x86 / Windows, in denen das Betriebssystem nicht über eine Build-Umgebung verfügt und der Betriebssystemhersteller den Schwerpunkt auf die Verteilung von Nur-Binär-Installationsprogrammen gelegt hat).
Um eine Software auf einem anderen System als dem vom Autor verwendeten auszuführen, sind möglicherweise sogar einige kleine Änderungen erforderlich, die mit der Quelle einfach sind . Ein kleines einmaliges Programm, das jemand geschrieben hat, um seinen eigenen Juckreiz zu kratzen, wurde wahrscheinlich noch nie auf den meisten obskuren Systemen getestet. Mit der Quelle können solche Änderungen vorgenommen werden. Der ursprüngliche Autor hat möglicherweise etwas übersehen oder absichtlich weniger portablen Code geschrieben, weil dies viel Zeit gespart hat. Selbst große Pakete wie Info-ZIP hatten nicht sofort Tester auf jeder Plattform und mussten ihre Portabilitäts-Patches einsenden, sobald Probleme entdeckt wurden.
(Es gibt andere Arten von Portabilitätsproblemen auf Quellenebene, die nur aufgrund von Unterschieden in der Build-Umgebung auftreten und für das Problem hier nicht wirklich relevant sind. Mit binärer Portabilität im Java-Stil, Auto-Tools ( autoconf/ auto-make) und ähnlichen Dingen wie cmakewürde Es wird nicht benötigt. Und wir hätten keine Dinge wie einige Systeme, die die Einbeziehung von <netinet/in.h>anstelle von<arpa/inet.h> für erfordernntohl(3) . (Und vielleicht hätten wir überhaupt ntohl()keine andere Byte-Reihenfolge!)
Ich entwickle mich regelmäßig in .NET-Sprachen, bin also kein Computer-Analphabet.
Einmal kompilieren, überall ausführen ist eines der Hauptziele von .NET und auch Java. Man kann also mit Recht sagen, dass ganze Sprachen erfunden wurden, um dieses Problem zu lösen , und Ihre Entwicklererfahrung ist mit einem von ihnen. Mit .NET wird Ihre Binärdatei in einer tragbaren Laufzeitumgebung (CLR) ausgeführt . Java nennt seine Laufzeitumgebung die Java Virtual Machine . Sie müssen nur eine Binärdatei verteilen, die auf jedem System funktioniert (zumindest auf jedem System, auf dem bereits jemand eine JVM oder CLR implementiert hat). Möglicherweise können weiterhin Portabilitätsprobleme auftreten, z. B. im /Vergleich zu \Pfadtrennzeichen oder zum Drucken oder Details zum GUI-Layout.
Viele Softwareprogramme sind in Sprachen geschrieben, die vollständig in nativen Code kompiliert sind . Es gibt keinen .netoder Java-Bytecode, nur nativen Maschinencode für die CPU, auf der er ausgeführt wird, gespeichert in einem nicht portierbaren ausführbaren Dateiformat. C und C ++ sind die wichtigsten Beispiele dafür, insbesondere in der Unix-Welt. Dies bedeutet natürlich, dass eine Binärdatei für eine bestimmte CPU-Architektur kompiliert werden muss.
Bibliotheksversionen sind ein weiteres Problem . Bibliotheken können und werden häufig die API auf Quellenebene stabil halten, während der ABI auf Binärebene geändert wird. (Siehe Unterschied zwischen API und ABI .) Wenn Sie beispielsweise einem undurchsichtigen Element ein weiteres Mitglied hinzufügen, structändert sich seine Größe weiterhin und es muss für jeden Code, der Speicherplatz für eine solche Struktur reserviert, unabhängig davon, ob sie dynamisch ist (malloc), eine Neukompilierung mit Headern für die neue Bibliotheksversion durchgeführt werden ), statisch (global) oder automatisch (lokal auf dem Stapel).
Betriebssysteme sind ebenfalls wichtig . Eine andere Unix - Variante für die gleiche CPU - Architektur könnten verschiedene binäre Dateiformate haben, eine andere ABI für die Herstellung von Systemaufrufen und unterschiedliche numerische Werte für Konstanten wie fopen(3)‚s O_RDONLY, O_APPEND,O_TRUNC .
Beachten Sie, dass selbst eine dynamisch verknüpfte Binärdatei noch einen betriebssystemspezifischen Startcode enthält, der zuvor ausgeführt wurde main(). Unter Windows ist dies crt0. Unix und Linux haben dasselbe, wobei ein C-Runtime-Startcode statisch mit jeder Binärdatei verknüpft ist. Ich denke, theoretisch könnten Sie ein System entwerfen, in dem dieser Code auch dynamisch verknüpft war und Teil von libc oder des dynamischen Linkers selbst ist, aber so funktionieren die Dinge in der Praxis auf keinem mir bekannten Betriebssystem. Dies würde nur das ABI-Problem des Systemaufrufs lösen, nicht das Problem der numerischen Werte für Konstanten für Standardbibliotheksfunktionen. (Normalerweise werden Systemaufrufe über libc-Wrapper-Funktionen ausgeführt: Eine normale x86-64-Linux-Binärdatei für die verwendete Quelle enthält mmap()nicht die syscallAnweisung, sondern nur acall Anweisung an die gleichnamige libc-Wrapper-Funktion.
Dies ist einer der Gründe, warum Sie i386-FreeBSD-Binärdateien nicht einfach unter i386-Linux ausführen können. (Für eine Weile hatte der Linux-Kernel eine Systemaufruf-Kompatibilitätsschicht. Ich denke, mindestens eines der BSDs kann Linux-Binärdateien mit einer ähnlichen Kompatibilitätsschicht ausführen, aber Sie benötigen natürlich Linux-Bibliotheken.)
Wenn Sie Binärdateien verteilen möchten, müssen Sie für jede Kombination aus CPU / Betriebssystem-Version + Version / installierte Bibliotheksversion eine separate erstellen .
In den 80er / 90er Jahren gab es viele verschiedene CPU-Typen, die für Unix-Systeme (MIPS, SPARC, POWER, PA-RISC, m68k usw.) allgemein verwendet wurden, und viele verschiedene Unix-Varianten (IRIX, SunOS, Solaris, AIX, HP-UX, BSD usw.).
Und das sind nur Unix- Systeme. Viele Quellpakete würden auch auf anderen Systemen wie VAX / VMS, MacOS (m68k und PPC), Amiga, PC / MS-DOS, Atari ST usw. kompiliert und funktionieren .
Es gibt immer noch viele CPU-Architekturen und Betriebssysteme, obwohl jetzt eine große Mehrheit der Desktops auf x86 mit einem von drei Hauptbetriebssystemen ausgeführt wird.
Es gibt also bereits mehr CPU / OS-Kombinationen, als Sie sich vorstellen können, noch bevor Sie über Abhängigkeiten von Bibliotheken von Drittanbietern nachdenken, die auf verschiedenen Systemen unterschiedliche Versionen haben können. (Alles, was nicht vom Hersteller des Betriebssystems gepackt wurde, muss von Hand installiert werden.)
Alle Pfade, die in die Binärdatei kompiliert werden, sind ebenfalls systemspezifisch. (Dies spart RAM und Zeit im Vergleich zum Lesen aus einer Konfigurationsdatei beim Start). Unix-Systeme der alten Schule hatten normalerweise viele handgefertigte Dinge, so dass Sie keine gültigen Annahmen darüber treffen können, was wo ist.
Das Verteilen von Binärdateien war für Unix der alten Schule völlig unmöglich, mit Ausnahme von kommerziellen Großprojekten, die es sich leisten können, alle wichtigen Kombinationen zu erstellen und zu testen .
Sogar Binärdateien für gerecht i386-linux-gnuund amd64-linux-gnuschwierig zu machen. Es wurde viel Zeit und Mühe in Dinge wie die Linux Standard Base investiert, um tragbare Binärdateien zu ermöglichen . Selbst das statische Verknüpfen von Binärdateien löst nicht alles. (z. B. wie sollte ein Textverarbeitungsprogramm auf einem RedHat-System im Vergleich zu einem Debian-System gedruckt werden? Wie sollte die Installation einen Benutzer oder eine Gruppe für einen Dämon hinzufügen und dafür sorgen, dass das Startskript nach jedem Neustart ausgeführt wird?) Diese sind nicht großartig Beispiele, weil das Neukompilieren aus dem Quellcode sie nicht löst.
Abgesehen davon war die Erinnerung früher kostbarer als heute. Wenn beim Kompilieren optionale Funktionen weggelassen werden, können kleinere Binärdateien (weniger Codegröße) erstellt werden, die auch weniger Speicher für ihre Datenstrukturen benötigen. Wenn für ein Feature in jeder Instanz eines bestimmten Elements ein zusätzliches Mitglied erforderlich ist classoder structum etwas zu verfolgen, wird durch Deaktivieren dieses Features das Objekt beispielsweise um 4 Byte verkleinert. Dies ist hilfreich, wenn es sich um ein Objekt handelt, dem das Programm 100.000 zuweist.
Optionale Funktionen zur Kompilierungszeit werden heutzutage am häufigsten verwendet, um zusätzliche Bibliotheken optional zu machen. zB können Sie kompilieren ffmpegmit oder ohne libx264, libx265, libvorbis, und viele andere Bibliotheken für spezifische Video / Audio - Encoder, Untertitel Handling, etc. etc. Häufiger kann eine Menge Dinge , mit oder ohne kompiliert werden libreadline: wenn es verfügbar ist , wenn Sie laufen ./configure, die Die resultierende Binärdatei hängt von der Bibliothek ab und bietet eine ausgefallene Zeilenbearbeitung beim Lesen von einem Terminal. Wenn dies nicht der Fall ist, verwendet das Programm eine Fallback-Unterstützung, um nur Zeilen aus dem Standard mit fgets()oder so etwas zu lesen .)
Einige Projekte verwenden weiterhin optionale Funktionen, um aus Leistungsgründen nicht benötigten Code wegzulassen. Beispielsweise kann der Linux-Kernel selbst ohne SMP-Unterstützung erstellt werden (z. B. für ein eingebettetes System oder einen alten Desktop). In diesem Fall ist ein Großteil der Sperrung einfacher. Oder mit vielen anderen optionalen Funktionen, die sich auf einen Teil des Kerncodes auswirken und nicht nur Treiber oder andere Hardwarefunktionen weglassen. (Obwohl arch- und hardwarespezifische Konfigurationsoptionen einen Großteil des gesamten Quellcodes ausmachen . Siehe Warum enthält der Linux-Kernel mehr als 15 Millionen Codezeilen? )