Установка программ tar bz2, из исходных кодов в Linux

Linux-системы неразрывно связаны с концепцией GNU – проекта, поддерживающего и развивающего философию свободно распространяемого программного обеспечения (ПО), в том числе и в виде исходного кода. А поскольку систем на базе ядра Linux существует великое множество и разработчики дистрибутивов всегда для своих систем используют исходный код ПО при сборке комплектов утилит, пакетов, да и самого ядра, то, очевидно, что использование исходных кодов ПО — это неотъемлемый аспект в эксплуатации Linux-систем. По крайней мере, любому пользователю, достаточно хорошо освоившему UNIX-подобные системы, рано или поздно приходится сталкиваться со сборкой ПО из исходных кодов.

Самым распространённым случаем, когда приходится собирать ПО из «исходников» является ситуация, когда в свет выходит новая версия какого-либо пакета с устранением критической уязвимости в системе безопасности или с добавлением важного функционала. Но поскольку системы Linux, как правило, снабжены хранилищами пакетов (репозиториями), из которых происходит загрузка, установка и обновление ПО, то часто бывает так, что разработчики дистрибутива, которые и поддерживают репозитории, ещё не успели сформировать новые пакеты ПО, для которых уже выпущено обновление. В этом случае можно прибегнуть к самостоятельной сборке требуемых пакетов из исходного кода.

Для чего нужно построение пакетов из исходного кода?

Как уже отмечалось ранее, это необходимо, в первую очередь для устранения брешей в безопасности. Часто новые версии ПО выпускаются в результате внедрения новых подходов и технологий при разработке и оптимизации программного кода, что существенно может сказаться на производительности ПО, и это также довольно частая причина обновления программных пакетов путём их сборки из исходных текстов.

Владельцы и администраторы хостинг-площадок предпочитают также устанавливать в качестве веб-серверов, PHP-интерпретаторов и серверов баз данных (БД) предварительно собранные на целевом оборудовании соответствующие программные пакеты. Это позволяет добиться максимальной совместимости ПО с оборудованием, на котором предполагается его работа и, как следствие — стабильности, что для веб-хостинга очень важно.

Для программистов навыки по построению исполняемых файлов из исходного кода являются ключевыми, несмотря даже на то, что с этой задачей прекрасно справляются все современные интегрированные среды разработки (IDE), однако, как показывает практика, часто приходится производить сборку ПО без применения IDE.

Общий порядок сборки пакетов — утилита make

Для облегчения сборки ПО из исходных кодов существует свободная утилита make. Она применяется во всех UNIX-подобных системах для подавляющего большинства утилит. При сборке пакета очень полезно изучать информацию, содержащуюся, как правило, в файлах README или INSTALL, входящих в пакет. В этих файлах разработчики ПО указывают инструкции и специфические мероприятия для успешной сборки пакетов. Здесь также можно найти и системные требования для работы ПО и описания необходимых зависимостей, без которых собрать пакет будет невозможно.

Общий порядок сборки выглядит так:

  1. Распаковка архива tar bz2, содержащего исходные коды (обычно именно так «исходники» и распространяются).
  2. Переход в директорию с распакованными исходными текстами.
  3. Конфигурирование предстоящей сборки (указание директорий установки, сторонних библиотек, архитектуры, дополнительных компонентов и т.д.). Для этого обычно используются служебные скрипты.
  4. Непосредственно, сама сборка — команда make.
  5. Установка (распространение) построенного ПО — команда make install.

Ниже будет приведена эта процедура на примере с FTP-клиентом FileZilla, итак распаковка архива с «исходниками»:

$ tar -jxvf FileZilla_3.38.1_src.tar.bz2 -C ~/Builds

В результате, в домашнем каталоге пользователя в поддиректории Builds появится директория filezilla-3.38.1. Нужно перейти в неё:

$ cd ~/Builds/filezilla-3.38.1

Просмотрев содержимое этой директории можно заметить файл INSTALL, в котором приведены инструкции для сборки/установки FileZilla:

$ ll

Посмотрим этот файл

cat INSTALL

Раздел «Compilation» из файла INSTALL:

Теперь, согласно этой инструкции, нужно создать директорию compile и перейти в неё:

$ mkdir compile
$ cd compile

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

$../configure

Подобные скрипты создаются разработчиками ПО для облегчения процесса сборки/установки. Символы ../ означают переход в каталог на уровень вверх — именно там

по отношению к недавно созданной директории compile находится служебный скрипт configure.

Вывод этого скрипта показывает , готов ли данный пакет к сборке:

checking for libfilezilla >= 0.15.0... no
configure: error: libfilezilla not found: Requested 'libfilezilla >= 0.15.0' but version of libfilezilla is 0.13.0
You may find new versions of libfilezilla at https://lib.filezilla-project.org/. You can download it from https://lib.filezilla-project.org/

В данном случае для сборки необходима библиотека libfilezilla более свежей версии, чем имеющаяся на данный момент в системе. По указанному адресу её можно скачать и собрать отдельно:

$ tar -jxvf libfilezilla-0.15.0.tar.bz2 -C ~/Builds
cd ~/Builds/libfilezilla-0.15.0/
$ ll

