Перейти к основному содержимому

Make-файлы ядра linux

Документы описывает make-файлы ядра linux.

Обзорная часть

Make-файлы состоят из пяти частей:

Makefile                    основной make-файл.
.config файл конфигурации ядра.
arch/$(SRCARCH)/Makefile make-файл для архитектуры.
scripts/Makefile.* общие правила и т.д. для всех kbuild make-файлов.
kbuild Makefiles присутствуют в каждой поддиректории.

Основной make-файл считывает файл .config, который получается из процесса конфигурации ядра. Он отвечает за сборку двух основных компонентов: vmlinux (образ резидентного ядра) и модулей (любые файлы модулей). Сборка происходит рекурсивно спускаясь в поддиректории дерева исходного кода ядра.

Список посещаемых поддиректорий, зависит от конфигурации ядра. Основной make-файл включает в себя текст make-файл архитектуры с именем arch/$(SRCARCH)/Makefile. Make-файл архитектуры предоставляет основному make-файлу информацию, специфичную для архитектуры.

В каждой поддиректории есть make-файл kbuild, который выполняет команды, переданные сверху. Make-файл kbuild использует информацию из файла .config для создания различных списков файлов, используемых kbuild для построения встроенных или модульных целей.

scripts/Makefile.* содержит все определения/правила и т. д., которые используются для построения ядра на основе make-файлов kbuild.

Кто что делает

Есть четыре типа людей, взаимодействующих с make-файлами ядра.

  1. Пользователи - люди, которые собирают ядра. Эти люди используют команды, такие как make menuconfig или make. Обычно они не читают или не редактируют никакие make-файлы ядра (или любые другие исходные файлы).

  2. Обычные разработчики - люди, которые работают над таким функционалом, как драйверы устройств, файловые системы и сетевые протоколы. Этим людям необходимо поддерживать make-файлы kbuild для подсистемы, над которой они работают. Для эффективной работы им необходимо иметь общее представление о make-файлах ядра, а также подробные знания об общедоступном интерфейсе для kbuild.

  3. Разработчики архитектуры - люди, которые работают над целой архитектурой, такой как sparc или x86. Разработчики архитектуры должны знать о make-файле для архитектуры, а также о make-файлах для kbuild.

  4. Разработчики kbuild - люди, которые работают над самой системой сборки ядра. Этим людям необходимо знать обо всех аспектах make-файлов ядра.

Эта статья предназначена для обычных разработчиков и разработчиков архитектур.

Файлы kbuild

Большинство make-файлов в ядре это kbuild make-файлы, использующие инфраструктуру kbuild. Эта глава знакомит с синтаксисом, используемым в make-файлах kbuild.

Предпочтительным именем для файлов kbuild является Makefile, хотя можно использовать и Kbuild. Если существуют и файл Makefile и файл Kbuild, то будет использован файл Kbuild.

Раздел "Определения целей" - это краткое введение; дальнейшие главы предоставляют более подробные сведения с реальными примерами.

Определения целей

Определение целей является основной частью (сердцем) make-файла для kbuild. Эти строки определяют файлы, которые должны быть собраны, любые особые опции компиляции и любые поддиректории, в которые нужно войти рекурсивно.

Самый простой make-файл для kbuild содержит одну строку:

Пример:

obj-y += foo.o

Это сообщает kbuild, что в этом каталоге есть один объект, с именем foo.o. foo.o будет создан из foo.c или foo.S.

Если foo.o должен быть создан как модуль, используется переменная obj-m. Поэтому часто используется следующий шаблон:

Пример:

obj-$(CONFIG_FOO) += foo.o

$(CONFIG_FOO) вычисляется как "y" (для встроенного) или "m" (для модуля). Если CONFIG_FOO не равен ни "y", ни "m", то файл не будет скомпилирован или скомпонован.

Цели: встраиваемые объекты – obj-y

