c1669888
c1669888

Reputation: 11

Iterating over a directory of files using GNU Make

My project has a directory called tests/ which contains an arbitrary number of C source files, each one is a self-contained program designed to test a library. For each of these sourcefiles, I want to create an executable of the same name in my build/ directory.

E.g. tests/test_init.c would compile to an executable file build/test_init.

Currently, my Makefile snippet looks like the following:

BUILD_DIR = build
TEST_DIR = tests

test_sources:= $(TEST_DIR)/*.c
test_executables:= $(patsubst %.c, %, $(test_sources))

.PHONY: tests

tests: $(test_executables)
    $(CC) $^ -o $@ -g

But this fails to produce to desired result. Any help would be much appreciated.

Upvotes: 0

Views: 2790

Answers (2)

David Grayson
David Grayson

Reputation: 87386

This Makefile will detect all files in test/*.c and provides tasks build_tests, run_tests, and clean_tests.

all: build_tests

define test_template

build_tests: test/$(1)

run_tests: build_tests run_test_$(1)

test/$(1) : test/$(1).c
    $$(CC) $$^ -o $$@

.PHONY : run_test_$(1)
run_test_$(1) : test/$(1)
    test/$(1)

endef

clean: clean_tests

clean_tests:
    rm -fv $(foreach test, $(tests),test/$(test))

# Auto detect the tests (any .c file in the test directory),
# and store the list of tests names.
tests := $(foreach test, $(wildcard test/*.c),$(patsubst %.c,%,$(notdir $(test))))

# Add information about each test to the Makefile.
$(foreach test, $(tests), $(eval $(call test_template,$(test))))

Note: I'm not sure how to get tabs working inside a code block in markdown, so you'll need to replace spaces with a single tab on each indented line if you copy and paste this.

Upvotes: 0

Beta
Beta

Reputation: 99094

First you need the wildcard function to find the sources:

test_sources:= $(wildcard $(TEST_DIR)/*.c)

Then the correct names for the executables:

test_executables:= $(patsubst $(TEST_DIR)/%.c, $(BUILD_DIR)/%, $(test_sources))

Then a pattern rule to build a test executable from the corresponding source:

$(BUILD_DIR)/%: $(TEST_DIR)/%.c
    $(CC) $< -o $@ -g

(A static pattern rule might be a little tidier, but it's a more advanced method.)

Finally a phony target to build all of the tests:

.PHONY: tests
tests: $(test_executables)

If you wanted Make to run all of these tests, you could make a phony pattern rule run_test_%, but that can wait for another day.

Upvotes: 2

Related Questions