Здесь также присутствует файл INSTALL с указанием порядка сборки библиотеки  libfilezilla-0.15.0

$ mkdir compile
$ cd compile
$ ../configure

Изучив вывод скрипта configure, можно сделать вывод о том, стоит ли далее приступать к сборке пакета. Обычно о критических ошибках сообщается фразами «configure: error». Убедившись, что всё нормально, можно приступать к построению:

$ make

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

$ sudo make install

В выводе этой команды при успешном завершении обычно присутствует сообщения вида:

Libraries have been installed in:
   /usr/local/lib

Сборка и установка библиотеки завершена, можно приступать к построению пакета FileZilla:

$ make
$ sudo make install

По-умолчанию установка будет произведена в директорию /usr/bin. Для изменения директории установки следует использовать опцию —prefix=каталог:

$ ../configure --prefix=~/bin

Сборка FTP-клиента FileZilla из исходных кодов на этом завершена. Следует отметить, что для FileZilla требуются также сторонние библиотеки инструментов, обеспечивающие работу с криптографическими алгоритмами (nettle), а также для отрисовки графического пользовательского интерфейса (GUI) — wxWidgets. Специфические требования всегда указываются разработчиками ПО в файлах README или INSTALL, входящих в архив пакета или исходных кодов.

Помимо установленных в системе требуемых пакетов, удовлетворяющим зависимостям для сборки, также необходимо, зачастую, устанавливать версии этих пакетов для разработки.

Обычно такие пакеты имеют идентичные с оригинальными наименования, но оканчивающиеся на «dev», к примеру nettle-3.1-dev или wx-gtk-base-dev. В данном примере предполагается, что данные пакеты установлены и правильно настроены.

Ручная сборка

Ручная сборка из исходных кодов выполняется следующим образом:

$ g++ -o program program.cpp

Для кода на процедурном C:

$ gcc -o program program.c

Здесь «program» — это собранный исполняемый файл, который можно теперь запускать:

$ ./program

Теперь стоит рассмотреть чуть более сложный вариант. Например, исходный код приложения состоит из классов, содержащихся в отдельных файлах. Класс BaseClass, заголовочный файл BaseClass.h:

#ifndef BASECLASS_H
#define BASECLASS_H
class BaseClass
{
    public:
        BaseClass();
        BaseClass(char* input[]);
        void showValue();
        virtual ~BaseClass();
    protected:
        float value;
    private:
};
#endif // BASECLASS_H

Реализация, файл BaseClass.cpp:

#include "../include/BaseClass.h"
#include <iostream>
#include <cstdlib>
using namespace std;
BaseClass::BaseClass()
{
    //ctor
    //this->tmp = 0.0;
    //value = 0.0;
}
BaseClass::BaseClass(char* input[])
{
    this->value = strtof(input[1], NULL);
}
void BaseClass::showValue()
{
    cout << "Это value: " << fixed << value << endl;
}
BaseClass::~BaseClass()
{
    //dtor
}

Класс ChildClass, заголовочный файл ChildClass.h:

#ifndef CHILDCLASS_H

#define CHILDCLASS_H

#include "BaseClass.h"

class ChildClass : public BaseClass

{

    public:

        ChildClass();

        ChildClass(char* inputBase[]);

        void valueSqr();

        virtual ~ChildClass();

    protected:

    private:

};

#endif // CHILDCLASS_H

Файл ChildClass.cpp, реализация:

#include "../include/ChildClass.h"
ChildClass::ChildClass() : BaseClass()
{
    //ctor
}
ChildClass::ChildClass(char* inputBase[]) : BaseClass(inputBase)
{
 
}
void ChildClass::valueSqr()
{
    value *= value;
}
ChildClass::~ChildClass()
{
    //dtor
}

Файл с функцией main, main.cpp:

#include <iostream>
#include <cstdlib>
#include "include/BaseClass.h"
#include "include/ChildClass.h"
using namespace std;
int main(int argc, char* argv[], char* argp[])
{
    setlocale(LC_ALL, "rus");
    
    if(argc <= 1)
    {
        cout << "Определите аргументы программы! Пример: ./program 5.25" << endl;
        exit(1);
    }
    cout << "Hello world!" << endl;
    cout << "Значения BaseObject:" << endl;
    BaseClass BaseObject(argv);
    BaseObject.showValue();
    cout << "Значения ChildObject (возведение в квадрат):" << endl;
    ChildClass ChildObject(argv);
    ChildObject.valueSqr();
    ChildObject.showValue();
    return 0;
}

Пусть все приведённые файлы находятся в директории «HelloWorld», причём заголовочные файлы в поддиректории «include», а файлы реализаций *.cpp — в «src». Чтобы построить исполняемый файл в данном случае нужно выполнить следующие команды:

$ g++ -c -o HelloWorld.o main.cpp
$ g++ -c -o BaseClass.o src/BaseClass.cpp
$ g++ -c -o ChildClass.o src/ChildClass.cpp
$ g++ -o HelloWorld  HelloWorld.o  BaseClass.o  ChildClass.o
$ ls
BaseClass.o   ChildClass.o  HelloWorld  HelloWorld.o  include  main.cpp     src
$ ./HelloWorld

