Как установить программное обеспечение из исходного кода ... и затем удалить его

Краткое содержание: В этом подробном руководстве объясняется, как установить программу из исходного кода в Linux и как удалить программное обеспечение, установленное из исходного кода.

Одной из самых сильных сторон вашего дистрибутива Linux является его менеджер пакетов и связанный с ним репозиторий программного обеспечения. С их помощью у вас есть все необходимые инструменты и ресурсы для полной загрузки и установки нового программного обеспечения на ваш компьютер.

Но, несмотря на все усилия, производители дистрибутивов не могут могут предусмотреть все варианты использования системы. Таким образом, все еще есть ситуации, когда вам придется самостоятельно собирать и устанавливать новое программное обеспечение. Что касается меня, то наиболее распространенной причиной, к сожалению, иногда мне необходимо скомпилировать некоторое программное обеспечение, когда мне нужно запустить конкретную версию этого ПО. Или потому, что я хочу изменить исходный код или воспользоваться некоторыми иными параметрами при компиляции. ( Да, вот такие мы извращенцы линуксоиды ;-) )

Если вы относитесь к последней категории, есть вероятность, что вы уже знаете, что делать.
Но для подавляющего большинства пользователей Linux компиляция и установка программного обеспечения из источников в первый раз может выглядеть как церемония инициации: несколько пугающая; но обещающая войти в новый мир возможностей и стать частью привилегированного сообщества, если вы преодолеете это.

И так, начнем.

И это именно то, что мы будем делать здесь. Для целей этой статьи, скажем, мне нужно установить NodeJS 8.1.1 в мою систему. Эта версия точно недоступная в репозитории Debian:

sh$ apt-cache madison nodejs | grep amd64 

    nodejs | 6.11.1~dfsg-1 | http://deb.debian.org/debian experimental/main amd64 Packages 
    nodejs | 4.8.2~dfsg-1 | http://ftp.fr.debian.org/debian stretch/main amd64 Packages 
    nodejs | 4.8.2~dfsg-1~bpo8+1 | http://ftp.fr.debian.org/debian jessie-backports/main amd64 Packages 
    nodejs | 0.10.29~dfsg-2 | http://ftp.fr.debian.org/debian jessie/main amd64 Packages 
    nodejs | 0.10.29~dfsg-1~bpo70+1 | http://ftp.fr.debian.org/debian wheezy-backports/main amd64 Packages 

Как и многие проекты с открытым исходным кодом, в том числе исходники NodeJS можно найти в GitHub: https://github.com/nodejs/node

Итак, пойдем прямо туда.

Если вы не знакомы с GitHub, git или любой другой системой управления версиями, то стоит отметить, что здесь располагаются репозитории, содержащие текущий источник программного обеспечения, а также историю всех изменений, сделанных на протяжении многих лет для этого программного обеспечения. До самой первой строки, написанной для этого проекта. Для разработчиков сохранение этой истории имеет много преимуществ. Для нас же основным является то, что мы сможем получить исходники проекта на любой момент времени. Проще говоря, я смогу получить исходники версии NodeJS 8.1.1, в момент ее релиза. Даже если с тех пор было сделано много изменений.

На GitHub вы можете использовать кнопку “branch” для навигации между различными версиями программного обеспечения. “Branch” и “tags” связанные понятия в Git. В основном разработчики создают “branch” и “tags”, чтобы отслеживать важные события в истории проекта, например, когда они начинают работать над новой функцией или когда публикуют выпуск. Я не буду вдаваться в подробности здесь, все, что вам нужно знать, я ищу версию с тегами «v8.1.1»

После выбора в теге «v8.1.1» страница обновляется, наиболее очевидным изменением является тег, который теперь отображается как часть URL-адреса. Кроме того, вы возможно заметили, что дата изменения файла также отличается. Исходное дерево, которое вы сейчас видите, это то, которое существовало на время создания тега v8.1.1. В некотором смысле инструмент управления версиями, такой как git, это как бы машина для путешествий во времени, позволяющую вам вернуться в историю проекта.

