2

I want to build make test with Makefile, and the test target should generate <file_name>_test executable based on the folder tests/<file_name>.c. All tests/*.c files have a main() function.

If there are 3 files under tests, then 3 executables should be generated; if there are 10 files, then 10 should be generated.

Here is the project structure:

./Makefile

./src
./src/hello.c
./src/hello.h
./src/world.c
./src/world.h
./src/(many_other_modules).c
./src/(many_other_modules).h

./tests
./tests/hello.c
./tests/world.c
./tests/(many_other_modules).c

Here is the Makefile:

CC = gcc
CFLAGS = -Wall -g
SOURCES = $(wildcard tests/*.c)

test:
    // How to gernate "hello_test" and "world_test" and other "(many_other_modules)_test" executables in Makefile?

How to write the test rule in Makefile for generating all test executables?

2
  • Nitpick: You are not "creating the executable in Makefile", you are creating the executable with GNU Make. That being said, Makefiles tend to be quite verbose and explicit, and target generation is better handled with tools like CMake or Meson. I do not know of a way to do what you want with only a Makefile. Commented Oct 29 at 11:45
  • Maybe give Testing with CMake and CTest a read. Commented Oct 29 at 11:51

3 Answers 3

5

You need a pattern rule that can create your test executables from their respective sources. For example:

%_test.o: tests/%.c
    $(COMPILE.c) %(OUTPUT_OPTION) $<

(Alternatively, just add tests to your VPATH and rename the sources with the _test suffix.)

Then your test target needs to depend on all of these:

test: %(patsubst tests/%.c,%_test,$(SOURCES))
Sign up to request clarification or add additional context in comments.

Comments

3

Assuming you have src/foo.c with a foo() function which you want to test and tests/foo.c as a test of that foo() you can do three makefiles:

In the root of the project you create a startup to process both sub directories

# /makefile

SUBDIRS = src tests

.PHONY: subdirs $(SUBDIRS)

subdirs: $(SUBDIRS)

$(SUBDIRS):
    $(MAKE) -C $@

In the /tests you can do a very short one:

# /tests/makefile

SRC=$(wildcard *.c)
TESTS=$(patsubst %.c,test_%.exe,$(SRC))

all: $(TESTS)

test_%.exe: %.c
    gcc -o $@ $< ../src/$<

And the third makefile would be in /src directory as a completely standard makefile.

1 Comment

It's better to use Make's $(COMPILE.c) than to write it (badly) with hard-coded gcc. Also, using sub-Makes is generally undesirable, especially when one sub-Make depends on another's build products. Best avoided unless absolutely essential.
1

Here is one way to do it. For the purpose of illustration the Makefile will build and clean nothing but the test programs. Evidently your real Makefile will have other targets.

The current directory contains:

$ tree .
.
├── Makefile
└── tests
    ├── a.c
    ├── b.c
    └── d.c

The Makefile is:

CC = gcc
CFLAGS = -Wall -g
TEST_SRCS = $(wildcard tests/*.c)
TEST_PROGS := $(patsubst %,%_test,$(notdir $(basename $(TEST_SRCS))))

.PHONY: test clean

test: $(TEST_PROGS)

$(TEST_PROGS): %_test : tests/%.c
    $(CC) $(CFLAGS) -o $@ $<
    
clean:
    $(RM) $(TEST_PROGS)

It runs:

$ make
gcc -Wall -g -o a_test tests/a.c
gcc -Wall -g -o b_test tests/b.c
gcc -Wall -g -o d_test tests/d.c

For documentation about patsubst see the GNU Make Manual, 8.2 Functions for String Substitution and Analysis. About notdir and basename see 8.3 Functions for File Names. About:

$(TEST_PROGS): %_test : tests/%.c

see 4.12 Static Pattern Rules

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.