【问题标题】:Make: How can I auto generate rules to build targets?Make:如何自动生成规则来构建目标?
【发布时间】:2018-02-14 01:15:23
【问题描述】:

这个问题有点含糊,因为我不完全确定在如此简短的摘要中问我想要实现什么的最佳方式。

为了更好地解释它,这就是我目前所拥有的......

common.mk

DESTDIR = ../../install/

tools.mk

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

生成文件

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_RUNNERS = test_foo test_bar

因此,对于列表中指定的每个 TEST_RUNNER,必须提供 SOURCES 列表(被测代码)和 TESTS 列表(单元测试源)...

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

【问题讨论】:

标签: makefile gnu-make


【解决方案1】:

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

https://www.gnu.org/software/make/manual/html_node/Eval-Function.html

其中有一些非常有用的信息,告诉我如何准确地构建我想要的 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))))

【讨论】:

    【解决方案2】:

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

    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 $@ $^
    

    (相信我,这种处理依赖关系的方法比您使用的方法要好得多。有关详细说明,请参阅here。)

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

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

    【讨论】:

    • 感谢您提供这些信息,尽管我想让 Makefile 尽可能简单;我正在为我的项目构建一个相对简单的递归构建系统,它允许我(或其他人)轻松添加库,并且只需要编写一个非常简单的 Makefile 就可以构建新的库/二进制文件。
    猜你喜欢
    • 1970-01-01
    • 2020-02-07
    • 1970-01-01
    • 2015-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-05
    相关资源
    最近更新 更多