2013-06-06 3 views
-1

Я пишу часть программного обеспечения, которое использует 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.

Так что теперь я могу с радостью построить все объекты индивидуально, если я передам имя файла, но я думаю, что мне все еще требуется разрешение зависимостей, так что мне не нужно писать правило для каждого файла.

ответ

0

Это может занять несколько итераций.

Первая проблема заключается в том, что у вас есть цель, build/OBJ/VGA.o и никакое соответствующее правило. Правило

%.o: %.cpp Makefile 
    ... 

не подходит; он может построить build/OBJ/VGA.o от build/OBJ/VGA.cpp, но нет такого исходного файла.

Так что для первого шага, если исходный файл src/whatever/VGA.cpp, попробуйте это правило:

build/OBJ/%.o: src/whatever/%.cpp 
    ... 

и сказать нам результат.

EDIT:

Хорошо, теперь попробуй это:

build/OBJ/%.o: src/%.cpp 
    ... 
+0

Я редактировал свой пост, чтобы включить неполную решение, мы надеемся, что это было правильным решением. Я рад видеть, что правило работает, однако я сбиваю с толку, что правило работает с файлами в каталоге build/OBJ ** и ** во всех его подпапках. Если% работает в качестве подстановочного знака, почему ** ** ** **. ** файл не был найден в моем предыдущем правиле? – xClueless

Смежные вопросы