Мой исходный код не централизован. Я хочу поместить все свои объекты в один каталог ./build/obj
.
Вот что у меня есть
ROOT=.
BUILDDIR=$(ROOT)/build
BINDIR=$(BUILDDIR)/bin
OBJDIR=$(BUILDDIR)/obj
CC=$(XCOMPILE)gcc
BIN=my-reader
CFLAGS+=\
-Wall \
-Wextra \
-Werror \
-pedantic \
-std=gnu11 \
$(INCLUDE)
SRCDIRS+=\
$(ROOT)/src \
$(ROOT)/../../folder0/folder01/src \
$(ROOT)/../../folder0/folder02/src \
$(ROOT)/../../folder1/folder03/folder04/i2c/src \
$(ROOT)/../../folder1/folder03/folder04/spi/src \
$(ROOT)/../../folder1/folder03/folder04/system/src \
$(ROOT)/../../folder2/folder03/folder04/chip-1-api/src \
$(ROOT)/../../folder2/folder03/folder04/chip-2-api/src
DEPDIRS+=\
$(SRCDIRS)
SRC+=$(shell find $(SRCDIRS) -type f -name "*\.c")
DEP+=$(shell find $(DEPDIRS) -type f -name "*\.h")
OBJ=$(patsubst %.c, $(OBJDIR)/%.o, $(SRC))
INCLUDE=$(foreach d, $(DEP),-I $(dir $d))
test:
echo $(SRC)
all: CFLAGS+=-O3
all: _all
debug: CFLAGS+=-ggdb
debug: CPPFLAGS+=-DDEBUG
debug: _all
_all: $(BINDIR) $(BINDIR)/$(BIN)
$(BINDIR)/$(BIN): $(OBJ) | $(BINDIR)
$(CC) $(CPPFLAGS) $(CFLAGS) $^ -o $@
$(BINDIR):
mkdir -p $@
$(OBJDIR)/%.o: %.c $(DEP)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
rm -rf $(BUILDDIR)
Это не совсем подходит для меня, поскольку создает некоторые файлы и каталоги, в которых находится make-файл. Я действительно хочу, чтобы все файлы .o
находились в ./build/obj
. Я провожу несколько дней, пытаясь выяснить, есть ли общий способ сделать это, но похоже, что его нет. Насколько я понимаю, для того, чтобы поместить все мои файлы в каталог ./build/obj
, мне нужно создать конкретную цель для каждого из них, что противоречит цели использования универсального make-файла. Кто-нибудь знает, возможно ли то, что я пытаюсь сделать? Я видел, как люди генерируют файлы .dep
(в которых есть настраиваемые цели), а затем включают их в make-файлы. К сожалению, я не знаю, как это сделать. Буду признателен за любую помощь в этом.
Это очень просто, используя VPATH. Во-первых, вы должны убедиться, что ваша переменная OBJS
содержит то, что вы хотите построить. В настоящее время у вас есть это:
OBJ=$(patsubst %.c, $(OBJDIR)/%.o, $(SRC))
что неверно, потому что SRC
содержит такие пути, как ./../../folder0/folder02/src/foobar.c
, что означает, что после patsubst
вы получите такие пути, как ./build/obj/./../../folder0/folder02/src/foobar.o
, что явно не то, что вам нужно. Используйте вместо этого:
OBJ = $(patsubst %.c, $(OBJDIR)/%.o, $(notdir $(SRC)))
который для каждого исходного файла somepath/foobar.c
, независимо от значения какой-то путь, даст вам ./build/obj/foobar.o
, который вам нужен.
Затем сохраните свое правило, которое строит этот .o из файла .c. Наконец, используйте VPATH, чтобы указать программе make, где искать исходные файлы, если они не существуют в локальном каталоге:
VPATH = $(SRCDIRS)
Это все, что вам нужно сделать.
Я должен отметить, что ваш INCLUDES
сломан: у вас будет огромное количество повторяющихся каталогов, добавленных с помощью -I
. Вместо этого:
INCLUDE=$(foreach d, $(DEP),-I $(dir $d))
Вам следует использовать:
INCLUDE = $(addprefix -I,$(sort $(dir $(DEP)))
Функция sort
также будет уникальной, и вам не понадобится foreach
, потому что большинство функций в make принимают несколько слов и работают со всеми из них.
В заключение, вы должны использовать :=
, а не =
, он будет более эффективным много. То, как вы это написали здесь, каждый раз, когда эти переменные расширяются, он будет повторно запускать операции find
и т. д. Вставьте echo find 1>&2;
в вызовы функций shell
перед find
и посмотрите, сколько раз он запускается ...
О, тогда действительно последнее замечание: теперь, как вы это настроили, каждый отдельный исходный файл будет перестраиваться при каждом изменении любого файла заголовка (вы добавили $(DEPS)
в качестве предварительного условия для цели $(OBJDIR)/%.o
). Может быть, вы этого и хотите, но это необычно.
Вы можете прочитать это для некоторых мыслей: make.mad-scientist.net/papers/… Если у вас есть вопросы, лучше всего задать новый вопрос по SO или обратиться за помощью по адресу [email protected], а не спрашивать здесь в комментариях.
Ok. Сделаю так в будущем.
Спасибо за комментарии. Как мне добавить точные зависимости для каждого файла вместо того, как у меня сейчас?