-1

我正在编写一个使用 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 会引发错误:

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 提供的规则没有问题,我的所有对象文件都成功构建并在正确的位置输出。这条规则甚至拿起了build/OBJ/Drivers/IO-Ports/CMOS.obuild/OBJ/Drivers/PS2.o

所以现在如果我传递文件名,我可以愉快地单独构建所有对象,但是我认为我仍然需要依赖解析,这样我就不必为每个文件编写规则。

4

1 回答 1

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
    ...
于 2013-06-07T00:20:56.687 回答