Este artigo foca na criação de um projeto de teste simplificado baseado nos princípios do sistema de Makefiles do kernel Linux. Ele serve como uma ferramenta prática para compreender a arquitetura de compilação do kernel, destacando características como modularidade e configuração cruzada.
Estrutura do Código-Fonte
A organização inclui um diretório raiz com cinco subdiretórios: add, sub, main, scripts e um diretório de saída. O sistema de build consiste em um Makefile principal, quatro scripts no diretório scripts, e Makefiles individuais em cada subdiretório de módulo. Os prgoramas em C estão localizados em add/add.c, sub/sub.c e main/main.c.
Implemnetação dos Makefiles
Makefile Raiz
.PHONY: all clean
CMD_MAKE := make
SRC_ROOT := $(or $(KBUILD_SRC), $(CURDIR))
export SRC_ROOT
# Ferramentas de compilação
ASM_PROC = $(CROSS_COMPILE)as
LINK_TOOL = $(CROSS_COMPILE)ld
CC_TOOL = $(CROSS_COMPILE)gcc
CPP_TOOL = $(CC_TOOL) -E
AR_TOOL = $(CROSS_COMPILE)ar
NM_TOOL = $(CROSS_COMPILE)nm
export ASM_PROC LINK_TOOL CC_TOOL CPP_TOOL AR_TOOL NM_TOOL
include $(SRC_ROOT)/scripts/Kbuild.inc
all: complete_target
MODULE_DIRS := add sub main
.PHONY: $(MODULE_DIRS)
OUTPUT_DIRS := $(MODULE_DIRS)
.PHONY: $(OUTPUT_DIRS)
complete_target: $(MODULE_DIRS)
$(CC_TOOL) -o $@ add/built-in.o sub/built-in.o main/built-in.o
$(MODULE_DIRS):
$(CMD_MAKE) $(build)=$@
CLEAN_LIST := $(addprefix purge_, $(OUTPUT_DIRS))
.PHONY: $(CLEAN_LIST) clean
$(CLEAN_LIST):
$(CMD_MAKE) $(clean)=$(patsubst purge_%,%, $@)
clean: $(CLEAN_LIST)
rm -f complete_target
clean := -f scripts/Makefile.clean obj
.PHONY: all clean
Script de Compilação (scripts/Makefile.build)
# Processo de construção
SOURCE_PATH := $(OBJ_DIR)
.PHONY: compile_all
compile_all:
include scripts/Kbuild.inc
DIR_TARGET := $(if $(filter /%, $(SOURCE_PATH)), $(SOURCE_PATH), $(SRC_ROOT)/$(SOURCE_PATH))
BUILD_FILE := $(if $(wildcard $(DIR_TARGET)/Kbuild), $(DIR_TARGET)/Kbuild, $(DIR_TARGET)/Makefile)
include $(BUILD_FILE)
include scripts/Makefile.lib
ifneq ($(strip $(obj-y)),)
OUTPUT_OBJ := $(OBJ_DIR)/built-in.o
endif
compile_all: $(OUTPUT_OBJ)
CMD_LINK_OBJECT = $(if $(strip $(obj-y)), \
$(LINK_TOOL) $(ld_flags) -r -o $@ $(filter $(obj-y), $^))
$(OUTPUT_OBJ): $(obj-y)
$(call if_changed, link_object)
CMD_COMPILE_C = $(CC_TOOL) $(c_flags) -c -o $@ $<
define RULE_COMPILE_C
$(CMD_COMPILE_C)
endef
$(OBJ_DIR)/%.o: $(SOURCE_PATH)/%.c
$(call if_changed_rule, compile_c)
.PHONY: FORCE
FORCE:
.PHONY: compile_all
Definições de Funções (scripts/Kbuild.inc)
build := -f scripts/Makefile.build obj
if_changed = $(CMD_$(1))
if_changed_rule = $(RULE_$(1))
Opções de Compilação (scripts/Makefile.lib)
c_flags =
ld_flags = $(LDFLAGS) $(ldflags-y)
obj-y := $(patsubst %/, %/built-in.o, $(obj-y))
obj-y := $(addprefix $(OBJ_DIR)/, $(obj-y))
Script de Limpeza (scripts/Makefile.clean)
# Rotina de limpeza
CLEAN_SRC := $(OBJ_DIR)
.PHONY: perform_clean
perform_clean:
perform_clean:
rm -f $(CLEAN_SRC)/*.o
Makefile do Módulo Add (add/Makefile)
obj-y += add.o
Limitações do Projeto Atual
- O sistema não implementa geração automática de dependências entre arquivos.
- Não há suporte para compilar em um diretório de saída separado do código-fonte.