1
- CFLAGS := -O -g \
2
- -std=c99 -pedantic
1
+ # Compiler and flags
2
+ CC ?= gcc
3
+ CFLAGS := -O -g -std=c99 -pedantic
3
4
5
+ # Flags to check for compiler support
4
6
CFLAGS_TO_CHECK := \
5
7
-fwrapv \
6
8
-Wall -Wextra \
@@ -16,122 +18,119 @@ CFLAGS_TO_CHECK := \
16
18
-Wno-format-pedantic \
17
19
-Wno-overflow
18
20
19
- SUPPORTED_CFLAGS :=
20
- # Check if a specific compiler flag is supported, attempting a dummy compilation
21
- # with flags. If successful, it returns the flag string; otherwise, it returns
22
- # an empty string.
23
- # Usage: $(call check_flag, -some-flag)
24
- check_flag = $(shell $(CC ) $(1 ) -S -o /dev/null -xc /dev/null 2>/dev/null; \
25
- if test $$? -eq 0; then echo "$(1 ) "; fi)
21
+ # Check if a specific compiler flag is supported
22
+ check_flag = $(shell $(CC ) $(1 ) -S -o /dev/null -xc /dev/null 2>/dev/null && echo "$(1 ) ")
26
23
27
- # Iterate through the list of all potential flags, effectively filtering out all
28
- # unsupported flags.
29
- $(foreach flag, $(CFLAGS_TO_CHECK), $(eval CFLAGS += $(call check_flag, $(flag))))
24
+ # Add supported flags
25
+ $(foreach flag,$(CFLAGS_TO_CHECK),$(eval CFLAGS += $(call check_flag,$(flag))))
30
26
27
+ # Build configuration
31
28
BUILD_SESSION := .session.mk
32
-
33
29
-include $(BUILD_SESSION )
34
30
31
+ # Stage definitions
35
32
STAGE0 := shecc
36
33
STAGE1 := shecc-stage1.elf
37
34
STAGE2 := shecc-stage2.elf
38
35
36
+ # Directory structure
39
37
OUT ?= out
40
- ARCHS = arm riscv
41
- ARCH ?= $(firstword $(ARCHS ) )
42
- HOST_ARCH = $(shell arch 2>/dev/null)
43
38
SRCDIR := $(shell find src -type d)
44
39
LIBDIR := $(shell find lib -type d)
45
40
46
- SRCS := $(wildcard $(patsubst % ,% /main.c, $(SRCDIR ) ) )
41
+ # Architecture configuration
42
+ ARCHS := arm riscv
43
+ ARCH ?= $(firstword $(ARCHS ) )
44
+ HOST_ARCH := $(shell arch 2>/dev/null)
45
+
46
+ # Source files
47
+ SRCS := $(wildcard $(patsubst % ,% /main.c,$(SRCDIR ) ) )
47
48
OBJS := $(SRCS:%.c=$(OUT ) /%.o )
48
- deps := $(OBJS:%.o=%.o.d )
49
+ DEPS := $(OBJS:%.o=%.o.d )
50
+
51
+ # Test files
49
52
TESTS := $(wildcard tests/* .c)
50
53
TESTBINS := $(TESTS:%.c=$(OUT ) /%.elf )
51
- SNAPSHOTS := $(foreach SNAPSHOT_ARCH,$(ARCHS ) , $(patsubst tests/% .c, tests/snapshots/% -$(SNAPSHOT_ARCH ) .json, $(TESTS ) ) )
54
+ SNAPSHOTS := $(foreach SNAPSHOT_ARCH,$(ARCHS ) ,$(patsubst tests/% .c,tests/snapshots/% -$(SNAPSHOT_ARCH ) .json,$(TESTS ) ) )
52
55
53
- all : config bootstrap
56
+ # Build targets
57
+ .PHONY : all config bootstrap clean distclean
58
+ .PHONY : check check-stage0 check-stage2 check-sanitizer check-snapshots check-snapshot
59
+ .PHONY : update-snapshots update-snapshot sanitizer help
54
60
55
- sanitizer : CFLAGS += -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -O0
56
- sanitizer : LDFLAGS += -fsanitize=address -fsanitize=undefined
57
- sanitizer : config $(OUT ) /$(STAGE0 ) -sanitizer
58
- $(VECHO ) " Built stage 0 compiler with sanitizers\n"
61
+ .DEFAULT_GOAL := all
62
+
63
+ all : config bootstrap
59
64
65
+ help :
66
+ @echo " Available targets:"
67
+ @echo " all - Build with bootstrap (default)"
68
+ @echo " bootstrap - Build and verify self-hosting compiler"
69
+ @echo " config - Configure target architecture"
70
+ @echo " sanitizer - Build with address/undefined sanitizers"
71
+ @echo " check - Run all tests"
72
+ @echo " check-stage0 - Test stage 0 compiler"
73
+ @echo " check-stage2 - Test stage 2 compiler"
74
+ @echo " check-sanitizer - Test with sanitizers"
75
+ @echo " check-snapshots - Verify IR snapshots"
76
+ @echo " update-snapshots - Update IR snapshots"
77
+ @echo " clean - Remove build artifacts"
78
+ @echo " distclean - Remove all generated files"
79
+ @echo " "
80
+ @echo " Variables:"
81
+ @echo " ARCH={arm,riscv} - Target architecture (default: $( ARCH) )"
82
+ @echo " OUT=<dir> - Output directory (default: $( OUT) )"
83
+ @echo " CC=<compiler> - C compiler (default: $( CC) )"
84
+
85
+ # Validate architecture selection
60
86
ifeq (,$(filter $(ARCH ) ,$(ARCHS ) ) )
61
- $(error Support ARM and RISC-V only. Select the target with " ARCH=arm" or " ARCH=riscv" )
87
+ $(error Unsupported architecture '$(ARCH)'. Use ARCH=arm or ARCH=riscv)
62
88
endif
89
+
63
90
include mk/$(ARCH ) .mk
64
91
include mk/common.mk
65
92
93
+ # Configuration target
66
94
config :
67
- $(Q ) ln -s $(PWD ) /$(SRCDIR ) /$(ARCH ) -codegen.c $(SRCDIR ) /codegen.c
95
+ $(Q ) mkdir -p $(OUT ) $(OUT ) /$(SRCDIR ) $(OUT ) /tests
96
+ $(Q ) ln -sf $(PWD ) /$(SRCDIR ) /$(ARCH ) -codegen.c $(SRCDIR ) /codegen.c
68
97
$(Q )$(PRINTF ) $(ARCH_DEFS ) > $@
69
- $(VECHO ) " Target machine code switch to %s\n" $(ARCH )
70
- $(Q )$(MAKE ) $(BUILD_SESSION ) --silent
98
+ $(VECHO ) " Target architecture: %s\n" $(ARCH )
99
+ $(Q )$(MAKE ) $(BUILD_SESSION ) --no-print-directory
71
100
$(Q )$(CONFIG_CHECK_CMD )
72
101
73
- $(OUT ) /tests/% .elf : tests/% .c $(OUT ) /$(STAGE0 )
74
- $(VECHO ) " SHECC\t$@ \n"
75
- $(Q )$(OUT ) /$(STAGE0 ) --dump-ir -o $@ $< > $(basename $@ ) .log ; \
76
- chmod +x $@ ; $(PRINTF ) " Running $@ ...\n"
77
- $(Q )$(TARGET_EXEC ) $@ && $(call pass)
78
-
79
- check : check-stage0 check-stage2
80
-
81
- check-stage0 : $(OUT ) /$(STAGE0 ) $(TESTBINS ) tests/driver.sh
82
- $(VECHO ) " TEST STAGE 0\n"
83
- tests/driver.sh 0
84
-
85
- check-stage2 : $(OUT ) /$(STAGE2 ) $(TESTBINS ) tests/driver.sh
86
- $(VECHO ) " TEST STAGE 2\n"
87
- tests/driver.sh 2
88
-
89
- check-sanitizer : $(OUT ) /$(STAGE0 ) -sanitizer tests/driver.sh
90
- $(VECHO ) " TEST STAGE 0 (with sanitizers)\n"
91
- $(Q ) cp $(OUT ) /$(STAGE0 ) -sanitizer $(OUT ) /shecc
92
- tests/driver.sh 0
93
- $(Q ) rm $(OUT ) /shecc
94
-
95
- check-snapshots : $(OUT ) /$(STAGE0 ) $(SNAPSHOTS ) tests/check-snapshots.sh
96
- $(Q )$(foreach SNAPSHOT_ARCH, $(ARCHS ) , $(MAKE ) distclean config check-snapshot ARCH=$(SNAPSHOT_ARCH ) --silent;)
97
- $(VECHO ) " Switching backend back to %s\n" $(ARCH )
98
- $(Q )$(MAKE ) distclean config ARCH=$(ARCH ) --silent
99
-
100
- check-snapshot : $(OUT ) /$(STAGE0 ) tests/check-snapshots.sh
101
- $(VECHO ) " Checking snapshot for %s\n" $(ARCH )
102
- tests/check-snapshots.sh $(ARCH )
103
- $(VECHO ) " OK\n"
104
-
105
- update-snapshots : tests/update-snapshots.sh
106
- $(Q )$(foreach SNAPSHOT_ARCH, $(ARCHS ) , $(MAKE ) distclean config update-snapshot ARCH=$(SNAPSHOT_ARCH ) --silent;)
107
- $(VECHO ) " Switching backend back to %s\n" $(ARCH )
108
- $(Q )$(MAKE ) distclean config ARCH=$(ARCH ) --silent
102
+ $(BUILD_SESSION ) :
103
+ @$(PRINTF ) " ARCH=$( ARCH) \n" > $@
109
104
110
- update-snapshot : $(OUT ) /$(STAGE0 ) tests/update-snapshots.sh
111
- $(VECHO ) " Updating snapshot for %s\n" $(ARCH )
112
- tests/update-snapshots.sh $(ARCH )
113
- $(VECHO ) " OK\n"
105
+ # Sanitizer build
106
+ sanitizer : CFLAGS += -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -O0
107
+ sanitizer : LDFLAGS += -fsanitize=address -fsanitize=undefined
108
+ sanitizer : config $(OUT ) /$(STAGE0 ) -sanitizer
109
+ $(VECHO ) " Built stage 0 compiler with sanitizers\n"
114
110
115
- $(OUT ) /% .o : % .c
111
+ # Object file compilation
112
+ $(OUT ) /% .o : % .c | $(OUT )
116
113
$(VECHO ) " CC\t$@ \n"
114
+ $(Q ) mkdir -p $(dir $@ )
117
115
$(Q )$(CC ) -o $@ $(CFLAGS ) -c -MMD -MF $@ .d $<
118
116
119
- SHELL_HACK := $(shell mkdir -p $(OUT ) $(OUT ) /$(SRCDIR ) $(OUT ) /tests)
117
+ # Tool binaries
118
+ $(OUT ) /norm-lf : tools/norm-lf.c | $(OUT )
119
+ $(VECHO ) " CC+LD\t$@ \n"
120
+ $(Q )$(CC ) $(CFLAGS ) -o $@ $^
120
121
121
- $(OUT ) /norm-lf : tools/norm-lf.c
122
+ $(OUT ) /inliner : tools/inliner.c | $( OUT )
122
123
$(VECHO ) " CC+LD\t$@ \n"
123
124
$(Q )$(CC ) $(CFLAGS ) -o $@ $^
124
125
125
- $(OUT ) /libc.inc : $(OUT ) /inliner $(OUT ) /norm-lf $(LIBDIR ) /c.c
126
+ # Generate libc include
127
+ $(OUT ) /libc.inc : $(OUT ) /inliner $(OUT ) /norm-lf $(LIBDIR ) /c.c | $(OUT )
126
128
$(VECHO ) " GEN\t$@ \n"
127
129
$(Q )$(OUT ) /norm-lf $(LIBDIR ) /c.c $(OUT ) /c.normalized.c
128
130
$(Q )$(OUT ) /inliner $(OUT ) /c.normalized.c $@
129
131
$(Q )$(RM ) $(OUT ) /c.normalized.c
130
132
131
- $(OUT ) /inliner : tools/inliner.c
132
- $(VECHO ) " CC+LD\t$@ \n"
133
- $(Q )$(CC ) $(CFLAGS ) -o $@ $^
134
-
133
+ # Stage 0: Host compiler build
135
134
$(OUT ) /$(STAGE0 ) : $(OUT ) /libc.inc $(OBJS )
136
135
$(VECHO ) " LD\t$@ \n"
137
136
$(Q )$(CC ) $(OBJS ) $(LDFLAGS ) -o $@
@@ -140,35 +139,94 @@ $(OUT)/$(STAGE0)-sanitizer: $(OUT)/libc.inc $(OBJS)
140
139
$(VECHO ) " LD\t$@ (with sanitizers)\n"
141
140
$(Q )$(CC ) $(OBJS ) $(LDFLAGS ) -o $@
142
141
142
+ # Stage 1: Self-compiled compiler
143
143
$(OUT ) /$(STAGE1 ) : $(OUT ) /$(STAGE0 )
144
144
$(Q )$(STAGE1_CHECK_CMD )
145
145
$(VECHO ) " SHECC\t$@ \n"
146
146
$(Q )$(OUT ) /$(STAGE0 ) --dump-ir -o $@ $(SRCDIR ) /main.c > $(OUT ) /shecc-stage1.log
147
147
$(Q ) chmod a+x $@
148
148
149
+ # Stage 2: Verify bootstrap
149
150
$(OUT ) /$(STAGE2 ) : $(OUT ) /$(STAGE1 )
150
151
$(VECHO ) " SHECC\t$@ \n"
151
152
$(Q )$(TARGET_EXEC ) $(OUT ) /$(STAGE1 ) -o $@ $(SRCDIR ) /main.c
153
+ $(Q ) chmod a+x $@
152
154
155
+ # Bootstrap verification
153
156
bootstrap : $(OUT ) /$(STAGE2 )
154
- $(Q ) chmod 775 $(OUT ) /$(STAGE2 )
155
- $(Q ) if ! diff -q $(OUT ) /$(STAGE1 ) $(OUT ) /$(STAGE2 ) ; then \
156
- echo " Unable to bootstrap. Aborting" ; false ; \
157
+ $(Q ) if cmp -s $(OUT ) /$(STAGE1 ) $(OUT ) /$(STAGE2 ) ; then \
158
+ echo " Bootstrap successful: Stage 1 and Stage 2 are identical" ; \
159
+ else \
160
+ echo " ERROR: Bootstrap failed - Stage 1 and Stage 2 differ" ; \
161
+ exit 1; \
157
162
fi
158
163
159
- $(BUILD_SESSION ) :
160
- $(PRINTF ) " ARCH=$( ARCH) " > $@
164
+ # Test compilation
165
+ $(OUT ) /tests/% .elf : tests/% .c $(OUT ) /$(STAGE0 )
166
+ $(VECHO ) " SHECC\t$@ \n"
167
+ $(Q )$(OUT ) /$(STAGE0 ) --dump-ir -o $@ $< > $(basename $@ ) .log
168
+ $(Q ) chmod +x $@
169
+ $(Q )$(PRINTF ) " Running $@ ...\n"
170
+ $(Q )$(TARGET_EXEC ) $@ && $(call pass)
171
+
172
+ # Test targets
173
+ check : check-stage0 check-stage2
161
174
162
- .PHONY : clean
175
+ check-stage0 : $(OUT ) /$(STAGE0 ) $(TESTBINS ) tests/driver.sh
176
+ $(VECHO ) " Testing Stage 0 compiler\n"
177
+ @tests/driver.sh 0
178
+
179
+ check-stage2 : $(OUT ) /$(STAGE2 ) $(TESTBINS ) tests/driver.sh
180
+ $(VECHO ) " Testing Stage 2 compiler\n"
181
+ @tests/driver.sh 2
182
+
183
+ check-sanitizer : $(OUT ) /$(STAGE0 ) -sanitizer tests/driver.sh
184
+ $(VECHO ) " Testing Stage 0 with sanitizers\n"
185
+ $(Q ) cp $(OUT ) /$(STAGE0 ) -sanitizer $(OUT ) /shecc
186
+ @tests/driver.sh 0
187
+ $(Q ) rm $(OUT ) /shecc
188
+
189
+ # Snapshot testing
190
+ check-snapshots : $(OUT ) /$(STAGE0 ) $(SNAPSHOTS ) tests/check-snapshots.sh
191
+ $(Q )$(foreach SNAPSHOT_ARCH,$(ARCHS ) ,$(MAKE ) distclean config check-snapshot ARCH=$(SNAPSHOT_ARCH ) --no-print-directory;)
192
+ $(VECHO ) " Switching backend back to %s\n" $(ARCH )
193
+ $(Q )$(MAKE ) distclean config ARCH=$(ARCH ) --no-print-directory
194
+
195
+ check-snapshot : $(OUT ) /$(STAGE0 ) tests/check-snapshots.sh
196
+ $(VECHO ) " Checking snapshot for %s\n" $(ARCH )
197
+ @tests/check-snapshots.sh $(ARCH )
198
+ $(VECHO ) " OK\n"
199
+
200
+ update-snapshots : tests/update-snapshots.sh
201
+ $(Q )$(foreach SNAPSHOT_ARCH,$(ARCHS ) ,$(MAKE ) distclean config update-snapshot ARCH=$(SNAPSHOT_ARCH ) --no-print-directory;)
202
+ $(VECHO ) " Switching backend back to %s\n" $(ARCH )
203
+ $(Q )$(MAKE ) distclean config ARCH=$(ARCH ) --no-print-directory
204
+
205
+ update-snapshot : $(OUT ) /$(STAGE0 ) tests/update-snapshots.sh
206
+ $(VECHO ) " Updating snapshot for %s\n" $(ARCH )
207
+ @tests/update-snapshots.sh $(ARCH )
208
+ $(VECHO ) " OK\n"
209
+
210
+ # Directory creation
211
+ $(OUT ) :
212
+ @mkdir -p $(OUT ) $(OUT ) /$(SRCDIR ) $(OUT ) /tests
213
+
214
+ # Clean targets
163
215
clean :
164
- -$(RM ) $(OUT ) /$(STAGE0 ) $(OUT ) /$(STAGE1 ) $(OUT ) /$(STAGE2 )
165
- -$(RM ) $(OBJS ) $(deps )
166
- -$(RM ) $(TESTBINS ) $(OUT ) /tests/* .log $(OUT ) /tests/* .lst
167
- -$(RM ) $(OUT ) /shecc* .log
168
- -$(RM ) $(OUT ) /libc.inc
216
+ $(VECHO ) " Cleaning build artifacts\n"
217
+ -$(Q )$(RM ) -f $(OUT ) /$(STAGE0 ) $(OUT ) /$(STAGE1 ) $(OUT ) /$(STAGE2 )
218
+ -$(Q )$(RM ) -f $(OUT ) /$(STAGE0 ) -sanitizer
219
+ -$(Q )$(RM ) -f $(OBJS ) $(DEPS )
220
+ -$(Q )$(RM ) -f $(TESTBINS ) $(OUT ) /tests/* .log $(OUT ) /tests/* .lst
221
+ -$(Q )$(RM ) -f $(OUT ) /shecc* .log
222
+ -$(Q )$(RM ) -f $(OUT ) /libc.inc $(OUT ) /c.normalized.c
169
223
170
224
distclean : clean
171
- -$(RM ) $(OUT ) /inliner $(OUT ) /norm-lf $(OUT ) /target $(SRCDIR ) /codegen.c config $(BUILD_SESSION )
172
- -$(RM ) DOM.dot CFG.dot
173
-
174
- -include $(deps )
225
+ $(VECHO ) " Removing all generated files\n"
226
+ -$(Q )$(RM ) -f $(OUT ) /inliner $(OUT ) /norm-lf $(OUT ) /target
227
+ -$(Q )$(RM ) -f $(SRCDIR ) /codegen.c config $(BUILD_SESSION )
228
+ -$(Q )$(RM ) -f DOM.dot CFG.dot
229
+ -$(Q )$(RM ) -rf $(OUT )
230
+
231
+ # Include dependencies
232
+ -include $(DEPS )
0 commit comments