Skip to content

Commit 36c49e6

Browse files
committed
Add top-level makefile
1 parent d7512a3 commit 36c49e6

File tree

2 files changed

+104
-1
lines changed

2 files changed

+104
-1
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ jobs:
1919
- name: Test Exercises
2020
env:
2121
CC: ${{ matrix.compiler }}
22-
run: ./bin/run-tests -a
22+
run: make -j $(nproc)

makefile

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# This makefile creates a target to build and test each exercise using the provided example
2+
# implementation. The exercise target depends on a list of other targets that
3+
# 1) Copy the main test file and adjust it to include all tests,
4+
# 2) Copy the example implementation so that it is used,
5+
# 3) Copy the makefile and unittest framework,
6+
# 4) Build and test the exercise.
7+
#
8+
# Use `make <slug>` to build and test a specific exercise. Simply running `make` builds and
9+
# tests all available exercises.
10+
11+
12+
# Macro to create the rules for one exercise.
13+
# Arguments:
14+
# $(1) - slug
15+
# $(2) - slug with dashes replaced by underscores
16+
# $(3) - type of exercise: 'practice' or 'concept'
17+
# $(4) - name of test implementation: 'example' or 'exemplar'
18+
define setup_exercise
19+
20+
# Copy the test file and removes TEST_IGNORE
21+
build/exercises/$(3)/$(1)/test_$(2).c: exercises/$(3)/$(1)/test_$(2).c
22+
@mkdir -p $$(dir $$@)
23+
@sed 's#TEST_IGNORE();#// &#' $$< > $$@
24+
25+
# Copy example/exemplar implementation
26+
build/exercises/$(3)/$(1)/$(2).c: exercises/$(3)/$(1)/.meta/$(4).c
27+
@mkdir -p $$(dir $$@)
28+
@cp $$< $$@
29+
@cp exercises/$(3)/$(1)/*.h build/exercises/$(3)/$(1)/.
30+
@if [ -e exercises/$(3)/$(1)/.meta/$(4).h ]; then \
31+
cp exercises/$(3)/$(1)/.meta/$(4).h build/exercises/$(3)/$(1)/$(2).h; \
32+
fi
33+
34+
# Copy Makefile
35+
build/exercises/$(3)/$(1)/makefile: exercises/$(3)/$(1)/makefile
36+
@mkdir -p $$(dir $$@)
37+
@cp $$< $$@
38+
39+
# Copy the test framework
40+
build/exercises/$(3)/$(1)/test-framework: $$(wildcard exercises/$(3)/$(1)/test-framework/*)
41+
@mkdir -p $$@
42+
@cp exercises/$(3)/$(1)/test-framework/* build/exercises/$(3)/$(1)/test-framework/
43+
44+
# Build the exercise.
45+
build/exercises/$(3)/$(1)/tests.out: \
46+
build/exercises/$(3)/$(1)/test_$(2).c \
47+
build/exercises/$(3)/$(1)/$(2).c \
48+
build/exercises/$(3)/$(1)/makefile \
49+
build/exercises/$(3)/$(1)/test-framework
50+
$$(MAKE) -C build/exercises/$(3)/$(1) tests.out
51+
52+
# Build and run the memcheck variant.
53+
build/exercises/$(3)/$(1)/memcheck.out: \
54+
build/exercises/$(3)/$(1)/test_$(2).c \
55+
build/exercises/$(3)/$(1)/$(2).c \
56+
build/exercises/$(3)/$(1)/makefile \
57+
build/exercises/$(3)/$(1)/test-framework
58+
$$(MAKE) -C build/exercises/$(3)/$(1) memcheck
59+
60+
61+
# Top-level target for an exercise. The target above always runs the executable, regardless of any
62+
# changes. Having the tests binary as a separate target in between allows make to skip anything
63+
# that hasn't changed.
64+
.PHONY: $(1)
65+
$(1): build/exercises/$(3)/$(1)/tests.out build/exercises/$(3)/$(1)/memcheck.out
66+
67+
endef
68+
69+
PRACTICE_EXERCISES := $(notdir $(wildcard exercises/practice/*))
70+
CONCEPT_EXERCISES := $(notdir $(wildcard exercises/concept/*))
71+
72+
.PHONY: all
73+
all: $(PRACTICE_EXERCISES) $(CONCEPT_EXERCISES)
74+
75+
# Instantiate the macro for each practice exercise to create targets for each exercise.
76+
$(foreach exercise,$(PRACTICE_EXERCISES),$(eval $(call setup_exercise,$(exercise),$(subst -,_,$(exercise)),practice,example)))
77+
$(foreach exercise,$(CONCEPT_EXERCISES),$(eval $(call setup_exercise,$(exercise),$(subst -,_,$(exercise)),concept,exemplar)))
78+
79+
.PHONY: list-practice
80+
list-practice:
81+
@for exercise in $(PRACTICE_EXERCISES); do \
82+
echo "$$exercise"; \
83+
done
84+
85+
.PHONY: list-concept
86+
list-concept:
87+
@for exercise in $(CONCEPT_EXERCISES); do \
88+
echo "$$exercise"; \
89+
done
90+
91+
.PHONY: clean
92+
clean:
93+
rm -rf build
94+
95+
.PHONY: help
96+
help:
97+
@echo "Available targets:"
98+
@echo " all - Build and test all practice exercises (default)"
99+
@echo " <slug> - Build and test a specific exercise given by its slug"
100+
@echo " clean - Remove all build artifacts"
101+
@echo " list-practice - List all practice exercises"
102+
@echo " list-concept - List all concept exercises"
103+
@echo " help - Show this help message"

0 commit comments

Comments
 (0)