Какие социальные или технические факторы привели к росту менталитета CIY?
Основная причина - это, очевидно, техническая причина: двоичная переносимость сложнее, чем переносимость исходного кода . Вне дистрибутивных пакетов большинство Свободного программного обеспечения все еще доступно только в исходной форме, потому что это гораздо более удобно для автора (ов) / сопровождающего (ей).
Пока дистрибутивы Linux не начали упаковывать большинство вещей, которые захотят использовать обычные люди, единственным вариантом было получить исходный код и скомпилировать его для своей собственной системы. Коммерческие поставщики Unix, как правило, не включают в себя вещи, которые нужны почти всем (например, хорошую оболочку, такую как GNU bash
или аналогичную), просто их собственную реализацию sh
и / или csh
, поэтому вам нужно было создавать вещи самостоятельно, если вы (как системный администратор) хотели обеспечить приятную среду Unix для ваших пользователей для интерактивного использования.
Ситуация, когда большинство людей являются единственным администратором и единственным пользователем компьютера, сидящего на рабочем столе, сильно отличается от традиционной модели Unix. Системный администратор поддерживал программное обеспечение в центральной системе и на рабочем столе каждого. (Часто, когда рабочие станции просто монтируются по NFS /opt
и /usr/local/
с центрального сервера, и устанавливаются там).
До таких вещей, как .NET и Java, настоящая двоичная переносимость между различными архитектурами ЦП была невозможна. По этой причине культура Unix развивалась с переносимостью исходного кода по умолчанию, при этом не требовалось больших усилий, чтобы даже попытаться включить переносимость двоичных файлов до недавних усилий Linux, таких как LSB. Например, POSIX ( основной стандарт Unix) только пытается стандартизировать исходную портативность, даже в последних версии.
Связанный культурный фактор: ранняя коммерческая версия AT & T Unix шла с исходным кодом (на лентах). Вам не нужно было собирать систему из исходного кода, это было просто на случай, если вы захотите увидеть, как что-то действительно работает, когда документов недостаточно.
Википедия говорит :
«Политика Unix в отношении обширной онлайновой документации и (в течение многих лет) легкого доступа ко всему исходному коду системы повысила ожидания программистов и способствовала началу движения за свободное программное обеспечение в 1983 году».
Я не уверен, что послужило причиной этого решения, так как предоставление клиентам доступа к исходному коду коммерческого программного обеспечения в наши дни неслыханно. Очевидно, в этом направлении есть некоторые ранние культурные предрассудки, но, возможно, они возникли из корней Unix как портативной ОС, написанной в основном на C (не на ассемблере), которая может быть скомпилирована для другого оборудования. Я думаю, что многие более ранние ОС имели больше кода, написанного в asm для конкретного процессора, поэтому переносимость на уровне исходного кода была одной из сильных сторон раннего Unix. (Возможно, я ошибаюсь; я не эксперт по ранним версиям Unix, но Unix и C связаны между собой.)
Распространение программного обеспечения в исходной форме - безусловно, самый простой способ позволить людям адаптировать его к любой системе, на которой он хочет работать. (Либо конечные пользователи, либо люди, которые упаковывают его для дистрибутива Linux). Если программное обеспечение уже было упаковано для / для распространения, конечные пользователи могут просто использовать это.
Но это слишком много, чтобы ожидать, что авторы большинства пакетов сами сделают бинарные файлы для каждой возможной системы. В некоторых крупных проектах предусмотрены двоичные файлы для нескольких распространенных случаев (особенно для x86 / windows, где ОС не поставляется со средой сборки, а поставщик ОС сделал основной упор на распространение установщиков только для двоичного кода).
Получение программного обеспечения для запуска в системе, отличной от той, которую использовал автор, может даже потребовать некоторых небольших изменений, которые легко сделать с источником . Небольшая одноразовая программа, которую кто-то написал, чтобы избавиться от собственного зуда, вероятно, никогда не тестировалась на большинстве непонятных систем. Наличие источника позволяет сделать такие изменения. Первоначальный автор мог что-то упустить или намеренно написал менее переносимый код, потому что это сэкономило много времени. Даже у крупных пакетов, таких как Info-ZIP , не было тестеров на каждой платформе сразу, и требовалось, чтобы люди отправляли свои исправления переносимости при обнаружении проблем.
(Существуют и другие виды проблем с переносимостью исходного уровня , которые только происходят из - за различий в сборки окр, и которые на самом деле не относятся к проблеме здесь. С Java-стиль двоичная портативности, автоинструмент ( autoconf
/ auto-make
) и тому подобные вещи , как cmake
Wouldn в этом нет необходимости. И у нас не было бы таких вещей, как некоторые системы, требующие включения <netinet/in.h>
вместо<arpa/inet.h>
forntohl(3)
. (И, может быть, у нас не было бы ntohl()
или чего-то другого в порядке следования байтов!)
Я регулярно работаю на языках .NET, поэтому я не компьютерный неграмотный.
Однократная компиляция, запуск в любом месте - одна из основных целей .NET, а также Java, поэтому справедливо сказать, что для решения этой проблемы были изобретены целые языки , и ваш опыт разработки связан с одной из них. С .NET ваш двоичный файл работает в переносимой среде выполнения (CLR) . Java называет среду выполнения виртуальной машиной Java . Вам нужно только распространить один двоичный файл, который будет работать в любой системе (по крайней мере, в любой системе, где кто-то уже внедрил JVM или CLR). Вы можете все еще есть проблемы с переносимостью , как, /
против \
разделителей пути, или , как печатать, или GUI макет детали, конечно.
Много программного обеспечения написано на языках, которые полностью скомпилированы в нативный код . Нет никакого .net
байт-кода или java, просто собственный машинный код для процессора, на котором он будет работать, хранящийся в непереносимом формате исполняемых файлов. C и C ++ являются основными примерами этого, особенно в мире Unix. Очевидно, это означает, что двоичный файл должен быть скомпилирован для конкретной архитектуры процессора.
Версии библиотеки - еще одна проблема . Библиотеки могут и часто поддерживают стабильность API уровня источника при изменении ABI двоичного уровня. (См. Раздел « Различие между API и ABI» .) Например, добавление другого элемента в opaque по- struct
прежнему меняет его размер и требует перекомпиляции с заголовками для новой версии библиотеки для любого кода, который выделяет пространство для такой структуры, будь то динамическая (malloc) ), статический (глобальный) или автоматический (локальный в стеке).
Операционные системы также важны . Другой вкус Unix для тех же архитектур процессора может иметь различные бинарные форматы файлы, различный ABI для создания системных вызовов, а также различных числовых значений констант , таких как fopen(3)
«с O_RDONLY
, O_APPEND
,O_TRUNC
.
Обратите внимание, что даже у динамически связанного двоичного файла все еще есть некоторый специфичный для ОС код запуска, который выполняется раньше main()
. На Windows это есть crt0
. Unix и Linux имеют одно и то же, где некоторый код запуска C-Runtime статически связан с каждым двоичным файлом. Я предполагаю, что теоретически вы могли бы спроектировать систему, в которой этот код был бы динамически связан, и часть libc или самого динамического компоновщика, но это не то, как все работает на практике на любой ОС, о которой я знаю. Это решило бы только проблему системного вызова ABI, а не проблему числовых значений констант для функций стандартной библиотеки. (Обычно системные вызовы выполняются через функции-оболочки libc: обычный бинарный Linux-файл x86-64 для исходного кода, mmap()
который не содержит syscall
инструкции, простоcall
инструкция к функции-оболочке libc с тем же именем.
Это одна из причин, по которой вы не можете просто запускать двоичные файлы i386-FreeBSD в i386-Linux. (Некоторое время ядро Linux имело уровень совместимости системных вызовов. Я думаю, что по крайней мере одна из BSD может запускать двоичные файлы Linux с аналогичным уровнем совместимости, но вам, конечно, нужны библиотеки Linux.)
Если вы хотите распространять двоичные файлы, вам нужно будет создать отдельный для каждой комбинации CPU / OS-flavor + version / instal-library-version .
Еще в 80–90-х годах было много разных типов ЦП, широко используемых для систем Unix (MIPS, SPARC, POWER, PA-RISC, m68k и т. Д.), А также множество различных разновидностей Unix (IRIX, SunOS, Solaris, AIX, HP-UX, BSD и т. Д.).
И это только системы Unix . Многие исходные пакеты также будут компилироваться и работать на других системах, таких как VAX / VMS, MacOS (m68k и PPC), Amiga, PC / MS-DOS, Atari ST и т. Д.
Все еще существует много процессорных архитектур и операционных систем, хотя в настоящее время большинство настольных компьютеров используют x86 с одной из трех основных операционных систем.
Таким образом, комбинаций CPU / OS уже больше, чем вы можете потрясти, даже прежде, чем вы начнете думать о зависимостях от сторонних библиотек, которые могут быть в разных версиях на разных системах. (Все, что не упаковано поставщиком ОС, должно быть установлено вручную.)
Любые пути, которые компилируются в двоичный файл, также зависят от системы. (Это экономит оперативную память и время по сравнению с чтением их из файла конфигурации при запуске). В Unix-системах старой школы обычно было много настраиваемых вручную вещей, поэтому вы никак не могли бы сделать какие-либо обоснованные предположения о том, что и где.
Распределение двоичных файлов было абсолютно невозможным для старой школы Unix, за исключением крупных коммерческих проектов, которые могут позволить построить и протестировать все основные комбинации .
Даже сделать двоичные файлы просто так i386-linux-gnu
и amd64-linux-gnu
сложно. Много времени и усилий было потрачено на такие вещи, как Linux Standard Base, чтобы сделать возможным переносимые двоичные файлы . Даже статически связанные двоичные файлы не решают все проблемы. (например, как программа печати текста должна печатать в системе RedHat по сравнению с системой Debian? Как при установке следует добавить пользователя или группу для демона и организовать запуск сценария запуска после каждой перезагрузки?) Это не очень хорошо примеры, потому что перекомпиляция из источника не решает их.
Помимо всего этого, в те времена память была более драгоценной, чем сейчас. Отсутствие дополнительных функций во время компиляции может создать меньшие двоичные файлы (меньший размер кода), которые также используют меньше памяти для своих структур данных. Если для функции требуется дополнительный элемент в каждом конкретном случае class
или struct
для отслеживания чего-либо, отключение этой функции приведет к уменьшению объекта на 4 байта (например), что хорошо, если это объект, для которого программа выделяет 100 КБ.
Дополнительные функции времени компиляции в наши дни чаще всего используются, чтобы сделать дополнительные библиотеки необязательными. Например , вы можете скомпилировать ffmpeg
с или без libx264
, libx265
, libvorbis
и многими другими библиотеками для конкретного видео / аудио кодеров, обработки субтитров и т.д. и т.п. Чаще всего , много вещей , которые могут быть собран с или без libreadline
: если он доступен при запуске ./configure
, то Полученный двоичный файл будет зависеть от библиотеки и обеспечит необычное редактирование строк при чтении из терминала. Если это не так, то программа будет использовать некоторую запасную поддержку, чтобы просто читать строки из stdin с помощью fgets()
чего-либо.)
В некоторых проектах все еще используются дополнительные функции для исключения ненужного кода по соображениям производительности. Например, само ядро Linux может быть собрано без поддержки SMP (например, для встроенной системы или старого рабочего стола), и в этом случае большая часть блокировки проще. Или со многими другими дополнительными функциями, которые влияют на некоторый основной код, а не просто пропуская драйверы или другие аппаратные функции. (Хотя специфичные для arch и аппаратные параметры конфигурации составляют большую часть общего исходного кода. См. Почему ядро Linux содержит более 15 миллионов строк кода? )