Makefile Make:如何自动生成规则以构建目标?

Makefile Make:如何自动生成规则以构建目标?,makefile,gnu-make,Makefile,Gnu Make,这个问题有点模糊,因为我不完全确定在这么短的总结中问我想达到什么目的的最佳方式 最好的解释是,这就是我目前拥有的 common.mk DESTDIR = ../../install/ CC = gcc CFLAGS = -fPIC -Wall -Wextra -O2 -g -I. LDFLAGS = -shared RM = rm -f MAKEDIR = mkdir -p 工具.mk DESTDIR = ../../install/ CC = gcc CFLAGS = -fPIC -Wa

这个问题有点模糊,因为我不完全确定在这么短的总结中问我想达到什么目的的最佳方式

最好的解释是,这就是我目前拥有的

common.mk

DESTDIR = ../../install/
CC = gcc
CFLAGS = -fPIC -Wall -Wextra -O2 -g -I.
LDFLAGS = -shared
RM = rm -f
MAKEDIR = mkdir -p
工具.mk

DESTDIR = ../../install/
CC = gcc
CFLAGS = -fPIC -Wall -Wextra -O2 -g -I.
LDFLAGS = -shared
RM = rm -f
MAKEDIR = mkdir -p
Makefile

include ../../builder/tools.mk
include ../../builder/common.mk

TEST_RUNNERS = test_foo test_bar

test_foo_TESTS = tests/test_foo.c
test_foo_SOURCES = foo.c

test_bar_TESTS = tests/test_bar.c
test_bar_SOURCES = bar.c


# Gather lists of ALL sources and objects required to build test_foo
test_foo_ALL_SOURCES = $(test_foo_TESTS) $(test_foo_SOURCES)
test_foo_ALL_OBJECTS = $(test_foo_ALL_SOURCES:.c=.o)

# Compile All the sources required for test_foo
$(test_foo_ALL_SOURCES:.c=.d):%.d:%.c
    $(CC) $(CFLAGS) -MM $< >$@
include $(test_foo_ALL_SOURCES:.c=.d)

# Build test_foo and clean up temporary build files
test_foo: $(test_foo_ALL_OBJECTS)
    $(CC) -L$(DESTDIR) -o $(strip $(DESTDIR))$(strip $@) $^
    -${RM} ${test_foo_ALL_OBJECTS} ${test_foo_ALL_SOURCES:.c=.d}


# Gather lists of ALL sources and objects required to build test_bar
test_bar_ALL_SOURCES = $(test_bar_TESTS) $(test_bar_SOURCES)
test_bar_ALL_OBJECTS = $(test_bar_ALL_SOURCES:.c=.o)

# Compile All the sources required for test_bar
$(test_bar_ALL_SOURCES:.c=.d):%.d:%.c
    $(CC) $(CFLAGS) -MM $< >$@
include $(test_bar_ALL_SOURCES:.c=.d)

# Build test_bar and clean up temporary build files
test_bar: $(test_bar_ALL_OBJECTS)
    $(CC) -L$(DESTDIR) -o $(strip $(DESTDIR))$(strip $@) $^
    -${RM} ${test_bar_ALL_OBJECTS} ${test_bar_ALL_SOURCES:.c=.d}
因此,对于列表中指定的每个测试运行程序,必须提供源列表(测试中的代码)和测试列表(单元测试源)

test_foo_TESTS
test_foo_SOURCES
我一直在玩foreach,但这不是正确的方法,我不完全确定我需要做什么来实现我的目标,所以在玩了几个小时后,我想我应该试着问你们中的一些人,因为这里有一些非常聪明的人,希望他们能帮助我

我玩的另一个想法是创建我可以调用的模板来生成这些规则:

$(foreach runner,$(TEST_RUNNERS),$(eval $(call COMPILE_ALL_TEST_RUNNER_SOURCES, runner)))
$(foreach runner,$(TEST_RUNNERS),$(eval $(call MAKE_TEST_RUNNER_TEMPLATE, runner)))

 define COMPILE_ALL_TEST_RUNNER_SOURCES
 $($(1)_ALL_SOURCES:.c=.d):%.d:%.c
     $(CC) $(CFLAGS) -MM $< >$@
 include $($(1)_ALL_SOURCES:.c=.d)
 endef


 define MAKE_TEST_RUNNER_TEMPLATE
 $(1): $($(1)_ALL_OBJECTS)
     $(CC) -L$(DESTDIR) -o $(strip $(DESTDIR))$(strip $@) $^
     -${RM} ${$(1)_ALL_OBJECTS} ${$(1)_ALL_SOURCES:.c=.d}
 endef
