LINUX.ORG.RU

GNU make: сборка нескольких одинаковых целей

 ,


1

2

Никак не получается создать правило средствами gnu make, которое собирало бы несколько целей со схожими именами.

Например, пусть есть проект с такой структурой (на самом деле файлов намного больше, но отдельные правила под каждый создавать не хочется)

exe
    /obj
src
    /lib/lib.c
    /tests
        /test-1.c
        /test-2.c
makefile

подкаталоги «exe» пока пустые, о них позже.

имеющиеся файлы:

// lib.c 
#include <stdio.h>

void print_nothing() {
    printf("nothing ");
}

// test-1.c 
#include <stdio.h>
void print_nothing();

int main() {
    print_nothing();
    printf("to say\n");
    return 0;
}
// test-2.c 
#include <stdio.h>
void print_nothing();

int main() {
    print_nothing();
    printf("to say again\n");
    return 0;
}

и собственно сам makefile:

$ cat makefile 
#!/usr/bin/make
MAKEFLAGS = -j 1
CC = gcc

#DOBJ = exe/obj/
#DMOD = exe/mod/
#DEXE = exe/
DOBJ = src/tests/
DMOD = src/tests/
DEXE = src/tests/

MKDIRS  = $(DOBJ) $(DMOD) $(DEXE)

#auxiliary variables
COTEXT = "Compile $(<F)"
LITEXT = "Assemble $@"