Make-файл kbuild указывает файлы объектов для vmlinux в списках $(obj-y). Эти списки зависят от конфигурации ядра.

Kbuild компилирует все файлы $(obj-y). Затем он вызывает $(AR) rcSTP для слияния этих файлов в один файл – built-in.a. Это маленький архив без таблицы символов, который затем будет скомпонован в vmlinux с помощью scripts/link-vmlinux.sh.

Порядок файлов в $(obj-y) имеет большое значение. Дубликаты в списках допускаются: первой будет скомпонован в built-in.a, а последующие будут проигнорированы.

Порядок компоновки важен, потому что определенные функции (module_init() / __initcall) будут вызваны при загрузке в том порядке, в котором они появляются. Поэтому имейте в виду, что изменение порядка компоновки может, например, изменить порядок обнаружения ваших SCSI-контроллеров и, следовательно, изменить нумерацию ваших дисков.

Пример:

#drivers/isdn/i4l/Makefile
# Make-файл для подсистемы ядра ISDN и драйверов устройств.
# Каждый конфигурационный параметр активирует список файлов.
obj-$(CONFIG_ISDN_I4L) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

Цели: загружаемые модули – obj-m

$(obj-m) указывает объектные файлы, которые собираются как загружаемые модули ядра.

Модуль может быть собран из одного исходного файла или нескольких исходных файлов. В случае одного исходного файла make-файл kbuild просто добавляет файл в $(obj-m).

Пример:

#drivers/isdn/i4l/Makefile
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
Note: В этом примере $(CONFIG_ISDN_PPP_BSDCOMP) вычисляется в “m”

Если модуль ядра строится из нескольких исходных файлов, вы указываете, что хотите построить модуль так же, как и выше; однако kbuild должен знать, из каких объектных файлов вы хотите построить свой модуль, поэтому вам нужно сообщить ему, установив переменную $(<module_name>-y).

Пример:

#drivers/isdn/i4l/Makefile
obj-$(CONFIG_ISDN_I4L) += isdn.o
isdn-y := isdn_net_lib.o isdn_v110.o isdn_common.o

В этом примере имя модуля будет isdn.o. Kbuild скомпилирует объекты, перечисленные в $(isdn-y), затем выполнит $(LD) -r для списка этих файлов, чтобы сгенерировать isdn.o.

Из-за того, что kbuild распознает $(<module_name>-y) для составных объектов, вы можете использовать значение символа CONFIG_ для необязательного включения файла объекта как части составного объекта.

Пример:

#fs/ext2/Makefile
obj-$(CONFIG_EXT2_FS) += ext2.o
ext2-y := balloc.o dir.o file.o ialloc.o inode.o ioctl.o \
namei.o super.o symlink.o
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o \
xattr_trusted.o

В этом примере xattr.o, xattr_user.o и xattr_trusted.o являются частью составного объекта ext2.o только в том случае, если $(CONFIG_EXT2_FS_XATTR) вычисляется как "y".

примечание

Конечно, когда вы собираете объекты в ядро, приведенный выше синтаксис также будет работать. Так что, если у вас CONFIG_EXT2_FS=y, то kbuild построит для вас файл ext2.o из отдельных частей и затем свяжет его с built-in.a, как и ожидается.

Цели: файлы библиотек – lib-y

Объекты, перечисленные с помощью obj-*, используются для модулей или объединяются в built-in.a для этой конкретной директории. Также есть возможность перечислить объекты, которые будут включены в библиотеку lib.a. Все объекты, перечисленные с lib-y, объединяются в одну библиотеку для этой директории. Объекты, перечисленные в obj-y и дополнительно перечисленные в lib-y, не будут включены в библиотеку, поскольку они в любом случае будут доступны. Для консистентности объекты, перечисленные в lib-m, будут включены в lib.a.

