Команда 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`:
#includevoid 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”:
#includevoid 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
Після видалення модулів з бібліотеки не забудьте видалити їх оголошення із заголовочного файлу.
Поділіться своїм кодом
Бібліотеки дозволяють розробникам ділитися кодом в зручний спосіб. Надаючи бібліотеку та її заголовочний файл, можна дозволити іншим використовувати ваші функції, при цьому ваш вихідний код залишається приватним.