-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMakefile
More file actions
223 lines (183 loc) · 9.04 KB
/
Copy pathMakefile
File metadata and controls
223 lines (183 loc) · 9.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
CC = gcc
CFLAGS = -Wall -Wextra -std=c11 -O2 -g -Iinclude -Isrc -MMD -MP
LDFLAGS = -lm
# Source files
CORE_SRC = src/core/runtime.c src/core/gc.c
FRONTEND_SRC = src/frontend/tokenizer.c src/frontend/keywords_hash.c src/frontend/parser.c
COMPILER_SRC = src/compiler/compiler.c
VM_SRC = src/vm/vm.c
MAIN_SRC = main.c
LINENOISE_SRC = linenoise.c
ALL_SRC = $(CORE_SRC) $(FRONTEND_SRC) $(COMPILER_SRC) $(VM_SRC) $(MAIN_SRC) $(LINENOISE_SRC)
# Object files
OBJ = $(ALL_SRC:.c=.o)
# LSP server excludes main.c and vm (only needs compiler/frontend)
LSP_SRC = $(CORE_SRC) $(FRONTEND_SRC) $(COMPILER_SRC)
LSP_OBJ = $(LSP_SRC:.c=.o)
# LSP server source files (split from lsp_server.c)
LSP_SERVER_SRC = src/lsp/lsp_main.c \
src/lsp/lsp_messages.c \
src/lsp/lsp_utils.c \
src/lsp/lsp_diagnostics.c \
src/lsp/lsp_handlers.c \
src/lsp/lsp_completion.c \
src/lsp/lsp_hover.c \
src/lsp/lsp_definition.c
LSP_SERVER_OBJ = $(LSP_SERVER_SRC:.c=.o)
# Dependency files (auto-generated)
DEP = $(OBJ:.o=.d)
LSP_DEP = $(LSP_SERVER_OBJ:.o=.d)
# Output binary
TARGET = kronos
.PHONY: all clean run test test-unit test-lsp install lsp
all: $(TARGET)
$(TARGET): $(OBJ)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# Generate perfect hash for keywords using gperf
src/frontend/keywords_hash.c: src/frontend/keywords.gperf
gperf -t --output-file=$@ --lookup-function-name=keyword_lookup --compare-strncmp $<
@# Fix empty string entries in generated file
@python3 -c "import re; content = open('$@').read(); content = re.sub(r'\{\s*\"\"\s*\}', '{NULL, 0}', content); open('$@', 'w').write(content)"
@# Remove inline keywords and related preprocessor directives that can cause linking issues
@python3 scripts/fix_keywords_hash.py $@
@# Fix struct definition and function signature
@# Fix function signatures (old-style to modern C)
@# Cross-platform sed: macOS needs -i '', Linux needs -i
@# Fix function signatures (old-style to modern C)
@# Cross-platform sed: macOS needs -i '', Linux needs -i
@# Handle both 'hash' and 'keyword_hash_func' (in case Python already renamed it)
@if [ "$$(uname)" = "Darwin" ]; then \
sed -i '' 's/^static unsigned int$$/static unsigned int/' $@; \
sed -i '' 's/^hash (str, len)$$/keyword_hash_func (register const char *str, register unsigned int len)/' $@; \
sed -i '' 's/^keyword_hash_func(str, len)$$/keyword_hash_func (register const char *str, register unsigned int len)/' $@; \
sed -i '' '/^ register const char \*str;$$/d' $@; \
sed -i '' '/^ register unsigned int len;$$/d' $@; \
sed -i '' 's/^struct KeywordEntry \*/const struct KeywordEntry */' $@; \
sed -i '' 's/^keyword_lookup (str, len)$$/keyword_lookup (register const char *str, register unsigned int len)/' $@; \
sed -i '' 's/static struct KeywordEntry wordlist/static const struct KeywordEntry wordlist/' $@; \
sed -i '' 's/unsigned int key = hash (str, len);/unsigned int key = keyword_hash_func (str, len);/' $@; \
sed -i '' 's/unsigned int key = keyword_hash_func(str, len);/unsigned int key = keyword_hash_func (str, len);/' $@; \
sed -i '' 's/register const char \*s = wordlist\[key\]\.name;/register const struct KeywordEntry *entry = \&wordlist[key];/' $@ || true; \
sed -i '' 's/if (\*str == \*s && !strncmp (str + 1, s + 1, len - 1) && s\[len\] == '\''\\0'\'')/if (entry->keyword \&\& strlen(entry->keyword) == len \&\& !strncmp(str, entry->keyword, len))/' $@ || true; \
sed -i '' 's/return \&wordlist\[key\];/return entry;/' $@ || true; \
sed -i '' 's/return 0;/return NULL;/' $@ || true; \
else \
sed -i 's/^static unsigned int$$/static unsigned int/' $@; \
sed -i 's/^hash (str, len)$$/keyword_hash_func (register const char *str, register unsigned int len)/' $@; \
sed -i 's/^keyword_hash_func(str, len)$$/keyword_hash_func (register const char *str, register unsigned int len)/' $@; \
sed -i '/^ register const char \*str;$$/d' $@; \
sed -i '/^ register unsigned int len;$$/d' $@; \
sed -i 's/^struct KeywordEntry \*/const struct KeywordEntry */' $@; \
sed -i 's/^keyword_lookup (str, len)$$/keyword_lookup (register const char *str, register unsigned int len)/' $@; \
sed -i 's/static struct KeywordEntry wordlist/static const struct KeywordEntry wordlist/' $@; \
sed -i 's/unsigned int key = hash (str, len);/unsigned int key = keyword_hash_func (str, len);/' $@; \
sed -i 's/unsigned int key = keyword_hash_func(str, len);/unsigned int key = keyword_hash_func (str, len);/' $@; \
sed -i 's/register const char \*s = wordlist\[key\]\.name;/register const struct KeywordEntry *entry = \&wordlist[key];/' $@ || true; \
sed -i 's/if (\*str == \*s && !strncmp (str + 1, s + 1, len - 1) && s\[len\] == '\''\\0'\'')/if (entry->keyword \&\& strlen(entry->keyword) == len \&\& !strncmp(str, entry->keyword, len))/' $@ || true; \
sed -i 's/return \&wordlist\[key\];/return entry;/' $@ || true; \
sed -i 's/return 0;/return NULL;/' $@ || true; \
fi
@# Keep struct definition but ensure it's properly formatted
@echo " Generated $@ from $<"
lsp: $(LSP_SERVER_OBJ) $(LSP_OBJ)
$(CC) $(CFLAGS) -o kronos-lsp $^ $(LDFLAGS)
clean:
rm -f $(OBJ) $(DEP) $(TARGET) kronos-lsp
rm -f src/core/*.o src/core/*.d src/frontend/*.o src/frontend/*.d
rm -f src/compiler/*.o src/compiler/*.d src/vm/*.o src/vm/*.d src/lsp/*.o src/lsp/*.d
rm -f $(TEST_OBJ) $(TEST_DEP) $(TEST_TARGET)
rm -f tests/framework/*.o tests/framework/*.d tests/unit/*.o tests/unit/*.d
run: $(TARGET)
./$(TARGET)
test: $(TARGET)
./$(TARGET) examples/test.kr
# Unit test sources
TEST_FRAMEWORK_SRC = tests/framework/test_framework.c
TEST_UNIT_SRC = tests/unit/test_tokenizer.c \
tests/unit/test_parser.c \
tests/unit/test_runtime.c \
tests/unit/test_compiler.c \
tests/unit/test_vm.c \
tests/unit/test_gc.c \
tests/unit/test_main.c
# Unit test object files
TEST_OBJ = $(TEST_FRAMEWORK_SRC:.c=.o) $(TEST_UNIT_SRC:.c=.o)
TEST_DEP = $(TEST_OBJ:.o=.d)
# Unit test executable
TEST_TARGET = tests/unit/kronos_unit_tests
# Object files for unit tests (exclude main.o)
TEST_OBJ_SRC = $(CORE_SRC) $(FRONTEND_SRC) $(COMPILER_SRC) $(VM_SRC)
TEST_OBJ_BASE = $(TEST_OBJ_SRC:.c=.o)
# Build unit tests
$(TEST_TARGET): $(TEST_OBJ_BASE) $(TEST_OBJ)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
# Build test object files
tests/framework/%.o: tests/framework/%.c
$(CC) $(CFLAGS) -c $< -o $@
tests/unit/%.o: tests/unit/%.c
$(CC) $(CFLAGS) -c $< -o $@
# Run unit tests
test-unit: $(TEST_TARGET)
./$(TEST_TARGET)
# LSP test sources
TEST_LSP_SRC = tests/lsp/test_lsp_framework.c tests/lsp/test_lsp_features.c
TEST_LSP_OBJ = $(TEST_LSP_SRC:.c=.o)
TEST_LSP_TARGET = tests/lsp/kronos_lsp_tests
# Build LSP tests
test-lsp: lsp $(TEST_LSP_TARGET)
./$(TEST_LSP_TARGET)
$(TEST_LSP_TARGET): tests/lsp/test_lsp_main.c $(TEST_LSP_OBJ) $(TEST_FRAMEWORK_SRC:.c=.o) $(TEST_OBJ_BASE)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
tests/lsp/%.o: tests/lsp/%.c
$(CC) $(CFLAGS) -c $< -o $@
# Install target (optional)
install: $(TARGET)
install -m 755 $(TARGET) /usr/local/bin/
# ============================================================================
# WebAssembly (WASM) Build Target
# ============================================================================
# Requires Emscripten SDK: https://emscripten.org/docs/getting_started/
# Install: git clone https://github.com/emscripten-core/emsdk.git && cd emsdk && ./emsdk install latest && ./emsdk activate latest
# Build: source emsdk_env.sh && make wasm
WASM_CC = emcc
WASM_CFLAGS = -Wall -Wextra -std=c11 -O2 -Iinclude -Isrc
WASM_LDFLAGS = -lm
# WASM source files (exclude main.c, linenoise.c - use wasm entry point instead)
WASM_SRC = $(CORE_SRC) $(FRONTEND_SRC) $(COMPILER_SRC) $(VM_SRC) wasm/kronos_wasm.c
# WASM output directory and files
WASM_OUT_DIR = website/public/wasm
WASM_TARGET = $(WASM_OUT_DIR)/kronos.js
# Emscripten settings for web deployment
WASM_SETTINGS = \
-s WASM=1 \
-s MODULARIZE=1 \
-s EXPORT_NAME="createKronosModule" \
-s EXPORTED_FUNCTIONS='["_kronos_wasm_init","_kronos_wasm_run","_kronos_wasm_cleanup","_kronos_wasm_reset","_kronos_wasm_get_error","_kronos_wasm_get_warnings","_kronos_wasm_version","_malloc","_free"]' \
-s EXPORTED_RUNTIME_METHODS='["ccall","cwrap","UTF8ToString","stringToUTF8","lengthBytesUTF8"]' \
-s ALLOW_MEMORY_GROWTH=1 \
-s INITIAL_MEMORY=16777216 \
-s MAXIMUM_MEMORY=268435456 \
-s ENVIRONMENT='web' \
-s NO_EXIT_RUNTIME=1 \
-s SINGLE_FILE=0 \
--no-entry
.PHONY: wasm wasm-clean wasm-debug
# Build WASM for production
wasm: $(WASM_TARGET)
$(WASM_TARGET): $(WASM_SRC)
@mkdir -p $(WASM_OUT_DIR)
$(WASM_CC) $(WASM_CFLAGS) $(WASM_SRC) -o $@ $(WASM_LDFLAGS) $(WASM_SETTINGS)
@echo " Built WebAssembly module: $@"
@echo " Also created: $(WASM_OUT_DIR)/kronos.wasm"
# Build WASM with debug symbols
wasm-debug: WASM_CFLAGS += -g -s ASSERTIONS=2 -s SAFE_HEAP=1
wasm-debug: $(WASM_TARGET)
# Clean WASM build artifacts
wasm-clean:
rm -rf $(WASM_OUT_DIR)
# Include auto-generated dependency files (if they exist)
-include $(DEP)
-include $(LSP_DEP)
-include $(TEST_DEP)