如何刷新/更新Makefile中的变量?

时间:2020-02-15 19:35:58

标签: c makefile

我有这个Makefile:

CFLAGS = -ffreestanding -O2 -nostdlib -lgcc
BUILD_DIR = ../build
BIN = $(BUILD_DIR)/os.bin
LINKER_SCRIPT = linker.ld
OBJ_FILES := $(shell find $(BUILD_DIR) -iname '*.o')

.PHONY: all

all:
    @make -C boot
    @make -C kernel
    $(CC) -T $(LINKER_SCRIPT) -o $(BIN) $(CFLAGS) $(OBJ_FILES)

编译后(在引导目录和内核目录中进行制作),应该具有扩展名为.o的文件,但是OBJ_FILES为空。只有在再次调用make之后,OBJ_FILES才包含链接所需的.o文件路径。因此,我的问题是在引导目录和内核目录中进行编译后如何更新OBJ_FILES,因为OBJ_FILES不会更新/刷新。

2 个答案:

答案 0 :(得分:0)

假设您具有以下结构:

.
|-- Makefile
|-- boot
|   |-- Makefile
|   |-- boot.c
|   `-- boot.h
|-- kernel
|   |-- Makefile
|   |-- kernel.c
|   `-- kernel.h
`-- main.c

您的Makefile如下

location = $(CURDIR)

OBJ_FILES = $(shell find $(location) -name '*.o')

all: make_common
        gcc -o main main.c $(OBJ_FILES)

make_common:
        @make -C boot
        @make -C kernel

clean:
        -rm boot/boot.o
        -rm kernel/kernel.o

您的源代码非常简单:

> cat boot/boot.h
int boot();

> cat boot/boot.c
int boot() {
  return 1;
}

> cat kernel/kernel.h
int kernel();

> cat kernel/kernel.c
int kernel() {
  return 2;
}

> cat main.c
#include "boot/boot.h"
#include "kernel/kernel.h"

int main() {
  int result = boot() + kernel();
  return 0;
}

“内部” Makefile包含

> cat boot/Makefile
all:
    gcc -c boot.c

> cat kernel/Makefile
all:
    gcc -c kernel.c

您将得到想要的东西

> make clean
rm boot/boot.o
rm: boot/boot.o: No such file or directory
make: [clean] Error 1 (ignored)
rm kernel/kernel.o
rm: kernel/kernel.o: No such file or directory
make: [clean] Error 1 (ignored)
> make
gcc -c boot.c
gcc -c kernel.c
gcc -o main main.c ..../boot/boot.o ..../kernel/kernel.o

VAR = val

使用变量时扩展。

答案 1 :(得分:0)

所以我的问题是在引导目录和内核目录中编译后如何更新OBJ_FILES,因为OBJ_FILES不会更新/刷新。

OBJ_FILES变量一旦开始执行规则就不会更改其值。

有关详细信息,请参见3.7 How make Reads a Makefile

GNU make在两个不同的阶段进行工作。在第一个阶段,它读取所有makefile,包括的makefile等,并内化所有变量及其值以及隐式和显式规则,并构建所有目标及其前提条件的依赖图。在第二阶段中,make使用此内部化数据来确定需要更新哪些目标,并运行更新目标所需的配方。

理解这种两阶段方法很重要,因为它会直接影响变量和函数扩展的发生方式;编写makefile时,这通常会引起一些混乱。

相反,您可以做的是一旦make构建内核并启动后重新启动:

all: $(BIN)

$(BIN) : $(OBJ_FILES)
    $(CC) -T $(LINKER_SCRIPT) -o $@ $(CFLAGS) $(OBJ_FILES)

Makefile :
    @$(MAKE) -C boot
    @$(MAKE) -C kernel
    touch $@ # <---- Causes the Makefile to be re-read.

.PHONY: all
相关问题