Обратите внимание, что в одном и том же make-файле kbuild может перечислять встраиваемые файлы и файлы, которые будут частью библиотеки. Поэтому в одной и той же директории могут находиться как файл built-in.a, так и файл lib.a.

Пример:

#arch/x86/lib/Makefile
lib-y := delay.o

Это создаст библиотеку lib.a на основе delay.o. Для того чтобы kbuild действительно распознал, что создается lib.a, директория должна быть перечислена в libs-y.

См. также "Список директорий для посещения при погружении".

Использование lib-y обычно ограничено директориями lib/ и arch/*/lib.

Цели: не встраиваемые, но необходимые для vmlinux – extra-y

extra-y указывает цели, необходимые для сборки vmlinux, но которые не объединяются в built-in.a. Например, скрипт компоновки vmlinux, который расположен в arch/${SRCARCH}/kernel/vmlinux.lds.

Пример:

# arch/x86/kernel/Makefile
extra-y += vmlinux.lds

$(extra-y) должен содержать только цели, необходимые для vmlinux.

Kbuild пропускает extra-y, когда vmlinux явно не является окончательной целью. (например, make modules или сборка внешних модулей)

Если вы намерены собирать цели безусловно, правильным синтаксисом для этого является always-y (объясняется в следующем разделе).

Цели: безусловные – always-y

always-y указывает цели, которые собираются всегда, когда Kbuild посещает make-файл.

Пример:

# ./Kbuild
offsets-file := include/generated/asm-offsets.h
always-y += $(offsets-file)

Флаги компиляции

  • ccflags-y, asflags-y и ldflags-y

    Эти три флага применяются только к make-файлу kbuild, в котором они назначены. Они используются для всех обычных вызовов cc, as и ld, происходящих во время рекурсивной сборки. Примечание: Флаги с тем же поведением ранее назывались: EXTRA_CFLAGS, EXTRA_AFLAGS и EXTRA_LDFLAGS. Они по-прежнему поддерживаются, но их использование устарело и нежелательно (deprecated).

    ccflags-y указывает параметры для компиляции с $(CC).

    Пример:

    # drivers/acpi/acpica/Makefile
    ccflags-y := -Os -D_LINUX -DBUILDING_ACPICA
    ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT

    Эта переменная обязательна, потому что основной make-файл владеет переменной $(KBUILD_CFLAGS) и использует ее для флагов компиляции для всего дерева.

    asflags-y указывает параметры для assembler'а.

    Пример:

    #arch/sparc/kernel/Makefile
    asflags-y := -ansi

    ldflags-y указывает параметры для компоновки с $(LD) .

    Пример:

    #arch/cris/boot/compressed/Makefile
    ldflags-y += -T $(src)/decompress_$(arch-y).lds
  • subdir-ccflags-y, subdir-asflags-y

    Два этих флага почти полностью идентичны на ccflags-y и asflags-y. Разница заключается в том, что варианты с subdir- имеют эффект для make-файла kbuild, в котором они присутствуют, а также для всех поддиректорий. Опции, заданные с помощью subdir-*, добавляются в командную строку перед опциями, указанными с использованием вариантов без subdir-.

    Пример:

    subdir-ccflags-y := -Werror
  • ccflags-remove-y, asflags-remove-y

    Эти флаги используются для удаления определенных флагов для вызовов компилятора и ассемблера.

    Пример:

    ccflags-remove-$(CONFIG_MCOUNT) += -pg
  • CFLAGS_$@, AFLAGS_$@

    CFLAGS_$@ и AFLAGS_$@ применяются только к командам в текущем make-файле kbuild.

    $(CFLAGS_$@) указывает опции для $(CC) для каждого файла отдельно. Часть $@ имеет значение, которое определяет файл, к которому она применяется.

    CFLAGS_$@ имеет более высокий приоритет, чем ccflags-remove-y; CFLAGS_$@ может снова добавить флаги компилятора, которые были удалены с помощью ccflags-remove-y.

    Пример:

    # drivers/scsi/Makefile
    CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF

    Эта строка указывает флаги компиляции для файла aha152x.o.

    $(AFLAGS_$@) - это аналогичная $(CFLAGS_$@) функция только для исходных файлов на языке ассемблера.

    AFLAGS_$@ имеет более высокий приоритет, чем asflags-remove-y; AFLAGS_$@ может повторно добавить флаги ассемблера, которые были удалены asflags-remove-y.

    Пример:

    # arch/arm/kernel/Makefile
    AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
    AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312
    AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt

Отслеживание зависимостей

Kbuild отслеживает зависимости от следующего:

  1. Все необходимые файлы (как *.c, так и *.h)
  2. Опции CONFIG_, используемые во всех обязательных файлах
  3. Командная строка, используемая для компиляции цели

Таким образом, если вы измените опцию для $(CC), все затронутые файлы будут перекомпилированы.

Пользовательские (custom) правила

Пользовательские правила используются, когда инфраструктура kbuild не предоставляет необходимую поддержку. Типичным примером являются заголовочные файлы, генерируемые во время процесса сборки. Ещё одним примером являются архитектурно-специфические make-файлы, которым требуются пользовательские правила для подготовки загрузочных образов и т. д.

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

Для определения пользовательских правил используются две переменные:

  • $(src)

    $(src) - это директория, где находится make-файл. Всегда используйте $(src), когда обращаетесь к файлам, находящимся в дереве исходного кода.

  • $(obj)

    $(obj) - это директория, где сохраняется цель. Всегда используйте $(obj) при обращении к созданным файлам. Используйте $(obj) для шаблонных правил, которые должны работать как для созданных файлов, так и для реальных исходных файлов (VPATH поможет найти необходимые файлы не только в дереве объектов, но и в дереве исходных файлов).

    Пример:

    #drivers/scsi/Makefile
    $(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl
    $(CPP) -DCHIP=810 - < $< | ... $(src)/script_asm.pl

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

    Целевой файл зависит от двух необходимых файлов. Ссылки на целевой файл имеют префикс $(obj), ссылки на необходимые файлы – $(src) (поскольку они не являются сгенерированными файлами).

  • $(kecho)

    Вывод информации пользователю в правиле часто является хорошей практикой, но при выполнении make -s не ожидается видеть какой-либо вывод, за исключением предупреждений/ошибок. Для поддержки этого kbuild определяет $(kecho), который будет выводить текст после $(kecho) в стандартный вывод (stdout), за исключением случаев использования make -s.

    Пример:

    # arch/arm/Makefile
    $(BOOT_TARGETS): vmlinux
    $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
    @$(kecho) ' Kernel: $(boot)/$@ is ready'

    Когда make-файл запускается с не установленным KBUILD_VERBOSE, обычно отображается только сжатая версия команды. Чтобы включить это поведение для пользовательских команд, kbuild требует установки двух переменных:

    quiet_cmd_<command> - что должно быть выведено
    cmd_<command> - команда для выполнения

    Пример:

    # lib/Makefile
    quiet_cmd_crc32 = GEN $@
    cmd_crc32 = $< > $@

    $(obj)/crc32table.h: $(obj)/gen_crc32table
    $(call cmd,crc32)

    При обновлении цели $(obj)/crc32table.h строка:

    GEN     lib/crc32table.h

    будет выведена вместе с make KBUILD_VERBOSE=.

Обнаружение изменения команды

При проверке правила сравниваются отметки времени между целью и необходимыми ей файлами. GNU Make обновляет цель, когда хотя бы один из необходимых файлов новее неё.

Цель должна быть пересобрана также в том случае, если вызываемая команда изменилась с последнего раза. Это не поддерживается самим Make, поэтому Kbuild достигает этого с помощью своего рода метапрограммирования.

Для этой цели используется макрос if_changed, в следующей форме:

quiet_cmd_<command> = ...
cmd_<command> = ...

<target>: <source(s)> FORCE
$(call if_changed,<command>)

Любая цель, которая использует if_changed, должна быть перечислена в $(targets), в противном случае проверка командной строки завершится неудачей, и цель будет всегда пересобираться.

Если цель уже перечислена в распознаваемом синтаксисе, таком как obj-y/m, lib-y/m, extra-y/m, always-y/m, hostprogs, userprogs, то Kbuild автоматически добавляет ее в $(targets). В противном случае цель должна быть явно добавлена в $(targets).

Присваивания $(targets) не содержат префикс $(obj)/. if_changed может использоваться совместно с пользовательскими правилами, как определено в Пользовательских правилах.

к сведению

Типичной ошибкой является забытие использования ключевого слова FORCE.

target: source(s) FORCE
От авторов перевода

Слово FORCE используется как специальная цель, которая всегда считается устаревшей.

к сведению

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

$(call if_changed, objcopy)
к сведению

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

Поддерживаемый функционал $(CC)

Ядро может быть собрано с несколькими различными версиями $(CC), каждая поддерживает уникальный набор функций и опций. kbuild предоставляет базовую поддержку для проверки допустимых опций для $(CC). $(CC) обычно является компилятором gcc, но также доступны и альтернативы.

  • as-option

    as-option используется для проверки того, поддерживает ли $(CC)(когда используется для компиляции файлов ассемблера (*.S)) указанную опцию. Можно указать дополнительную вторую опцию, если первая опция не поддерживается.

    Пример:

    #arch/sh/Makefile
    cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),)

    В указанном выше примере, cflags-y будет присвоено значение опции -Wa$(comma)-isa=$(isa-y), если она поддерживается $(CC). Второй аргумент является необязательным, и, если указан, будет использоваться, если первый аргумент не поддерживается.

  • as-instr

    as-instr проверяет, сообщает ли ассемблер о конкретной инструкции, а затем выводит либо option1, либо option2. В тестовой инструкции поддерживаются символы C escapes. Примечание: as-instr-option использует KBUILD_AFLAGS для опций ассемблера.

  • cc-option

    cc-option используется для проверки поддержки $(CC) определенной опции, и если опция не поддерживается, используется дополнительная вторая опция.

    Пример:

    #arch/x86/Makefile
    cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586)

    В указанном выше примере, для cflags-y будет назначена опция -march=pentium-mmx, если она поддерживается $(CC), в противном случае -march=i586. Второй аргумент для cc-option является необязательным, и если он опущен, cflags-y не получит никакое значение, если первая опция не поддерживается. Примечание: cc-option использует KBUILD_CFLAGS для опций $(CC).

  • cc-option-yn

    cc-option-yn используется для проверки поддержки $(CC) заданной опцией и возвращает "y", если она поддерживается, в противном случае – "n".

    Пример:

    #arch/ppc/Makefile
    biarch := $(call cc-option-yn, -m32)
    aflags-$(biarch) += -a32
    cflags-$(biarch) += -m32

    В приведенном примере $(biarch) устанавливается в 'y', если $(CC) поддерживает опцию -m32. Когда $(biarch) равно "y", развёрнутым переменным $(aflags-y) и $(cflags-y) будут присвоены значения -a32 и -m32 соответственно.

    к сведению

    cc-option-yn использует KBUILD_CFLAGS для параметров $(CC).

  • cc-disable-warning

    Функция cc-disable-warning проверяет, поддерживает ли $(CC) указанное предупреждение и возвращает параметр командной строки для его отключения. Эта специальная функция необходима, потому что gcc 4.4 и более поздние версии принимают любую неизвестную опцию -Wno-* и предупреждают об этом только в случае ещё одного предупреждения в исходном файле.

    Пример:

    KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)

    В приведенном примере опция -Wno-unused-but-set-variable будет добавлена к KBUILD_CFLAGS только в том случае, если $(CC) действительно ее принимает.

  • gcc-min-version

    Функция gcc-min-version проверяет, является ли значение $(CONFIG_GCC_VERSION) большим или равным предоставленному значению, и возвращает 'y', если это так.

    Пример:

    cflags-$(call gcc-min-version, 70100) := -foo

    В этом примере переменной cflags-y будет присвоено значение -foo, если компилятором $(CC) является gcc и $(CONFIG_GCC_VERSION) >= 7.1.

  • clang-min-version

    Функция clang-min-version проверяет, является ли значение $(CONFIG_CLANG_VERSION) большим или равным предоставленному значению, и возвращает 'y', если это так.

    Пример:

    cflags-$(call clang-min-version, 110000) := -foo

    В данном примере переменной cflags-y будет присвоено значение -foo, если компилятором $(CC) является clang и $(CONFIG_CLANG_VERSION) >= 11.0.0.

  • cc-cross-prefix

    cc-cross-prefix используется для проверки наличия $(CC) в пути с одним из указанных префиксов. Возвращается первый префикс, для которого существует префикс$(CC) в PATH. Если ни один префикс$(CC) не найден, то ничего возвращается.

    Дополнительные префиксы разделяются одним пробелом в вызове cc-cross-prefix.

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

    Рекомендуется устанавливать CROSS_COMPILE только в случае кросс-сборки (архитектура хоста отличается от целевой архитектуры). Если CROSS_COMPILE уже установлен, то оставьте его со старым значением.

    Пример:

    #arch/m68k/Makefile
    ifneq ($(SUBARCH),$(ARCH))
    ifeq ($(CROSS_COMPILE),)
    CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu-)
    endif
    endif

Поддерживаемый функицонал $(LD)

  • ld-option

    ld-option используется для проверки поддержки $(LD) предоставленной опции. ld-option принимает две опции в качестве аргументов.

    Второй аргумент является необязательной опцией, которая может быть использована, если первая опция не поддерживается $(LD).

    Пример:

    #Makefile
    LDFLAGS_vmlinux += $(call ld-option, -X)

Вызов скриптов

Правила make могут вызывать скрипты для сборки ядра. Правила всегда должны предоставлять соответствующий интерпретатор для выполнения скрипта. Они не должны полагаться на то, установлен ли бит исполняемости и не должны вызывать скрипт напрямую. Тем не менее для удобства ручных вызовов скриптов (например, вызова ./scripts/checkpatch.pl), рекомендуется установить бит исполняемости на скрипты.

От авторов перевода

Под "битом исполняемости" имеется ввиду chmod +x ....

Kbuild предоставляет переменные $(CONFIG_SHELL), $(AWK), $(PERL) и $(PYTHON3) для обращения к интерпретаторам соответствующих скриптов.

Пример:

#Makefile
cmd_depmod = $(CONFIG_SHELL) $(srctree)/scripts/depmod.sh $(DEPMOD) \
$(KERNELRELEASE)

Поддержка программ хоста

Kbuild поддерживает сборку исполняемых файлов на хосте для использования их на этапе компиляции.

Для использования исполняемого файла на хосте требуется два шага.

Первый шаг - сообщить kbuild о существовании хост-программы. Это делается с использованием переменной hostprogs.

Второй шаг - добавить явную зависимость от исполняемого файла. Это можно сделать двумя способами. Либо добавить зависимость в правило, либо использовать переменную always-y. Оба варианта описаны далее.

Простая программа хоста

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

Следующая строка сообщает kbuild, что программа bin2hex должна быть собрана на компьютере, где выполняется сборка.

Пример:

hostprogs := bin2hex

В указанном примере Kbuild предполагает, что bin2hex создается из одного исходного c-файла с именем bin2hex.c, расположенного в той же директории, что и make-файл.

Составные программы хоста

Хост-программы могут быть созданы на основе составных объектов. Синтаксис, используемый для определения составных объектов для программ хоста, аналогичен синтаксису, используемому для объектов ядра. $(<executable>-objs) перечисляет все объекты, используемые для компоновки конечного исполняемого файла.

Пример:

#scripts/lxdialog/Makefile
hostprogs := lxdialog
lxdialog-objs := checklist.o lxdialog.o

Объекты с расширением .o компилируются из соответствующих файлов .c. В приведенном выше примере, checklist.c компилируется в checklist.o и lxdialog.c компилируется в lxdialog.o.

Наконец, два файла .o линкуются с исполняемым файлом lxdialog. Примечание: синтаксис <executable>-y не разрешен для программ хоста.

Использование C++ для программ хоста

kbuild предлагает поддержку программ хоста, написанных на C++. Это было введено исключительно для поддержки kconfig и не рекомендуется для общего использования.

Пример:

#scripts/kconfig/Makefile
hostprogs := qconf
qconf-cxxobjs := qconf.o

В приведенном выше примере исполняемый файл состоит из C++ файла qconf.cc - определённого как $(qconf-cxxobjs).

Если qconf состоит из смеси файлов .c и .cc, то для указания этого можно использовать дополнительную строку.

Пример:

#scripts/kconfig/Makefile
hostprogs := qconf
qconf-cxxobjs := qconf.o
qconf-objs := check.o

Использование Rust для программ хоста

Kbuild предлагает поддержку программ хоста, написанных на Rust. Однако, поскольку набор инструментов Rust не является обязательным для компиляции ядра, его можно использовать только в сценариях, где требуется наличие Rust (например, при включенной опции CONFIG_RUST).

Пример:

hostprogs     := target
target-rust := y

Kbuild скомпилирует цель, используя target.rs в качестве корня crate, расположенного в той же директории, что и Makefile. Crate может состоять из нескольких исходных файлов (см. samples/rust/hostprogs).

Настройка опций компилятора для программ хоста

При компиляции программ хоста можно устанавливать конкретные флаги. Программы всегда будут компилироваться с использованием $(HOSTCC), передаваемого опции, указанные в $(KBUILD_HOSTCFLAGS).

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

Пример:

#scripts/lxdialog/Makefile
HOST_EXTRACFLAGS += -I/usr/include/ncurses

Для установки конкретных флагов для одного файла используется следующая конструкция:

Пример:

#arch/ppc64/boot/Makefile
HOSTCFLAGS_piggyback.o := -DKERNELBASE=$(KERNELBASE)

Также можно указать дополнительные параметры для компоновщика.

Пример:

#scripts/kconfig/Makefile
HOSTLDLIBS_qconf := -L$(QTDIR)/lib

При компоновке qconf ему будет передан дополнительный параметр -L$(QTDIR)/lib.

Когда на самом деле создаются программы хоста

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

Это возможно в двух случаях:

  1. Явное перечисление необходимых файлов в пользовательском правиле.

    Пример:

    #drivers/pci/Makefile
    hostprogs := gen-devlist
    $(obj)/devlist.h: $(src)/pci.ids $(obj)/gen-devlist
    ( cd $(obj); ./gen-devlist ) < $<

    Цель $(obj)/devlist.h не будет построена до обновления $(obj)/gen-devlist. Обратите внимание, что ссылки на программы хоста в пользовательских правилах должны быть предварительно указаны префиксом $(obj).

  2. Использование always-y

    Если нет подходящего пользовательского правила, и хост-программа должна быть построена при посещении make-файла, используйте переменную always-y.

    Пример:

    #scripts/lxdialog/Makefile
    hostprogs := lxdialog
    always-y := $(hostprogs)

    Kbuild предоставляет следующее сокращение для этого:

    hostprogs-always-y := lxdialog

    Это скажет kbuild построить lxdialog, даже если он не упоминается в каком-либо правиле.