Як використовувати команду ar Linux для створення статичних бібліотек

Команда ar у Linux є потужним інструментом для управління бібліотеками функцій під час розробки програмного забезпечення. У цьому посібнику ви дізнаєтеся, як створювати, модифікувати та використовувати статичні бібліотеки у ваших проєктах, а також побачите приклади коду.

Команда ar – це досить давній інструмент, що існує з 1971 року. Її назва походить від початкового призначення – створення архівних файлів. Архівний файл – це, по суті, контейнер для інших файлів. Він дозволяє додавати, видаляти та витягувати файли. Хоча зараз для архівування частіше використовують інші утиліти, такі як tar, команда ar досі відіграє важливу роль у розробці програмного забезпечення.

Основне застосування ar сьогодні – це створення статичних бібліотек, які використовуються при розробці програм. Крім того, команда ar може створювати файли пакетів, такі як “.deb” файли, що використовуються в Debian Linux та його похідних (наприклад, Ubuntu).

Давайте розберемо, як створити і змінити статичну бібліотеку та як використовувати її у програмі. Для демонстрації ми створимо невелику бібліотеку для шифрування та дешифрування тексту.

Зверніть увагу, що цей приклад є спрощеним і використовує дуже простий шифр підстановки (A стає B, B стає C і т.д.). Не використовуйте його для захисту цінних даних.

Функції шифрування cipher_encode() та дешифрування cipher_decode()

Спочатку ми працюватимемо в каталозі “library”, а згодом створимо підкаталог “test”.

У каталозі “library” у нас будуть два файли. Перший файл, `cipher_encode.c`, містить функцію `cipher_encode()`:

void cipher_encode(char *text)
{
    for (int i=0; text[i] != 0x0; i++) {
        text[i]++;
    }
} // end of cipher_encode

Другий файл, `cipher_decode.c`, містить функцію `cipher_decode()`:

void cipher_decode(char *text)
{
    for (int i=0; text[i] != 0x0; i++) {
        text[i]--;
    }
} // end of cipher_decode

Ці файли з кодом називаються файлами вихідного коду. Ми створимо бібліотечний файл під назвою `libcipher.a`. Він буде містити скомпільовані версії обох файлів вихідного коду. Також створимо заголовочний файл `libcipher.h`, який міститиме визначення функцій нашої бібліотеки.

Маючи бібліотеку і заголовочний файл, розробники зможуть використовувати ці функції у своїх програмах, не переписуючи код. Це є важливим аспектом повторного використання коду.

Компіляція файлів cipher_encode.c та cipher_decode.c

Для компіляції файлів вихідного коду ми використаємо `gcc`, стандартний компілятор GNU. Опція `-c` (компілювати без лінкування) вказує `gcc` скомпілювати файли і створити проміжні об’єктні файли, а не виконувану програму. Нам потрібні саме об’єктні файли.

Перевіримо, чи наявні файли вихідного коду:

ls -l

У каталозі є два файли вихідного коду. Скомпілюємо їх:

gcc -c cipher_encode.c
gcc -c cipher_decode.c

Якщо компіляція пройшла успішно, `gcc` не виведе нічого.

В результаті будуть створені два об’єктні файли з розширеннями “.o”, готові до додавання в бібліотечний файл.

ls -l

Створення бібліотеки libcipher.a

Для створення файлу бібліотеки, ми використаємо команду `ar`.

Опція `-c` створює файл бібліотеки, `-r` додає файли (з заміною, якщо вони вже є), а `-s` створює індекс файлів всередині бібліотеки.

Створюємо файл бібліотеки `libcipher.a` та додаємо до нього об’єктні файли:

ar -crs libcipher.a cipher_encode.o cipher_decode.o

Перевіряємо, що файл бібліотеки створено:

ls -l

За допомогою опції `-t` можна переглянути вміст бібліотеки:

ar -t libcipher.a

Створення заголовного файлу libcipher.h

Файл `libcipher.h` необхідний для використання бібліотеки `libcipher.a`. Він містить оголошення функцій, які є в бібліотеці. Створимо цей файл:

void cipher_encode(char *text);
void cipher_decode(char *text);

Збережіть його під назвою `libcipher.h` в тому ж каталозі, де знаходиться `libcipher.a`.

Використання бібліотеки libcipher

Щоб перевірити роботу бібліотеки, напишемо невелику тестову програму. Створимо каталог “test”:

mkdir test

Скопіюємо файли бібліотеки та заголовка в новий каталог:

cp libcipher.* ./test

Перейдемо до каталогу “test”:

cd test

Перевіримо наявність скопійованих файлів:

ls -l

Створимо файл `test.c` з наступним кодом:

#include 
#include 
#include "libcipher.h"

int main(int argc, char *argv[])
{
    char text[]="How-To Geek loves Linux";
    puts(text);
    cipher_encode(text);
    puts(text);
    cipher_decode(text);
    puts(text);
    exit (0);
} // end of main

Ця програма:

  • Включає заголовочний файл `libcipher.h`.
  • Створює рядок `text` зі словами “How-To Geek loves Linux”.
  • Виводить оригінальний текст.
  • Викликає `cipher_encode()` для шифрування тексту і виводить зашифрований текст.
  • Викликає `cipher_decode()` для дешифрування тексту і виводить розшифрований текст.

Скомпілюємо програму `test.c` та злінкуємо її з бібліотекою. Опція `-o` задає ім’я виконуваної програми:

gcc test.c libcipher.a -o test

Запускаємо тестову програму:

./test

Якщо все зроблено правильно, програма виведе оригінальний, зашифрований та розшифрований рядки. Наша бібліотека працює!

Додавання ще одного модуля до бібліотеки

Давайте розширимо нашу бібліотеку, додавши функцію, що виводить версію бібліотеки. Створимо новий файл `cipher_version.c`:

#include 

void cipher_version(void)
{
    puts("How-To Geek :: VERY INSECURE Cipher Library");
    puts("Version 0.0.1 Alphan");
} // end of cipher_version

Додамо оголошення нової функції до файлу `libcipher.h`:

void cipher_encode(char *text);
void cipher_decode(char *text);
void cipher_version(void);

Скомпілюємо файл `cipher_version.c`:

gcc -c cipher_version.c

Додамо об’єктний файл до бібліотеки. Опція `-v` робить вивід ar більш детальним:

ar -rsv libcipher.a cipher_version.o

ar повідомить про додавання нового файлу в бібліотеку.

Перевіримо вміст бібліотеки:

ar -t libcipher.a

Тепер в бібліотеці три модулі.

Використання функції cipher_version()

Видалимо старі файли з каталогу “test”, скопіюємо нові та перейдемо до нього:

rm ./test/libcipher.*
cp libcipher.* ./test
cd test

Змінимо програму `test.c` так, щоб вона викликала нову функцію `cipher_version()`:

#include 
#include 
#include "libcipher.h"

int main(int argc, char *argv[])
{
    char text[]="How-To Geek loves Linux";
    cipher_version();
    puts(text);
    cipher_encode(text);
    puts(text);
    cipher_decode(text);
    puts(text);
    exit (0);
} // end of main

Збережемо `test.c`, скомпілюємо та запустимо оновлену програму:

gcc test.c libcipher.a -o test

Запустимо програму:

./test

Тепер у виводі програми з’явиться версія бібліотеки.

Заміна модуля в бібліотеці

Номер версії бібліотеки в виводі неправильний, бо насправді це вже друга версія бібліотеки, тому потрібно замінити модуль `cipher_version()` на правильний. Спочатку змінимо текст в `cipher_version.c` на “Version 0.0.2 Alpha”:

#include 

void cipher_version(void)
{
  puts("How-To Geek :: VERY INSECURE Cipher Library");
  puts("Version 0.0.2 Alphan");
} // end of cipher_version

Скомпілюємо файл:

gcc -c cipher_version.c

Замінимо старий модуль на новий:

ar -rsv libcipher.a cipher_version.o

ar повідомить про заміну модуля.

Використання оновленої функції cipher_version()

Скопіюємо файли бібліотеки до каталогу “test”, перейдемо до нього та зкомпілюємо програму з оновленою бібліотекою:

cp libcipher.* ./test
cd ./test
gcc test.c libcipher.a -o test

Запустимо тестову програму:

./test

Тепер версія бібліотеки відображається правильно.

Видалення модулів з бібліотеки

Видалимо модуль `cipher_version.o` з бібліотеки. Для цього використовуємо опцію `-d`:

ar -dsv libcipher.a cipher_version.o

ar повідомить про видалення модуля.

Перевіримо вміст бібліотеки:

ar -t libcipher.a

Після видалення модулів з бібліотеки не забудьте видалити їх оголошення із заголовочного файлу.

Поділіться своїм кодом

Бібліотеки дозволяють розробникам ділитися кодом в зручний спосіб. Надаючи бібліотеку та її заголовочний файл, можна дозволити іншим використовувати ваші функції, при цьому ваш вихідний код залишається приватним.