-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
454 lines (369 loc) Β· 15.4 KB
/
Makefile
File metadata and controls
454 lines (369 loc) Β· 15.4 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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# tidesh
# A lightweight but fully-featured shell
#
# This is the Makefile for the tidesh project.
# Version 1.0
# Compiler and flags
CC ?= clang
CFLAGS = -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=unused-parameter -Wno-error=unused-but-set-variable -Wno-error=comment -std=gnu11 $(EXTRA_CFLAGS)
DEBUGFLAGS = -Wall -Wextra -Werror -fsanitize=address -g
RELEASEFLAGS = -O3 -DNDEBUG
TESTINGFLAGS = -DTESTING -Itests/snow/ -DSNOW_ENABLED
# Binary name
PROJECT_NAME ?= tidesh
VERSION ?= 1.0
BRIEF ?= A lightweight but fully-featured shell
# Directory structure
SRC_DIR ?= src
INCLUDES_DIR ?= include
TESTS_DIR ?= tests
OBJ_DIR ?= obj
BIN_DIR ?= bin
DOC_DIR ?= docs
# Installation directory
PREFIX ?= /usr/local
INSTALL_DIR ?= $(PREFIX)/bin
# Include the headers
CFLAGS += -I$(INCLUDES_DIR)
# Terminal styling
BOLD := $(shell tput bold 2>/dev/null || echo '')
SGR0 := $(shell tput sgr0 2>/dev/null || echo '')
SITM := $(shell tput sitm 2>/dev/null || echo '')
SMUL := $(shell tput smul 2>/dev/null || echo '')
SETAF244 := $(shell if [ $$(tput colors 2>/dev/null || echo 0) -ge 256 ] 2>/dev/null; then tput setaf 244 2>/dev/null || echo ''; else tput setaf 0 2>/dev/null || echo ''; fi)
######################################
# CHECKS #
######################################
# Create necessary directories
$(shell mkdir -p $(OBJ_DIR) $(TESTS_OBJ_DIR) $(TESTS_SRC_OBJ_DIR) $(BIN_DIR) $(DOC_DIR))
# Build type configuration (release by default)
BUILD_TYPE ?= release
ifeq ($(BUILD_TYPE),release)
CFLAGS += $(RELEASEFLAGS)
else
CFLAGS += $(DEBUGFLAGS)
endif
# Detect platform
UNAME := $(shell uname)
ifeq ($(UNAME), Darwin)
PLATFORM ?= macos
else ifeq ($(UNAME), Linux)
PLATFORM ?= linux
else
PLATFORM ?= windows
endif
# Version information from git (if available)
ifdef CI_COMMIT_SHORT_SHA
GIT_VERSION := $(CI_COMMIT_SHORT_SHA)
# GitLab CI - full SHA that needs truncation
else ifdef CI_COMMIT_SHA
GIT_VERSION := $(shell echo ${CI_COMMIT_SHA} | cut -c1-8)
# GitHub Actions
else ifdef GITHUB_SHA
GIT_VERSION := $(shell echo ${GITHUB_SHA} | cut -c1-8)
else
GIT_VERSION := $(shell git describe --tags --always 2>/dev/null || echo "unknown")
endif
BUILD_DATE := $(shell date +"%Y-%m-%d")
CFLAGS += -DPROJECT_NAME='"$(PROJECT_NAME)"' -DRAW_VERSION='"$(VERSION)"' -DGIT_VERSION='"$(GIT_VERSION)"' -DVERSION='"$(VERSION)-$(GIT_VERSION)"' -DBUILD_DATE='"$(BUILD_DATE)"' -DPLATFORM='"$(PLATFORM)"' -DBRIEF='"$(BRIEF)"'
# Source files
SRC = $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/*/*.c)
# Object files
OBJ = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRC))
# Test source files
TESTS_SRC = $(wildcard $(TESTS_DIR)/*.c $(TESTS_DIR)/*/*.c)
# Test object directories
TESTING_OBJ_DIR = $(OBJ_DIR)/testing
TESTS_OBJ_DIR = $(TESTING_OBJ_DIR)/tests
TESTS_SRC_OBJ_DIR = $(TESTING_OBJ_DIR)/src
# Test object files
TESTS_OBJ = $(patsubst $(TESTS_DIR)/%.c,$(TESTS_OBJ_DIR)/%.o,$(TESTS_SRC))
# Source objects compiled with TESTING flag for test builds
TESTS_SRC_OBJ = $(patsubst $(SRC_DIR)/%.c,$(TESTS_SRC_OBJ_DIR)/%.o,$(SRC))
# Targets
TARGET_PREFIX = $(BIN_DIR)/$(PROJECT_NAME)
ifeq ($(PLATFORM), windows)
TARGET_EXTENSION = ".exe"
else
TARGET_EXTENSION = ""
endif
TARGET_SUFFIX = $(VERSION)-$(GIT_VERSION)-$(PLATFORM)-$(BUILD_TYPE)$(TARGET_EXTENSION)
TARGET ?= $(TARGET_PREFIX)-$(TARGET_SUFFIX)
TESTS_TARGET ?= $(TARGET_PREFIX)-test-$(TARGET_SUFFIX)
######################################
# HELP #
######################################
# Silent mode toggle
ifndef VERBOSE
SILENT = @
endif
.PHONY: all
all: compile
# Help command
.PHONY: help
help:
@echo "$(SITM)$(PROJECT_NAME) Makefile$(SGR0)"
@echo "$(BRIEF)"
@echo ""
@echo "Usage:"
@echo " $(BOLD)make$(SGR0) <command> [BUILD_TYPE=debug|release] [VERBOSE=1] [CFLAGS='...']"
@echo ""
@echo "Build types:"
@echo " debug: Build with debug info"
@echo " release: Build optimized version (default)"
@echo ""
@echo "Feature flags (optional, all enabled by default):"
@echo " $(BOLD)CFLAGS='-DTIDESH_DISABLE_HISTORY'$(SGR0) Disable history builtin"
@echo " $(BOLD)CFLAGS='-DTIDESH_DISABLE_DIRSTACK'$(SGR0) Disable pushd/popd builtins"
@echo " $(BOLD)CFLAGS='-DTIDESH_DISABLE_JOB_CONTROL'$(SGR0) Disable jobs/fg/bg builtins"
@echo " $(BOLD)CFLAGS='-DTIDESH_DISABLE_ALIASES'$(SGR0) Disable alias expansion"
@echo ""
@echo "Available commands:"
@echo " $(BOLD)all: Compile everything$(SGR0)"
@echo " $(BOLD)run: Run the shell$(SGR0)"
@echo " $(BOLD)install: Install the shell$(SGR0)"
@echo " $(BOLD)test: Run all tests$(SGR0)"
@echo " $(BOLD)routine: Run routine checks$(SGR0) $(BOLD)$(SETAF244)(clean, format, docs, lint)$(SGR0)"
@echo ""
@echo "Other commands:"
@echo " $(BOLD)info: Show build configuration$(SGR0)"
@echo " $(BOLD)docs: Generate documentation$(SGR0)"
@echo " $(BOLD)clean: Clean build files$(SGR0)"
@echo " $(BOLD)clean/all: Clean everything$(SGR0)"
@echo " $(BOLD)build/python: Build Python bindings$(SGR0)"
@echo " $(BOLD)clean/python: Clean Python bindings$(SGR0)"
@echo " $(BOLD)uninstall: Uninstall the shell$(SGR0)"
@echo " $(BOLD)lint: Run linters$(SGR0)"
@echo " $(BOLD)lint/tests: Lint test code$(SGR0)"
@echo " $(BOLD)format: Format code$(SGR0)"
@echo " $(BOLD)format/tests: Format test code$(SGR0)"
@echo ""
@echo "Current configuration:"
@echo " $(BOLD)Platform: $(PLATFORM)$(SGR0)"
@echo " $(BOLD)Build type: $(BUILD_TYPE)$(SGR0)"
@echo " $(BOLD)Version: $(VERSION)-$(GIT_VERSION)$(SGR0)"
@echo " $(BOLD)Build date: $(BUILD_DATE)$(SGR0)"
@echo ""
@echo "Example usage:"
@echo " $(BOLD)make build$(SGR0) # Full build"
@echo " $(BOLD)make build BUILD_TYPE=debug$(SGR0) # Debug build"
@echo " $(BOLD)make clean build CFLAGS='-DTIDESH_DISABLE_JOB_CONTROL'$(SGR0) # Without job control"
@echo ""
@echo "For more information, visit the repository at"
@echo " $(SMUL)https://github.com/Animenosekai/tidesh$(SGR0)"
# Info command
.PHONY: info
info:
@echo "$(BOLD)Build Configuration:$(SGR0)"
@echo " $(BOLD)Platform: $(PLATFORM)$(SGR0)"
@echo " $(BOLD)Build type: $(BUILD_TYPE)$(SGR0)"
@echo " $(BOLD)Version: $(VERSION)-$(GIT_VERSION)$(SGR0)"
@echo " $(BOLD)Build date: $(BUILD_DATE)$(SGR0)"
@echo " $(BOLD)Compiler: $(CC)$(SGR0)"
@echo " $(BOLD)CFLAGS: $(CFLAGS)$(SGR0)"
@echo " $(BOLD)Target: $(TARGET)$(SGR0)"
######################################
# ROUTINE UTILITIES #
######################################
# Routine command
.PHONY: routine
routine: clean format docs lint
# Clean commands
.PHONY: clean clean/all clean/python
clean:
@echo "$(BOLD)π§Ή Cleaning build files...$(SGR0)"
$(SILENT)rm -rf $(OBJ_DIR)
clean/all: clean clean/python
@echo "$(BOLD)π§Ή Performing deep clean...$(SGR0)"
$(SILENT)rm -rf $(BIN_DIR)
$(SILENT)rm -rf $(DOC_DIR)/out
clean/python:
@echo "$(BOLD)π§Ή Cleaning Python bindings...$(SGR0)"
$(SILENT)rm -rf bindings/python/dist bindings/python/build bindings/python/*.egg-info bindings/python/obj
# Linting commands
.PHONY: lint lint/tests
lint:
@echo "$(BOLD)π Linting the code...$(SGR0)"
$(SILENT)clang-tidy $(SRC)
lint/tests:
@echo "$(BOLD)π§ͺ Linting the tests...$(SGR0)"
$(SILENT)clang-tidy $(TESTS_SRC)
# Formatting commands
.PHONY: format format/tests
format:
@echo "$(BOLD)β¨ Formatting the code...$(SGR0)"
$(SILENT)clang-format -i $(SRC) $(INCLUDES_DIR)/*.h || true
format/tests:
@echo "$(BOLD)π§ͺ Formatting the tests...$(SGR0)"
$(SILENT)clang-format -i $(TESTS_SRC) $(TESTS_DIR)/*.h || true
# Documentation command
DOXY_PROJECT_NAME = $(PROJECT_NAME)
DOXY_PROJECT_NUMBER = $(VERSION)-$(GIT_VERSION)
DOXY_PROJECT_BRIEF = $(BRIEF)
export DOXY_PROJECT_NAME
export DOXY_PROJECT_NUMBER
export DOXY_PROJECT_BRIEF
.PHONY: docs
docs:
@echo "$(BOLD)π Generating the documentation...$(SGR0)"
$(SILENT) doxygen Doxyfile || true
######################################
# COMPILATION #
######################################
# Source files
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(SILENT)mkdir -p $(dir $@)
$(SILENT)echo "$(BOLD)π¨ Compiling $<...$(SGR0)"; \
$(CC) $(CFLAGS) -MMD -MP -c $< -o $@; \
# Include generated dependencies
-include $(OBJ_DIR)/*.d $(TESTS_OBJ_DIR)/*.d
# Component build targets
.PHONY: compile
compile: $(OBJ)
@echo "$(BOLD)βοΈ Core module ready$(SGR0)"
# Binary targets
$(TARGET): $(OBJ)
@echo "$(BOLD)π Linking...$(SGR0)"
$(SILENT)$(CC) $(CFLAGS) -o $@ $^
######################################
# RUNNING #
######################################
# Run targets
.PHONY: run build
build: $(TARGET)
@echo "$(BOLD)β
Build completed: $(TARGET)$(SGR0)"
run: build
@echo "$(BOLD)π» Running $(PROJECT_NAME)...$(SGR0)"
@echo "βββββββββββββββββββββββββββββββββββββββββββββββββββββ"
$(SILENT)$(TARGET)
@echo "βββββββββββββββββββββββββββββββββββββββββββββββββββββ"
######################################
# INSTALLATION #
######################################
# Install targets
.PHONY: install uninstall
install: build
@echo "$(BOLD)π₯ Installing $(PROJECT_NAME) to $(INSTALL_DIR)...$(SGR0)"
$(SILENT)mkdir -p $(INSTALL_DIR)
$(SILENT)cp $(TARGET) $(INSTALL_DIR)/$(PROJECT_NAME)
$(SILENT)chmod +x $(INSTALL_DIR)/$(PROJECT_NAME)
@echo "$(BOLD)β
Installation completed: $(INSTALL_DIR)/$(PROJECT_NAME)$(SGR0)"
uninstall:
@echo "$(BOLD)ποΈ Uninstalling $(PROJECT_NAME) from $(INSTALL_DIR)...$(SGR0)"
$(SILENT)rm -f $(INSTALL_DIR)/$(PROJECT_NAME)
@echo "$(BOLD)β
Uninstallation completed$(SGR0)"
######################################
# TESTING #
######################################
# Source files with `TESTING` enabled
$(TESTS_SRC_OBJ_DIR)/%.o: $(SRC_DIR)/%.c
@echo "$(BOLD)π§ͺ Compiling $< with TESTING flags...$(SGR0)"
$(SILENT)mkdir -p $(dir $@)
$(SILENT)$(CC) $(CFLAGS) $(TESTINGFLAGS) -MMD -MP -c $< -o $@
# Test files
$(TESTS_OBJ_DIR)/%.o: $(TESTS_DIR)/%.c
@echo "$(BOLD)π§ͺ Compiling test $<...$(SGR0)"
$(SILENT)mkdir -p $(dir $@)
$(SILENT)$(CC) $(CFLAGS) $(TESTINGFLAGS) -MMD -MP -c $< -o $@
# Test targets
.PHONY: test tests test/data test/core test/parsing test/execution test/integration test/builtins test/lexer test/ast test/execute test/utf8
tests: test
test: $(TESTS_TARGET)
@echo "$(BOLD)π§ͺ Testing $(PROJECT_NAME)...$(SGR0)"
@echo "βββββββββββββββββββββββββββββββββββββββββββββββββββββ"
$(SILENT)$(TESTS_TARGET)
@echo "βββββββββββββββββββββββββββββββββββββββββββββββββββββ"
@echo "$(BOLD)β
Tests completed$(SGR0)"
test/data: $(TESTS_TARGET)
@echo "$(BOLD)π§ͺ Testing data structures...$(SGR0)"
$(SILENT)$(TESTS_TARGET) array dynamic trie utf8
test/core: $(TESTS_TARGET)
@echo "$(BOLD)π§ͺ Testing core components...$(SGR0)"
$(SILENT)$(TESTS_TARGET) environ session dirstack history
test/parsing: $(TESTS_TARGET)
@echo "$(BOLD)π§ͺ Testing parsing...$(SGR0)"
$(SILENT)$(TESTS_TARGET) lexer ast
test/execution: $(TESTS_TARGET)
@echo "$(BOLD)π§ͺ Testing execution...$(SGR0)"
$(SILENT)$(TESTS_TARGET) execute
test/integration: $(TESTS_TARGET)
@echo "$(BOLD)π§ͺ Testing integration...$(SGR0)"
$(SILENT)$(TESTS_TARGET) integration
test/builtins: $(TESTS_TARGET)
@echo "$(BOLD)π§ͺ Testing builtins...$(SGR0)"
$(SILENT)$(TESTS_TARGET) builtin
test/lexer: $(TESTS_TARGET)
$(SILENT)$(TESTS_TARGET) lexer
test/ast: $(TESTS_TARGET)
$(SILENT)$(TESTS_TARGET) ast
test/execute: $(TESTS_TARGET)
$(SILENT)$(TESTS_TARGET) execute
test/utf8: $(TESTS_TARGET)
$(SILENT)$(TESTS_TARGET) utf8
# Test binary targets
$(TESTS_TARGET): $(TESTS_OBJ) $(TESTS_SRC_OBJ)
@echo "$(BOLD)π Linking tests...$(SGR0)"
$(SILENT)$(CC) $(CFLAGS) $(TESTINGFLAGS) -o $@ $^
######################################
# PYTHON BINDINGS #
######################################
.PHONY: build/python
######################################
# FEATURE FLAG BUILDS #
######################################
# Convenience targets for common feature flag combinations
.PHONY: build/minimal build/no-history build/no-dirstack build/no-jobs build/no-aliases
build/minimal:
@echo "$(BOLD)π¨ Building minimal shell (all optional features disabled)...$(SGR0)"
@$(MAKE) clean build \
EXTRA_CFLAGS="-DTIDESH_DISABLE_JOB_CONTROL -DTIDESH_DISABLE_HISTORY -DTIDESH_DISABLE_ALIASES -DTIDESH_DISABLE_DIRSTACK -DTIDESH_DISABLE_EXPANSIONS -DTIDESH_DISABLE_PIPES -DTIDESH_DISABLE_REDIRECTIONS -DTIDESH_DISABLE_SEQUENCES -DTIDESH_DISABLE_SUBSHELLS -DTIDESH_DISABLE_COMMAND_SUBSTITUTION -DTIDESH_DISABLE_ASSIGNMENT"
build/no-history:
@echo "$(BOLD)π¨ Building without history...$(SGR0)"
@$(MAKE) clean build EXTRA_CFLAGS="-DTIDESH_DISABLE_HISTORY"
build/no-dirstack:
@echo "$(BOLD)π¨ Building without dirstack (no pushd/popd)...$(SGR0)"
@$(MAKE) clean build EXTRA_CFLAGS="-DTIDESH_DISABLE_DIRSTACK"
build/no-jobs:
@echo "$(BOLD)π¨ Building without job control...$(SGR0)"
@$(MAKE) clean build EXTRA_CFLAGS="-DTIDESH_DISABLE_JOB_CONTROL"
build/no-aliases:
@echo "$(BOLD)π¨ Building without alias expansion...$(SGR0)"
@$(MAKE) clean build EXTRA_CFLAGS="-DTIDESH_DISABLE_ALIASES"
build/no-expansions:
@echo "$(BOLD)π¨ Building without expansions...$(SGR0)"
@$(MAKE) clean build EXTRA_CFLAGS="-DTIDESH_DISABLE_EXPANSIONS"
build/no-pipes:
@echo "$(BOLD)π¨ Building without pipes...$(SGR0)"
@$(MAKE) clean build EXTRA_CFLAGS="-DTIDESH_DISABLE_PIPES"
build/no-redirections:
@echo "$(BOLD)π¨ Building without redirections...$(SGR0)"
@$(MAKE) clean build EXTRA_CFLAGS="-DTIDESH_DISABLE_REDIRECTIONS"
build/no-sequences:
@echo "$(BOLD)π¨ Building without command sequences...$(SGR0)"
@$(MAKE) clean build EXTRA_CFLAGS="-DTIDESH_DISABLE_SEQUENCES"
build/no-subshells:
@echo "$(BOLD)π¨ Building without subshells...$(SGR0)"
@$(MAKE) clean build EXTRA_CFLAGS="-DTIDESH_DISABLE_SUBSHELLS"
build/no-command-substitution:
@echo "$(BOLD)π¨ Building without command substitution...$(SGR0)"
@$(MAKE) clean build EXTRA_CFLAGS="-DTIDESH_DISABLE_COMMAND_SUBSTITUTION"
build/no-assignment:
@echo "$(BOLD)π¨ Building without assignment...$(SGR0)"
@$(MAKE) clean build EXTRA_CFLAGS="-DTIDESH_DISABLE_ASSIGNMENT"
python/stage: $(SRC) $(INCLUDES_DIR)/*.h
@echo "$(BOLD)π¦ Staging C sources for Python bindings...$(SGR0)"
$(SILENT)mkdir -p bindings/python/src bindings/python/include
$(SILENT)cp -r $(SRC_DIR)/* bindings/python/src/ 2>/dev/null || true
$(SILENT)cp -r $(INCLUDES_DIR)/* bindings/python/include/ 2>/dev/null || true
@echo "$(BOLD)β
Staging completed$(SGR0)"
build/python: python/stage
@echo "$(BOLD)π Building Python bindings...$(SGR0)"
@echo "$(BOLD) β Running build...$(SGR0)"
@if cd bindings/python && PROJECT_NAME="$(PROJECT_NAME)" RAW_VERSION="$(VERSION)" BRIEF="$(BRIEF)" PLATFORM="$(PLATFORM)" GIT_VERSION="$(GIT_VERSION)" BUILD_DATE="$(BUILD_DATE)" BUILD_TYPE="$(BUILD_TYPE)" uv build; then \
echo "$(BOLD) β Cleaning up staged sources...$(SGR0)"; \
rm -rf src include; \
echo "$(BOLD)β
Python bindings built successfully$(SGR0)"; \
else \
echo "$(BOLD)β Build failed. Keeping staged sources for debugging.$(SGR0)"; \
exit 1; \
fi