我正在编写一个利用Makefile进行编译的软件,最初我为每个文件设置了一个规则,但是每当我添加一个新文件时,这被证明太麻烦了。为了尝试自动化这个过程,我做了一些研究,并了解到GCC / G ++可以使用-M标志自动构建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
CC=@$(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),$@)
./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 $@"
$(CC) $(CFLAGS) -MMD -MP -MF $(subst $(SrcDIR),$(DepDIR),$@) -o $(subst $(SrcDIR), $(ObjDIR),$@)
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..."
-@rm -R $(BuildDIR) ./isodir
-@$(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),$@) -o $(subst $(SrcDIR), $(ObjDIR),$@)
适用于每个.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
这是我在这里的第一篇文章,所以对我的问题的反馈表示赞赏:)
希望我能解决这个问题并重新开发我的代码。
编辑:
@Beta提供的规则没有问题,我的所有Object文件都成功构建并输出到正确的位置。此规则甚至选择了build/OBJ/Drivers/IO-Ports/CMOS.o
和build/OBJ/Drivers/PS2.o
。
所以现在我可以愉快地单独构建所有对象,如果我传递文件名但是我认为我仍然需要依赖性解析,这样我就不必为每个文件编写规则。
答案 0 :(得分: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
...
告诉我们结果。
修改
好,现在试试这个:
build/OBJ/%.o: src/%.cpp
...