Как обновить / обновить переменную в Makefile? - PullRequest
0 голосов
/ 15 февраля 2020

У меня есть этот 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)

После компиляции (делая make в каталогах boot и kernel) должны быть файлы с расширением .o, однако OBJ_FILES пуст. Только после вызова make снова OBJ_FILES содержит пути к файлам .o, которые необходимы для связи. Поэтому мой вопрос заключается в том, как мне обновить OBJ_FILES после компиляции в каталогах boot и kernel, потому что OBJ_FILES не обновляет / refre sh.

Ответы [ 2 ]

0 голосов
/ 17 февраля 2020

Поэтому мой вопрос: как мне обновить OBJ_FILES после компиляции в каталогах boot и kernel, потому что OBJ_FILES не обновляет / не обновляет sh.

* Переменная 1007 * не изменит свое значение, как только make начнет выполнять правила.

См. 3.7 Как make Читает Makefile для получения полной информации:

GNU make выполняет свою работу в два этапа. На первом этапе он считывает все make-файлы, включая make-файлы и т. Д. c. и интернализует все переменные и их значения, а также неявные и явные правила, и строит граф зависимостей всех целей и их предпосылок. На втором этапе make использует эти интернализованные данные, чтобы определить, какие цели необходимо обновить, и запустите рецепты, необходимые для их обновления.

Важно понимать этот двухэтапный подход, поскольку он напрямую влияет на то, как происходит расширение переменной и функции; это часто вызывает путаницу при написании make-файлов.

Вместо этого вы можете перезапустить 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
0 голосов
/ 16 февраля 2020

Допустим, у вас есть следующая структура:

.
|-- 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 s содержит

> 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

Расширяется при использовании переменной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...