Цей контент є частиною серії: Розробка модулів ядра Linux
Слідкуйте за виходом нових статей цієї серії.
У попередніх частинах циклу були розглянуті практично всі питання, які стосуються процесу створення модулів ядра, крім самого важливого. Це питання складання модулів і написання файлів сценаріїв збірки Makefile. Раніше в прикладах вже використовувалися різні варіанти Makefile, однак поряд з вивченням окремих випадків, необхідно знати і базові принципи створення Makefile'ов для збірки модулів ядра.
параметри компіляції
Параметри компіляції модуля можна перевизначити, змінивши змінні, визначені в сценарії, що виконує складання, наприклад:
Таким же чином можна доповнити визначення необхідних препроцесорну змінних (які спрацюють в збираному коді), специфічних для збірки модуля:
(Зверніть увагу на знак + =).
Примітка. Звідки беруться змінні, що не певні явно в тексті файлу Makefile, як, наприклад, EXTRA_CFLAGS. Або звідки беруться правила складання за замовчуванням (як в прикладі використання ассемблерного коду, представленому в попередній статті)? І як можна подивитися ці правила? Утиліта make має безліч значень за замовчуванням (змінних, суфіксів і т.д.), найважливішими з яких є правила обробки суфіксів, а також визначення внутрішніх змінних оточення. Вся ця інформація називається базою даних make і може бути виведена по ключу -p. Але обсяг виведеної інформації буде дуже великий, тому розумно відправити цей висновок в файл, а вже потім вивчити його:
Лістинг 1. Визначення внутрішніх змінних оточення make
Тепер можна використовувати всі ці змінні в власних сценаріях збірки Makefile.
Збірка модулів в деталях
У попередніх версіях ядра (2.4 і раніше) збірка модулів здійснювалася більш складними способами, які до того ж відрізнялися від підходу, використовуваного у версії 2.6 (тому не варто акцентувати увагу на публікаціях, які стосуються колишніх версіями ядра). Починаючи з версії 2.6, розробники ядра створили цілу систему макросів збірки, які роблять збірку чисто технічним дією.
Далі будуть розглядатися різні особливості процедури складання (make) проектів модулів ядра. Також буде представлений і проаналізовано набір сценаріїв збірки (Makefile) для найбільш часто зустрічаються ситуацій, наприклад: збірка кількох модулів в проекті, збірка модуля об'єднанням декількох файлів з вихідним кодом і т.д.
Як одночасно зібрати кілька модулів?
У раніше згадуваному файлі Makefile може бути виконана одночасна збірка будь-якої кількості модулів:
Лістинг 2. Одночасна збірка двох модулів
Як зібрати модуль разом з відносяться до нього програмами?
Часто потрібно зібрати не тільки сам модуль, а й кілька користувальницьких програм, що використовуються спільно з модулем (тести, утиліти, і т.д.). Найчастіше в такому сценарії модуль і призначені для користувача програми використовують загальні файли визначень (заголовки). Ось як виглядає фрагмент Makefile для збірки в одному робочому каталозі модуля і всіх використовують його програм (архів ioctl.tgz, який буде розглядатися в найближчому майбутньому) .:
Лістинг 3. Одночасна збірка модуля і призначених для користувача програм
Особливість такої спільної збірки полягає в тому, що і модуль, і призначені для користувача процеси включають (за допомогою директиви #include) одні й ті ж загальні та узгоджені визначення (приклад, в тому ж архіві ioctl.tgz):
Такий сполучний файл містить загальні визначення, як для коду простору ядра, так і для призначених для користувача додатків. Як приклад показано вміст файлу ioctl.h:
У зв'язку з цим може виникнути певна проблема, так як при складанні додатків і модулів (що використовують спільні визначення) для пошуку системних (#include <.> ) Заголовків файлів використовуються різні каталоги за замовчуванням. / Usr / include для процесів і / lib / modules / `uname -r` / build / include для модулів. Прийнятним рішенням буде включення до загального заголовки (ioctl.h) фрагмента подібного виду:
Лістинг 4. Умовні визначення для ядра і для додатків
При всій схожості імен заголовків файлів (а іноді і повний збіг, наприклад:
призначені для користувача бібліотеки
На додаток до набору додатків простору користувачів може виявитися зручним зібрати у вигляді єдиної бібліотеки цілий ряд спільно використовуваних цими додатками функцій (так усувається дублювання коду, спрощується внесення змін і поліпшується структура проекту). Фрагмент Makefile з архіву time.tgz, який буде представлений в одній з наступних статей, демонструє, як це зробити, не вказуючи в явному вигляді всі цілі збірки (перераховані списком у змінній OBJLIST) для кожного такого об'єктного файлу, що включається в бібліотеку (реалізує окрему функцію бібліотеки). В даному випадку збирається статична бібліотека libdiag.a:
Лістинг 5. Збірка користувальницької статичної бібліотеки
У лістингу 5 збираються дві мети prog і lib. об'єднані в одну загальну мету all. При бажанні статичну бібліотеку можна замінити на динамічну (що розділяється), що може бути затребуване в великих проектах. При цьому в Makefile потрібно внести тільки незначні зміни (всі інші файли проекту залишаються в незмінному вигляді).
Лістинг 6. Збірка користувальницької вашої бібліотеки
Примітка. У разі побудови вашої бібліотеки необхідно також забезпечити розміщення новоствореної бібліотеки (в нашому прикладі це libdiag.so) на шляху, де вона буде знайдена динамічним загрузчиком. Розміщення в "поточному каталозі" в даному випадку не підходить: відносні імена каталогів не застосовуються для пошуку динамічних бібліотек. Вирішити це завдання можна різними способами:
Але всі ці питання відносяться вже до системного адміністрування і виходять за рамки даної статті.
висновок
У цій статті були розглянуті стандартні питання, що відносяться до процесу складання модулів ядра з програмного коду. У наступній статті ми продовжимо обговорення питань, пов'язаних з цією темою.