Я пишу часть программного обеспечения, которое использует Makefile для компиляции, изначально у меня была настройка правил для каждого файла, однако это оказалось слишком громоздким, когда я добавлял новый файл. Чтобы попытаться автоматизировать процесс, я сделал некоторые исследования и узнал, что GCC/G ++ может автоматически создавать правила Makefile с помощью флага -M.Автоматическое разрешение зависимостей с использованием GNU Makefile
Есть много примеров этого делается с простой структурой каталогов, однако моя идеальная структура каталогов выглядит следующим образом:
src/
kernel.hpp kernel.cpp
Types/
String.cpp
String.hpp
Drivers/IO-Ports/
CMOS.cpp
CMOS.hpp
...
build/
DEPS/
kernel.d
Types/String.d
...
OBJ/
kernel.o
Types/String.o
...
Мой текущий Makefile:
CCHOME=/home/dan/opt/cross/bin
[email protected]$(CCHOME)/i586-elf-g++
CFLAGS=-ffreestanding -O2 -Wextra -Wall -fno-exceptions -fno-rtti
KernelName=CPlusKern
QEMU=qemu-system-x86_64 -monitor stdio
SrcDIR=src
SourceDIRS:=$(shell find $(SrcDIR) -type d)
SrcFILES=$(shell find $(SrcDIR) -type f -name *.cpp)
HdrFILES=$(shell find $(SrcDIR) -type f -name *.hpp)
DepDIR=$(BuildDIR)/DEPS
DepFILES0=$(subst $(SrcDIR), $(DepDIR),$(SrcFILES))
DepFILES=$(subst .cpp,.d,$(DepFILES0))
ObjDIR=$(BuildDIR)/OBJ
ObjDIRS=$(subst $(SrcDIR),$(ObjDIR),$(SourceDIRS))
ObjFILES0=$(subst $(SrcDIR), $(ObjDIR),$(SrcFILES))
ObjFILES=$(subst .cpp,.o,$(ObjFILES0))
BuildDIR=build
BuildDIRS=$(BuildDIR) $(ObjDIR) $(DepDIR)
all: assemble compile run
image: assemble compile build-image run-image
debug:
@echo "BuildDIRS: " $(BuildDIRS)
@echo "DepFiles: " $(DepFILES)
@echo "SrcFiles: " $(SrcFILES)
@echo "ObjFiles: " $(ObjFILES)
./src/kernel.o: ./src/kernel.cpp
@echo $(CC) $(CFLAGS) -MMD -MP -MF $< -o $(subst $(SrcDIR), $(ObjDIR),[email protected])
./src/kernel.cpp:
dir:
@echo "Making Build Dirs..."
@-mkdir -p $(BuildDIRS)
compile: dir $(ObjFILES)
# @echo "Compiling Source Files: " $(SrcFILES)
assemble: dir boot.o
@echo "Assembling Core Files..."
boot.o: $(SrcDIR)/boot.s
@$(CCHOME)/i586-elf-as $(SrcDIR)/boot.s -o $(ObjDIR)/boot.o
build: %.o
echo "Building Kernel Binary..."
@$(CC) -T linker.ld -o $(KernelName).bin -ffreestanding -O2 -nostdlib $(SrcFILES)-lgcc
build-image: build
@echo "Building Kernel Image..."
@cp $(KernelName).bin isodir/boot/$(KernelName).bin
@Scripts/MakeGrub.sh $(KernelName) isodir/boot/grub
grub-mkrescue -o $(KernelName).iso isodir
%.o: %.cpp Makefile
@echo "Building Object [email protected]"
$(CC) $(CFLAGS) -MMD -MP -MF $(subst $(SrcDIR),$(DepDIR),[email protected]) -o $(subst $(SrcDIR), $(ObjDIR),[email protected])
run:
@echo "Starting QEMU"
@$(QEMU) -kernel $(KernelName).bin
run-image:
@echo "Starting QEMU"
@$(QEMU) -bios OVMF.fd -cdrom $(KernelName).iso
clean:
@echo "Cleaning Build Directories..."
[email protected] -R $(BuildDIR) ./isodir
[email protected]$(RM) $(KernelName).bin $(KernelName).iso
Я думал, что это может сделать т. е. совершает ошибку:
make: *** No rule to make target `build/OBJ/VGA.o', needed by `compile'. Stop.
Я не могу сдержать мой, как сделать правило:
%.o: %.cpp Makefile
$(CC) $(CFLAGS) -MMD -MP -MF $(subst $(SrcDIR),$(DepDIR),[email protected]) -o $(subst $(SrcDIR), $(ObjDIR),[email protected])
относится ко всем файлам .cpp. Насколько я знаю, подстановочные знаки не могут использоваться в определениях правил.
Я не уверен, что это помогает, но путь/имя каждого исходного файла сохраняется в переменной $ (SrcFILES).
Просто чтобы прояснить, вот это расширенная версия вышеприведенного правила:
/home/dan/opt/cross/bin/i586-elf-g++ -ffreestanding -O2 -Wextra -Wall -fno-exceptions -fno-rtti -MMD -MP -MF src/kernel.cpp -o build/OBJ/kernel.o
И файл генерируется зависимость для этого экземпляра:
kernel.o: src/kernel.cpp src/kernel.hpp src/Globals.hpp \
src/VGATerminal.hpp src/Types/String.hpp src/Types/../Globals.hpp \
src/VGA.hpp src/IO/Read.hpp src/IO/Write.hpp \
src/Drivers/IO-Ports/CMOS.hpp src/Drivers/IO-Ports/../../IO/Read.hpp \
src/Drivers/IO-Ports/../../IO/Write.hpp
Это мой первый пост здесь, так что обратная связь по мой вопрос приветствуется :)
Надеюсь, я смогу избавиться от этого пути и вернуться к разработке моего кода.
EDIT: Правило, предоставленное @Beta, работало без проблем. Все мои файлы объектов успешно создаются и выводятся в нужном месте. Это правило даже подняло build/OBJ/Drivers/IO-Ports/CMOS.o
и build/OBJ/Drivers/PS2.o
.
Так что теперь я могу с радостью построить все объекты индивидуально, если я передам имя файла, но я думаю, что мне все еще требуется разрешение зависимостей, так что мне не нужно писать правило для каждого файла.
Я редактировал свой пост, чтобы включить неполную решение, мы надеемся, что это было правильным решением. Я рад видеть, что правило работает, однако я сбиваю с толку, что правило работает с файлами в каталоге build/OBJ ** и ** во всех его подпапках. Если% работает в качестве подстановочного знака, почему ** ** ** **. ** файл не был найден в моем предыдущем правиле? – xClueless