DTESTS=src/tests/
TESTS=$(basename $(notdir $(wildcard $(DTESTS)/*.c)))
TESTSOBJ=$(addsuffix .o, $(TESTS))
$(info TESTS: $(TESTS))
$(info TESTSOBJ: $(TESTSOBJ))

all: $(DEXE)$(TESTS)
#building rules
$(DEXE)$(TESTS): %: $(MKDIRS) %.o
        @echo $(LITEXT)
        @$(CC) $(DOBJ)*.o -o $@

#compiling rules
$(DOBJ)lib.o: src/lib/lib.c
        @echo $(COTEXT)
        @$(CC) -c $< -o $@

$(DOBJ)$(TESTSOBJ): %.o: %.c \
        $(DOBJ)lib.o
        @echo $(COTEXT)
        @$(CC) -c $< -o $@

– этот попытка использовать Static Pattern Rules.

Но в результате собирается только test-2:

$ make
TESTS: test-2 test-1
TESTSOBJ: test-2.o test-1.o
Compile lib.c
Compile test-2.c
Assemble src/tests/test-2
make: *** No rule to make target 'test-1.c', needed by 'test-1.o'.  Stop.

Уже пару дней не могу сообразить как это сделать, а создавать под сотню правил очень не хочется.

А вот теперь о подкаталогах в exe: в makefile есть закоментированные строки

#DOBJ = exe/obj/
#DMOD = exe/mod/
#DEXE = exe/

и их предплагается использовать, взамен того, что используется ниже. То есть на самом деле всё ещё и усложняется тем, что цели объектных файлов и исполняемых файлов предполагается хранить отдельно от исходников.

★★★★★

foreach здесь непонятно как применить для описания цели, а автоматические переменные действуют только внутри «рецептов» (об этом пишут в документации).

Может кто видел проект с реализацией похожих вещей для сборки целей в цикле?

grem ★★★★★
() автор топика
Ответ на: комментарий от DELIRIUM

Не хочу, мне подправить хочется уже готовый make одного проекта. Кто-то cmake для него с нуля пишет, но что-то пока ещё не всё зависимости описаны для сборки и выглядит это всё ещё страшнее.

grem ★★★★★
() автор топика

TESTS=$(basename $(notdir $(wildcard $(DTESTS)/*.c)))
TESTSOBJ=$(addsuffix .o, $(TESTS))
...
$(DOBJ)$(TESTSOBJ): ...

Может заменить последнее на что-то вида $(addprefix $(DOBJ) $(TESTSOBJ))? И остальное в том же духе

DllMain
()
Последнее исправление: DllMain (всего исправлений: 1)
Ответ на: комментарий от grem

Внутри foreach генерируются имена target-ов, потом их в зависимость all(к примеру) запихать. А правило для сборки обычное шаблонное. Но вообще, я не слишком понял, чего нужно добиться

DllMain
()

сборка нескольких одинаковых целей

Это неправильный заголовок.

Во-первых, ты хочешь собирать объектники отдельно от исходников. Что непострая задача для make в общем случае. И в большинстве случаев ненужная. Зачем тебе это надо? Напиши install(_tests) и clean(_tests), которые положит объектники туда, куда тебе хочется, и почистит за собой.

Во-вторых, ты не понимаешь, что используешь. Применяешь инструмент (Static Pattern Rules) ради применения инструмента. При этом не понимаешь элементарного - что будет в результате конкатенации более элементарного инструмента $(DEXE)$(TESTS).

Вывод. Тебе нельзя помочь, потому что у тебя нет необходимой базы. Ты даже не можешь объяснить, что ты хочешь получить. Я бы написал примерно как можно решить твою задачу, которую ты не можешь объяснить, но смысла в этом мало, так как ты скорее всего не поймешь.

anonymous
()
Ответ на: комментарий от anonymous

Я уже вообще подумываю, а нужны ли мне здесь вообще промежуточные объектники кроме lib.o?

будет в результате конкатенации более элементарного инструмента $(DEXE)$(TESTS)

Тут я в примере, действительно накосячил при переносе с более большого makefile, так как должен использоваться $(addprefix ), как указали выше и я его почему-то в примере не использовал.

Для другого примера даже добился (только путь подменить не могу никак), чтобы в одном случае он исполняемой цели «test-2», например, требовал только «test-2.o» из списка объектников. Но вот дальше ничего не вышло.

Задача в том, чтобы не писать правило для каждой цели в директории отдельно, учитывая, что имена у целей отличаются только номером (но это вообще не важно, главное, что исходники в одном каталоге): т.е. если есть список файлов /test/test-1.c, /test/test-2.c, /test/test-3.c b и т.д., то хочется описать шаблонное правило для цели сборки исполняемых файлов exe/test-1, exe/test-2 и т.д. такое, чтобы для каждого элемента из списка целей «exe/test-N» брался только соответствующий элемент из «/test/test-N.c».

Но мне уже кажется, что проще либо вручную их размножить, либо опакетить наконец собственную систему сборки от того разработчика, которую он использует.

grem ★★★★★
() автор топика
Последнее исправление: grem (всего исправлений: 1)
Ответ на: комментарий от grem

чтобы для каждого элемента из списка целей «exe/test-N» брался только соответствующий элемент из «/test/test-N.c».

Набросок (форум на для кодирования кода)

TEST_SRCS=$(wildcard test/*.c)
TEST_EXES=$(patsubst test/%.c, exe/%, $(TEST_SRCS))
test: $(TEST_EXES)

# настраиваем флаги компилера
$(TEST_EXES): CFLAGS = -Obest -march=aborigine -flto -DTEST
$(TEST_EXES): LDFLAGS = -flto
$(TEST_EXES): LIBS = $(pkg-config --libs mybestlib)

$(TEST_EXES): %: %.o
  $(CC) -o $@ $(LDFLAGS) $(LIBS)

exe/%.o: test/%.c
  $(CC) $(CFLAGS) -x c -c -o $@ $<
anonymous
()

К сожалению Мэйк подходит только для сборки такого же как и он сам устаревшего дерьма, типа Си и Си++ и прочего. А я об этом ничего не знаю. Прости, помоч не могу.

anonymous
()
MAKEFLAGS = -j 1
CC = gcc

DOBJ = exe/obj/
DMOD = exe/mod/
DEXE = exe/

MKDIRS  = $(DOBJ) $(DMOD) $(DEXE)

#auxiliary variables
COTEXT = "Compile $(<F)"
LITEXT = "Assemble $@"

DTESTS=src/tests/
TESTS=$(basename $(notdir $(wildcard $(DTESTS)/*.c)))
TESTSOBJ=$(addsuffix .o, $(TESTS))
$(info TESTS: $(TESTS))
$(info TESTSOBJ: $(TESTSOBJ))

all: $(addprefix $(DEXE),$(TESTS))
#building rules
$(addprefix $(DEXE),$(TESTS)): $(DEXE)%: $(DOBJ)%.o $(DOBJ)lib.o | $(MKDIRS)
	@echo $(LITEXT)
	@$(CC) $^ -o $@

#compiling rules
$(DOBJ)lib.o: src/lib/lib.c
	@echo $(COTEXT)
	@$(CC) -c $< -o $@

$(addprefix $(DOBJ),$(TESTSOBJ)): $(DOBJ)%.o: $(DTESTS)%.c \
	$(DOBJ)lib.o
	@echo $(COTEXT)
	@$(CC) -c $< -o $@

$(MKDIRS):
	mkdir -p $@
$ make
TESTS: test-2 test-1
TESTSOBJ: test-2.o test-1.o
XXX: exe/test-2 exe/test-1
Compile lib.c
Compile test-2.c
mkdir -p exe/mod/
Assemble exe/test-2
Compile test-1.c
Assemble exe/test-1
xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)
Ответ на: комментарий от xaizek

O_o

Спасибо, только $(MKDIRS) в all: перетащил (отступы сделал табами), а то почему-то не срабатывало, ругалось

Compile lib.c
Assembler messages:
Fatal error: can't create exe/obj/lib.o: No such file or directory
make: *** [makefile:30: exe/obj/lib.o] Error 1

если каталоги уже существуют, то не ругается.

grem ★★★★★
() автор топика
Ответ на: комментарий от grem

Логично, там же эти каталоги тоже используются. Если ещё будет так ругаться, то надо вместо all: указать $(MKDIRS) в каждой из целей, которая их использует. Так как порядок сборки зависимостей цели не определён, мне кажется, что $(MKDIRS) может быть вызвана в конце для $(all).

xaizek ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.