На этом этапе мы можем загрузить исходники NodeJS 8.1.1. Вы не можете пропустить большую синюю кнопку на странице, предлагающую загрузить ZIP-архив проекта. Что касается меня, я буду загружать и извлекать ZIP в командной строке. Но если вы предпочитаете использовать инструменты GUI, не стесняйтесь, делайте как вам удобно:

$ wget https://github.com/nodejs/node/archive/v8.1.1.zip 
$ unzip v8.1.1.zip 
$ cd node-8.1.1/

Скачивание ZIP-архива отлично работает. Но если вы хотите сделать это «как профессионал», я бы предложил напрямую использовать инструмент git для загрузки источников. Это совсем не сложно - и это будет хороший первый контакт с инструментом, которым вам часто придется работать:

1. Сначала убедитесь, что git установлен в вашей системе

sh$ sudo apt-get install git

2. Сделайте свой маленький клон репозитория NodeJS v8.1.1

sh$ git clone --depth 1 --branch v8.1.1 https://github.com/nodejs/node 
sh$ cd node/ 

В любом случае, всякий раз, когда вы загружаете источник с помощью git или ZIP-архива, у вас должны быть в текущем каталоге точно такие файлы исходников:

sh$ ls

android-configure  BUILDING.md            common.gypi      doc            Makefile   src 
AUTHORS            CHANGELOG.md           configure        GOVERNANCE.md  node.gyp   test 
benchmark          CODE_OF_CONDUCT.md     CONTRIBUTING.md  lib            node.gypi  tools 
BSDmakefile        COLLABORATOR_GUIDE.md  deps             LICENSE        README.md  vcbuild.bat 

Обычно мы говорим о «компиляции исходников», но компиляция является лишь одним из этапов, необходимых для создания рабочего программного обеспечения из его исходника. Система сборки представляет собой набор инструментов и методов, используемых для автоматизации и формулирования этих различных задач, чтобы полностью собрать программное обеспечение, просто набрав несколько команд.

Если концепция проста, то реальность несколько сложнее. Потому что разные проекты или языки программирования могут иметь разные требования. Или из-за вкусов программиста. Или поддерживаемых платформ. Или по исторической причине. Или … или .. существует бесконечный список причин выбора или создания различных систем сборки. Все, что можно сказать, это то, что есть много различных используемых решений.

NodeJS использует систему сборки в GNU-стиле. Это популярный набор сообщества открытого исходного кода. И еще раз, это хороший старт вашего путешествие в мир СПО.

Написание и настройка системы сборки - довольно сложная задача. Но для «конечного пользователя» системы сборки в стиле GNU резюмируют себя использованием всего двух инструментов: configure и make.

Файл configure представляет собой скрипт конкретного проекта, который будет проверять конфигурацию системы назначения и доступные функции для того, чтобы гарантировать сборки проекта, с учетом специфики текущей платформы.

Важной частью задания типичного configure является создание Makefile. Это файл, содержит инструкции, необходимые для эффективной сборки проекта.

Инструмент **make**, с другой стороны, представляет собой инструмент POSIX, доступный в любой Unix-подобной системе. Он считывает Makefile конкретного проекта и выполняет необходимые операции по сборке и установке программы.

Но, как всегда в мире Linux, у вас могут возникнуть некоторые трудности при настройке сборок для ваших конкретных потребностей.

$ ./configure --help

Команда configure -help покажет вам все доступные параметры конфигурации. Еще раз, в этом возникает необходимость, как правило, для очень специфичных проектов. И, честно говоря, иногда требуется вникнуть в проект, прежде чем полностью понять смысл каждой опции конфигурации.

Но есть, по крайней мере, один стандартный параметр GNU Autotools, который вы должны знать: параметр –prefix. Это связано с иерархией файловой системы и местом установки вашего программного обеспечения.

Шаг третий: FHS

Иерархия файловой системы Linux в типичном дистрибутиве в основном соответствует стандарту иерархии файловой системы (FHS - Filesystem Hierarchy Standard)