$(foreach runner,$(TEST\u runner),$(eval$(调用COMPILE\u ALL\u TEST\u runner\u SOURCES,runner)))
$(foreach runner,$(TEST\u runner),$(eval$(调用MAKE\u TEST\u runner\u TEMPLATE,runner)))
定义编译\u所有\u测试\u运行程序\u源
$($(1)\所有来源:.c=.d:%.d:%.c
$(CC)$(CFLAGS)-MM$<>$@
包括$($(1)\所有来源:.c=.d)
恩德夫
定义MAKE_TEST_RUNNER_模板
$(1):$($(1)\所有对象)
$(CC)-L$(DESTDIR)-o$(strip$(DESTDIR))$(strip$@)$^
-${RM}${$(1){u所有对象}${$(1){u所有源:.c=.d}
恩德夫

如果您愿意为每个目标多添加一行:

test_foo_TESTS = tests/test_foo.c
test_foo_SOURCES = foo.c
test_foo_ALL_OBJECTS := tests/test_foo.o foo.o
然后,两个模式规则可以处理所有其他规则:

%.o: %.c
    $(CC) $(CFLAGS) -MMD -c $< -o $@

-include *.d tests/*.d

.PHONY: $(TEST_RUNNERS)

$(TEST_RUNNERS): test_% : $(DESTDIR)test_%

$(DESTDIR)test_%:
    $(CC) -L$(DESTDIR) -o $@ $^
%.o:%.c
$(CC)$(CFLAGS)-MMD-c$<-o$@
-包括*.d测试/*.d
.PHONY:$(测试跑步者)
$(测试运行者):测试%:$(DESTDIR)测试%
$(DESTDIR)测试百分比:
$(CC)-L$(DESTDIR)-o$@$^
(相信我,这种依赖关系处理方法比您以前的要好得多。有关详细说明,请参阅。)

如果您不喜欢为每个目标写三行,请注意前两行实际上没有用于任何用途,可以省略


如果您喜欢前两个,但确实不喜欢第三个,是的,您可以自动构建对象列表的过程,但这不值得为这个问题付出努力。

如果您愿意为每个目标多添加一行:

test_foo_TESTS = tests/test_foo.c
test_foo_SOURCES = foo.c
test_foo_ALL_OBJECTS := tests/test_foo.o foo.o
然后,两个模式规则可以处理所有其他规则:

%.o: %.c
    $(CC) $(CFLAGS) -MMD -c $< -o $@

-include *.d tests/*.d

.PHONY: $(TEST_RUNNERS)

$(TEST_RUNNERS): test_% : $(DESTDIR)test_%

$(DESTDIR)test_%:
    $(CC) -L$(DESTDIR) -o $@ $^
%.o:%.c
$(CC)$(CFLAGS)-MMD-c$<-o$@
-包括*.d测试/*.d
.PHONY:$(测试跑步者)
$(测试运行者):测试%:$(DESTDIR)测试%
$(DESTDIR)测试百分比:
$(CC)-L$(DESTDIR)-o$@$^
(相信我,这种依赖关系处理方法比您以前的要好得多。有关详细说明,请参阅。)

如果您不喜欢为每个目标写三行,请注意前两行实际上没有用于任何用途,可以省略


如果你喜欢前两个,而真的不喜欢第三个,是的,你可以自动构建对象列表的过程,但这不值得为这个问题付出努力。

在花多一点时间阅读Make手册后,我发现了这个非常有用的页面

它提供了一些非常有用的信息,告诉我如何准确地构建我的Makefile。如果有人感兴趣,我将以此作为我前进的基础

TEST_RUNNERS = test_foo test_bar

test_foo_TESTS = tests/test_foo.c
test_foo_SOURCES = foo.c

test_bar_TESTS = tests/test_bar.c
test_bar_SOURCES = bar.c

.PHONY: test
test: unittest

#
# Template to create rules for each TEST_RUNNER defined within TEST_RUNNERS
#
# $(1) is the name of the test runner
#
define test_TEST_RUNNER_template
THE_$(1)_SOURCES = $$($(1)_TESTS)
.PHONY: unittest unittest_$(1)
unittest: unittest_$(1)
unittest_$(1):
    @echo "?(1)=" $(1) "?@=" $$@ " THE_$(1)_SOURCES="  $$(THE_$(1)_SOURCES)
endef

# Create a rule for all TEST_RUNNERS when "make test" is invoked...
$(foreach runner,$(TEST_RUNNERS),$(eval $(call test_TEST_RUNNER_template,$(runner))))

在花了更多的时间阅读Make手册之后,我发现了这个非常有用的页面

它提供了一些非常有用的信息,告诉我如何准确地构建我的Makefile。如果有人感兴趣,我将以此作为我前进的基础

TEST_RUNNERS = test_foo test_bar

test_foo_TESTS = tests/test_foo.c
test_foo_SOURCES = foo.c

test_bar_TESTS = tests/test_bar.c
test_bar_SOURCES = bar.c

.PHONY: test
test: unittest

#
# Template to create rules for each TEST_RUNNER defined within TEST_RUNNERS
#
# $(1) is the name of the test runner
#
define test_TEST_RUNNER_template
THE_$(1)_SOURCES = $$($(1)_TESTS)
.PHONY: unittest unittest_$(1)
unittest: unittest_$(1)
unittest_$(1):
    @echo "?(1)=" $(1) "?@=" $$@ " THE_$(1)_SOURCES="  $$(THE_$(1)_SOURCES)
endef

# Create a rule for all TEST_RUNNERS when "make test" is invoked...
$(foreach runner,$(TEST_RUNNERS),$(eval $(call test_TEST_RUNNER_template,$(runner))))

如果您可以使用BSD的
make
,您可以更轻松地完成(主要是
bmake
包)。看一个例子:-我想这正是你想要的:)如果你能使用BSD的
make
你可以做得更简单(主要是
bmake
软件包)。请看一个例子:-我认为这正是您想要的:)感谢您提供的信息,尽管我希望使Makefile尽可能简单;我正在为我的项目构建一个相对简单的递归构建系统,它允许我(或其他人)轻松添加一个库,只需编写一个非常简单的Makefile即可构建新的库/二进制文件;我正在为我的项目构建一个相对简单的递归构建系统,它允许我(或其他人)轻松地添加一个库,只需编写一个非常简单的Makefile即可构建新的库/二进制文件。