Определите аргументы программы! Пример: ./program 5.25

$./HelloWorld 5.25
Hello world!
Значения BaseObject:
Это value: 5.250000
Значения ChildObject (возведение в квадрат):
Это value: 27.562500

Автоматическая сборка — написание Make-файлов

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

Синтаксис Makefile’а следующий:

target: dependencies
[tab] system command

Это описание цели, в котором указываются зависимости  dependencies, команды для достижения цели system command, а также сама цель target. Символ табуляции [tab] является обязательным и только этим символом обозначаются команды для достижения целей. Например, для данного примера, одна из целей будет иметь следующее описание:

BaseClass.o: src/BaseClass.cpp
     g++ -c -o BaseClass.o src/BaseClass.cpp

Эта запись означает, что для получения объектного файла BaseClass.o нужно использовать исходный код из файла src/BaseClass.cpp, использовав команду g++, которой, в свою очередь, передаются соответствующие параметры.

Для вышеупомянутого проекта HelloWorld Make-файл будет иметь следующий вид:

all: HelloWorld
HelloWorld: HelloWorld.o BaseClass.o ChildClass.o
     g++ -o HelloWorld HelloWorld.o BaseClass.o ChildClass.o
HelloWorld.o: main.cpp
     g++ -c -o HelloWorld.o main.cpp
BaseClass.o: src/BaseClass.cpp
     g++ -c -o BaseClass.o src/BaseClass.cpp
ChildClass.o: src/ChildClass.cpp
     g++ -c -o ChildClass.o src/ChildClass.cpp

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

Теперь нужно выполнить команду make и запустить построенный исполняемый файл:

$ make
$./HelloWorld 5.25

Но даже и такой вариант для больших проектов не подойдёт, поскольку придётся обрабатывать практически каждый файл отдельно, задавая для них описания целей. Используя правила implicit rules, а также predrfined implicit rules можно заставить Make-файл автоматически обрабатывать содержимое проекта и генерировать описания целей для его компонентов. Для того, чтобы составлять универсальные Make-файлы нужно придерживаться определённых правил или даже стандартов, определяющих структуру всего проекта, например:

  1. Имя конечного исполняемого файла должно совпадать с папкой проекта.
  2. Заголовочные файлы и файлы реализаций находятся в отдельных (include и src соответственно) поддиректориях.
  3. Функция main находится в отдельном файле, расположенном в корне проекта над директориями src и include.
  4. Объектные файлы должны создаваться в отдельной поддиректории, например obj.
  5. Конечный исполняемый файл должен создаваться в отдельной поддиректории, например build.

Make-файл, удовлетворяющий этим требованиям для данного проекта HelloWorld может иметь такой вид:

SRC=src
OBJ=obj
BIN=build
MAIN=./main.cpp
 
TARGET=$(BIN)/$(shell basename `pwd`)
SOURCES=$(wildcard $(MAIN) $(SRC)/*.cpp)
OBJECTS=$(SOURCES:$(SRC)%.cpp=$(OBJ)%.o)
 
$(OBJ)/%.o: $(SRC)/%.cpp
     $(CXX) -c $(CFLAGS) $(CXXFLAGS) $(CPPFLAGS) -o $@ $<
 
all: $(TARGET)
 
$(OBJECTS): $(SOURCES)
 
$(TARGET): $(OBJECTS)
     $(CXX) -o $(TARGET) $(LDFLAGS) $(OBJECTS) $(LOADLIBES) $(LDLIBS)
     
clean:
     $(RM) $(filter-out $(MAIN),$(OBJECTS)) $(TARGET)
     
.PHONY: all clean

Обращение к переменным производится с помощью конструкции $(VALUE). Запись SOURCES=$(wildcard $(MAIN) $(SRC)/*.cpp) указывает, что исходные тексты будут искаться в поддиректории src по маске *.cpp и в файле main.cpp. А конструкция:

$(OBJ)/%.o: $(SRC)/%.cpp
     $(CXX) -c $(CFLAGS) $(CXXFLAGS) $(CPPFLAGS) -o $@ $<

описывает, как будут генерироваться цели для создания объектных файлов в каталоге obj из исходных текстов файлов в каталоге src. Цель clean подразумевает удаление всего, что связано с предыдущими сборками. Функция filter-out, присутствующая в списке команд для этой цели, нужна для того, чтобы при очистке не удалились нужные файлы, в данном случае — main.cpp. Цель .PHONY  описывает зависимости, не связанные напрямую с файлами.

Теперь, после выполнения команды make:

$ make

исполняемый файл будет в директории build:

$ ls build
HelloWorld

Объектные файлы — в директории obj:

$ ls obj
BaseClass.o  ChildClass.o

Следует отметить, что грамотное составление универсальных Make-файлов требует предварительно и внимательного изучения соответствующей документации, например по адресу http://www.gnu.org/software/make/manual/, где можно найти исчерпывающее описание для более подробного изучения данной темы.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

ИТ Проффи

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам:

Adblock detector