Этот стандарт объясняет назначение различных каталогов вашей системы: /usr, /tmp, /var и т.д.

При использовании GNU Autotools и большинства других систем сборки - место установки по умолчанию для вашего нового программного обеспечения будет /usr/local. Что является хорошим выбором, поскольку в соответствии с FSH «Иерархия /usr/local предназначена для использования системным администратором при локальном установки программного обеспечения. Он должен быть защищен от перезаписи, при обновлении системное программного обеспечения. Он может использоваться для программ и данных, которые могут быть включены в группу хостов, но не найдены в /usr.»

Иерархия /usr/local повторяет корневой каталог, поэтому вы найдете там /usr/local/bin для исполняемых программ, /usr/local/lib для библиотек, /usr/local/share для независимых от архитектуры файлов и т.д.

Единственная проблема при использовании каталога /usr/local для установки пользовательского программного обеспечения - это файлы вашего программного обеспечения установленного из исходников. В частности, после установки нескольких программ, будет сложно отслеживать, к какой программе принадлежат файлы в /usr/local/bin и /usr/local/lib. Однако это не вызовет проблемы для системы. В конце концов, в /usr/bin почти такой же беспорядок. Но это станет проблемой в тот момент, когда вы захотите удалить установленное из исходников программное обеспечение.

Чтобы решить эту проблему, я обычно предпочитаю устанавливать программное обеспечение в каталоге /opt. Еще раз, процитирую FHS:

/opt зарезервирован для установки дополнительных программных пакетов приложений. Пакет, который должен быть установлен в /opt, должен размещать свои статические файлы в отдельном /opt/<package> или /opt/<provider>, где <package> - это имя, которое описывает пакет программного обеспечения и <provider> - зарегистрированное имя LANANA провайдера.

Поэтому мы создадим подкаталог в /opt специально для нашей пользовательской установки Node JS. И если когда-нибудь я захочу удалить это программное обеспечение, мне просто необходимо будет удалить этот каталог:

sh$ sudo mkdir /opt/node-v8.1.1 
sh$ sudo ln -sT node-v8.1.1 /opt/node 
sh$ ./configure --prefix=/opt/node-v8.1.1 
sh$ make -j9 && echo ok

-j9 означает запуск до 9 параллельных задач для создания программного обеспечения. Как правило, используйте -j (N + 1), где N - количество ядер вашей системы. Это максимизирует использование ЦП (одна задача на процессорный поток / ядро + предоставление одной дополнительной задачи, когда процесс блокируется операцией ввода-вывода).

Все, кроме «ok», после завершения команды make, будет означать, что во время процесса сборки произошла ошибка. Когда мы запускаем параллельную сборку с опции -j, нелегко получить сообщение об ошибке, учитывая большой объем вывода информации, выданной инструментами сборки.

В случае возникновения проблем, просто перезапустите make, но без опции -j на этот раз. И ошибка появится ближе к концу вывода:

sh$ make

Наконец, как только компиляция завершится, вы можете установить свое программное обеспечение в нужное место, выполнив команду:

sh$ sudo make install

И протестировать его:

sh$ /opt/node/bin/node --version 
v8.1.1

То, что я объяснял выше, - это в основном то, что вы можете увидеть на странице «Инструкции по сборке» («build instruction») хорошо документированного проекта. Но цель этой статьи состоит в том, чтобы позволить вам скомпилировать ваше первое программное обеспечение из источников и, возможно, стоит потратить время на исследование некоторых распространенных проблем. Итак, я сделаю всю процедуру снова, но на этот раз в свежих и минимальных системах Debian 9.0 и CentOS 7.0. Таким образом, вы можете увидеть ошибки, с которыми я столкнулся, и как я их решил.

$ git clone --depth 1 --branch v8.1.1 https://github.com/nodejs/node
-bash: git: command not found

Эта проблема довольно легко диагностируется и решается. Просто установите пакет git:

$ sudo apt-get install git
$ git clone --depth 1 --branch v8.1.1 https://github.com/nodejs/node && echo ok
[много-много букв...] 
ok
$ sudo mkdir /opt/node-v8.1.1 
$ cd node 
$ sudo ln -sT node-v8.1.1 /opt/node

Здесь проблем не наблюдаем

$ ./configure --prefix=/opt/node-v8.1.1/ 
WARNING: failed to autodetect C++ compiler version (CXX=g++) 
WARNING: failed to autodetect C compiler version (CC=gcc)  
Node.js configure error: No acceptable C compiler found! 
        Please make sure you have a C compiler installed on your system and/or 
        consider adjusting the CC environment variable if you installed 
        it in a non-standard prefix.

Очевидно, что для компиляции проекта вам нужен компилятор. NodeJS, написан с использованием языка C++, поэтому нам нужен компилятор C++. Здесь я установлю компилятор GNU C++, которым является g++:

$ sudo apt-get install g++ 
$ ./configure --prefix=/opt/node-v8.1.1/ && echo ok 
[много-много букв...] 
ok
$ make -j9 && echo ok 
-bash: make: command not found

Еще один недостающий инструмент. Те же симптомы. То же решение:

$ sudo apt-get install make 
$ make -j9 && echo ok 
[много-много букв...] 
ok
$ sudo make install 
[много-много букв...] 
$ /opt/node/bin/node --version 
v8.1.1

Ура! Золотой ключик наш.

Обратите внимание: я установил различные инструменты один за другим, чтобы показать, как диагностировать проблемы компиляции и показать вам типичное решение этих проблем. Но если вы захотите узнать больше по этой теме или прочитаете другие учебники, вы обнаружите, что большинство дистрибутивов имеют «meta-packages» (мета-пакеты), действующие в качестве зонтика при установки некоторых или всех типовых инструментов, используемых для компиляции программного обеспечения. В системах на базе Debian вы, вероятно, столкнетесь с пакетом build-essentials для этой цели. А в дистрибутивах на основе Red Hat, это будет Development Tools.

$ git clone --depth 1 --branch v8.1.1 https://github.com/nodejs/node 
-bash: git: command not found

Команда не найдена? Просто установите его с помощью менеджера пакетов yum:

$ sudo yum install git
$ git clone --depth 1 --branch v8.1.1 https://github.com/nodejs/node && echo ok 
[много-много букв...] 
ok
$ sudo mkdir /opt/node-v8.1.1 
$ sudo ln -sT node-v8.1.1 /opt/node
$ cd node 
$ ./configure --prefix=/opt/node-v8.1.1/ 
WARNING: failed to autodetect C++ compiler version (CXX=g++) 
WARNING: failed to autodetect C compiler version (CC=gcc) 
Node.js configure error: No acceptable C compiler found! 

        Please make sure you have a C compiler installed on your system and/or 
        consider adjusting the CC environment variable if you installed 
        it in a non-standard prefix.

Вы догадались: NodeJS написан на языке C ++, но моей системе не хватает соответствующего компилятора. Yum вам в помощь. Поскольку я не являюсь постоянным пользователем CentOS, мне действительно нужно было искать в Интернете точное имя пакета, содержащего компилятор g++. Поиск привел меня на эту страницу: https://superuser.com/questions/590808/yum-install-gcc-g-doesnt-work-anymore-in-centos-6-4

$ sudo yum install gcc-c++ 
$ ./configure --prefix=/opt/node-v8.1.1/ && echo ok 
[много-много букв...] 
ok
$ make -j9 && echo ok 
[много-много букв...] 
ok
$ sudo make install && echo ok 
[много-много букв...] 
ok
$ /opt/node/bin/node --version 
v8.1.1

Ура! Пройден очередной уровень. :)

Вы можете установить программное обеспечение из исходников, если вам нужна конкретная версия, недоступная в вашем репозитории. Или потому, что вы хотите изменить данную программу. Либо исправить ошибку, либо добавить функцию. В конце концов, open-source и придуман для этого. Поэтому я воспользуюсь этой возможностью, чтобы дать вам почувствовать силу, которая у вас есть. Теперь вы можете скомпилировать свое собственный вариант необходимого вам программного обеспечения.

Сейчас мы сделаем незначительные изменения в исходниках NodeJS. И увидим, будут ли внесены изменения в скомпилированную версию программного обеспечения:

Откройте файл node/src/node.cc в вашем любимом текстовом редакторе (vim, nano, gedit, …). И попытайтесь найти этот фрагмент кода:

if (debug_options.ParseOption(argv[0], arg)) { 
     // Done, consumed by DebugOptions::ParseOption(). 
    } else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {  
      printf("%s\n", NODE_VERSION);  
      exit(0); 
    } else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) { 
      PrintHelp(); 
      exit(0); 
    }

Это примерно 3830 строка файла. Затем измените строку, содержащую printf, впишите следующее:

printf("%s (compiled by myself)\n", NODE_VERSION);

Затем вернитесь в терминал. Прежде чем идти дальше - и дать вам более полное представление о силе, стоящей за git, вы можете проверить, изменили ли вы правильно файл:

$ diff --git a/src/node.cc b/src/node.cc 
index bbce1022..a5618b57 100644 
--- a/src/node.cc 
+++ b/src/node.cc 
@@ -3828,7 +3828,7 @@ static void ParseArgs(int* argc, 
     if (debug_options.ParseOption(argv[0], arg)) { 
       // Done, consumed by DebugOptions::ParseOption(). 
     } else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) { 
-      printf("%s\n", NODE_VERSION); 
+      printf("%s (compiled by myself)\n", NODE_VERSION); 
       exit(0); 
     } else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) { 
       PrintHelp();

Перед строкой, которую вы изменили, вы должны увидеть знак «-» (минус) и как это было до ваших изменений. И знак «+» (плюс) перед строкой после ваших изменений.

Настало время перекомпилировать и переустановить ваше программное обеспечение:

$ make -j9 && sudo make install && echo ok 
[много-много букв...] 
ok

В данный момент, единственная причина, по которой вы можете потерпеть неудачу, заключается в том, что вы могли сделали опечатку при изменении кода. Если это так, повторно откройте файл node/src/node.cc в текстовом редакторе и исправьте ошибку.

Как только вам удастся скомпилировать и установить новую модифицированную версию NodeJS, вы сможете проверить, действительно ли ваши модификации были включены в программное обеспечение:

$ /opt/node/bin/node --version 
v8.1.1 (compiled by myself)

Поздравляем! Вы сделали свое первое изменение в программе с открытым исходным кодом!

Возможно вы заметили, что до сих пор, я всегда запускал свое недавно скомпилированное программное обеспечение NodeJS, указав абсолютный путь к бинарному файлу.

/opt/node/bin/node

Оно конечно работает, но раздражает, если не сказать больше. На самом деле существует два актуальных способа устранения этой неопределенности. Но чтобы понять их, вы должны сначала знать, что ваша оболочка находит исполняемые файлы автоматически, но только в каталогах, заданных переменной среды PATH.

$ echo $PATH 
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

В Debian, если вы не укажете явно какой-либо каталог как часть команды, оболочка сначала будет искать эти исполняемые программы в /usr/local/bin, а затем, если не будет найдена в /usr/bin, затем в /bin, затем в /usr/local/games, затем в /usr/games, ну а если и здесь не найден, то… оболочка выдаст ошибку «command not found» (команда не найдена).

Учитывая это, у нас есть два способа сделать команду доступной для shell: добавив ее в один из уже настроенных каталогов PATH или добавив каталог, содержащий наш исполняемый файл, в PATH.

Простое копирование бинарного исполняемого файла node из /opt/node/bin в /usr/local/bin было бы плохой идеей, так как при этом исполняемая программа больше не сможет находить другие необходимые компоненты, принадлежащие /opt/node/ (общепринятой практикой для программного обеспечения? является поиск его файлов ресурсов относительно его собственного местоположения).

Таким образом, традиционный способ сделать это - использовать символическую ссылку:

$ sudo ln -sT /opt/node/bin/node /usr/local/bin/node 
$ which -a node || echo not found 
/usr/local/bin/node 
$ node --version 
v8.1.1 (compiled by myself)

Это простое и эффективное решение, особенно если программный пакет состоит из нескольких известных исполняемых программ, поскольку вам нужно создать символическую ссылку для каждой команды, вызываемой пользователем. Например, если вы знакомы с NodeJS, вы знаете приложение-компаньон npm, я должен создать символическую ссылку на /usr/local/bin. Но я дал это вам как упражнение.

Во-первых, если вы попробовали предыдущее решение, удалите символическую ссылку node, созданную ранее, чтобы начать с чистого листа:

$ sudo rm /usr/local/bin/node 
$ which -a node || echo not found 
not found

И теперь, волшебная команда, для изменения вашего PATH:

$ export PATH="/opt/node/bin:${PATH}" 
$ echo $PATH 
/opt/node/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Проще говоря, я изменил содержимое переменной среды PATH предыдущим содержимым, но с добавлением /opt/node/bin. Итак, как вы можете себе представить, оболочка сначала будет искать в каталоге /opt/node/bin исполняемые программы, а далее по стандартным путям. Мы можем проверить это с помощью команды which:

$ which -a node || echo not found 
/opt/node/bin/node 
$ node --version 
v8.1.1 (compiled by myself)

В то время как решение «ссылка»,как только вы создали символическую ссылку в /usr/local/bin, является правилом для всей системы, то изменение PATH действует только в текущей оболочке. Я позволю вам сделать некоторые исследования самостоятельно, чтобы узнать, как сделать изменения в PATH постоянными. Как подсказка, это связано с вашим “profile” (профилем). Если вы найдете решение, не стесняйтесь делиться этим с другими пользователями Linux.

Поскольку наше пользовательское скомпилированное программное обеспечение NodeJS полностью находится в каталоге /opt/node-v8.1.1, то удаление этого программного обеспечения не является трудным, для этого используем команду rm для удаления этого каталога:

$ sudo rm -rf /opt/node-v8.1.1

ОСТОРОЖНО: sudo и rm -rf - опасный коктейль! Всегда проверяйте свою команду дважды, прежде чем нажимать клавишу «Ввод». У вас не будет никакого подтверждающего сообщения и восстановление не будет возможно, если вы удалите неправильный каталог …

Затем, если вы изменили свой PATH, вам придется отменить эти изменения. Что совсем не сложно.

И если вы создали ссылки в /usr/local/bin, вам придется удалить их все:

$ sudo find /usr/local/bin -type l -ilname "/opt/node/*" -print -delete 
/usr/local/bin/node

В качестве заключительного комментария, если вы читали о компиляции своего собственного программного обеспечения, то вы, возможно, слышали об аде зависимостей. Это прозвище раздражающей ситуации, когда перед тем, как успешно скомпилировать программное обеспечение, вы должны сначала скомпилировать связанную библиотеку, которая, в свою очередь, требует наличия другой библиотеки, которая в свою очередь может быть несовместима с каким-либо другим программным обеспечением, которое вы уже установлены.

Часть работы сторонних разработчиков пакета заключается в том, чтобы фактически разрешить этот адский ад и обеспечить, чтобы различное программное обеспечение вашей системы использовало совместимые библиотеки и было установлено в правильном порядке.

В этой статье я специально решил установить NodeJS, поскольку у нее практически нет зависимостей. Я сказал «практически», потому что на самом деле он имеет зависимости. Но исходный код этих зависимостей присутствует в исходном репозитории проекта (в подкаталоге node/deps), поэтому вам не нужно загружать и устанавливать их вручную перед началом работы.

Но если вам интересно узнать больше об этой проблеме и узнать, как с ней бороться, то начинайте читать специализированную литературу! 8-)