diff --git a/.github/workflows/build-gems.yml b/.github/workflows/build-gems.yml index e134f1ef..59a333ad 100644 --- a/.github/workflows/build-gems.yml +++ b/.github/workflows/build-gems.yml @@ -62,28 +62,17 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Add LLVM apt Repo - run: |- - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo add-apt-repository "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-21 main" - sudo apt update - - - name: Install APT dependencies - run: xargs sudo apt-get install -y --no-install-recommends < Aptfile - - name: Setup Ruby uses: ruby/setup-ruby@v1 with: - bundler-cache: false - - - name: bundle install - run: bundle install + ruby-version: '3.4' + bundler-cache: true - name: Render Templates run: bundle exec rake templates - - name: Compile Herb - run: bundle exec rake make + - name: Vendor Prism + run: bundle exec rake prism:vendor - name: Build gem run: | @@ -128,7 +117,7 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: '3.4' - bundler-cache: false + bundler-cache: true - name: Download gem artifacts uses: actions/download-artifact@v4 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3d0764ae..b7978bdb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,14 +38,11 @@ jobs: with: bundler-cache: true - - name: bundle install - run: bundle install - - name: Render Templates run: bundle exec rake templates - name: Compile Herb - run: bundle exec rake make + run: make - name: Compile Ruby extension run: bundle exec rake compile @@ -63,7 +60,7 @@ jobs: # run: bundle exec srb tc - name: Run C tests - run: ./run_herb_tests + run: make test && ./run_herb_tests - name: Run valgrind on examples/ run: ./bin/valgrind_check_examples diff --git a/.github/workflows/java.yml b/.github/workflows/java.yml index 807c5896..d2a0526f 100644 --- a/.github/workflows/java.yml +++ b/.github/workflows/java.yml @@ -30,18 +30,8 @@ jobs: with: bundler-cache: true - - name: Render Templates - run: bundle exec rake templates - - - name: Compile Herb - run: bundle exec rake make - - - name: Build JNI library - run: make jni - working-directory: java - - - name: Compile Java classes - run: make java + - name: Build JNI library and Java classes + run: make all working-directory: java - name: Run tests diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4001a22e..f4f01e37 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -44,14 +44,13 @@ jobs: with: bundler-cache: true - - name: bundle install - run: bundle install - - - name: Render Templates - run: bundle exec rake templates + - name: Setup + run: make setup + working-directory: rust - - name: Compile Herb - run: bundle exec rake make + - name: Build Rust + run: make build + working-directory: rust - name: Check Rust formatting run: make format-check @@ -61,10 +60,6 @@ jobs: run: make lint working-directory: rust - - name: Build Rust - run: make build - working-directory: rust - - name: Run Rust tests run: make test working-directory: rust diff --git a/Makefile b/Makefile index 5a1413df..e05e1706 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,6 @@ extension_sources = $(wildcard ext/**/*.c) extension_headers = $(wildcard ext/**/*.h) extension_objects = $(extension_sources:.o) -prism_objects = $(filter-out src/main.c, $(sources)) - project_files = $(sources) $(headers) extension_files = $(extension_sources) $(extension_headers) nodejs_extension_files = $(wildcard node/**/*.cpp) $(wildcard node/**/*.h) $(wildcard node/**/*.hpp) @@ -30,37 +28,27 @@ $(shell mkdir -p $(build_dir)) os := $(shell uname -s) -prism_path = $(shell bundle show prism) -prism_include = $(prism_path)/include -prism_build = $(prism_path)/build +prism_vendor_path = vendor/prism +prism_include = $(prism_vendor_path)/include +prism_src = $(prism_vendor_path)/src -prism_flags = -I$(prism_include) -prism_ldflags = $(prism_build)/libprism.a +prism_sources = $(wildcard $(prism_src)/*.c) $(wildcard $(prism_src)/util/*.c) +prism_objects = $(prism_sources:.c=.o) +prism_static_lib = $(build_dir)/libprism.a -# Enable strict warnings -warning_flags = -Wall -Wextra -Werror -pedantic +prism_flags = -I$(prism_include) -I$(prism_src) -# Debug build (no optimizations, debug symbols) +warning_flags = -Wall -Wextra -Werror -pedantic debug_flags = -g -O0 -Wno-unused-parameter - -# Production build (optimized) production_flags = $(warning_flags) -O3 -march=native -flto - -# Shared library flags (only for `.so`/`.dylib`/`.bundle`) shared_library_flags = -fPIC - -# Default build mode (change this as needed) flags = $(warning_flags) $(debug_flags) $(prism_flags) -std=c99 - -# Separate test compilation flags test_flags = $(debug_flags) $(prism_flags) -std=gnu99 - -# Shared library build (if needed) shared_flags = $(production_flags) $(shared_library_flags) $(prism_flags) ifeq ($(os),Linux) test_cflags = $(test_flags) -I/usr/include/check - test_ldflags = -L/usr/lib/x86_64-linux-gnu -lcheck -lm -lsubunit $(prism_ldflags) + test_ldflags = -L/usr/lib/x86_64-linux-gnu -lcheck -lm -lsubunit cc = clang-21 clang_format = clang-format-21 clang_tidy = clang-tidy-21 @@ -69,7 +57,7 @@ endif ifeq ($(os),Darwin) brew_prefix := $(shell brew --prefix check) test_cflags = $(test_flags) -I$(brew_prefix)/include - test_ldflags = -L$(brew_prefix)/lib -lcheck -lm $(prism_ldflags) + test_ldflags = -L$(brew_prefix)/lib -lcheck -lm llvm_path = $(shell brew --prefix llvm@21) cc = $(llvm_path)/bin/clang clang_format = $(llvm_path)/bin/clang-format @@ -78,30 +66,42 @@ endif all: templates prism $(exec) $(lib_name) $(static_lib_name) test wasm clangd_config -$(exec): $(objects) - $(cc) $(objects) $(flags) $(ldflags) $(prism_ldflags) -o $(exec) +$(exec): $(objects) $(prism_objects) + $(cc) $(objects) $(prism_objects) $(flags) $(ldflags) -o $(exec) -$(lib_name): $(objects) - $(cc) -shared $(objects) $(shared_flags) $(ldflags) $(prism_ldflags) -o $(lib_name) - # cp $(lib_name) $(ruby_extension) +$(lib_name): $(objects) $(prism_objects) + $(cc) -shared $(objects) $(prism_objects) $(shared_flags) $(ldflags) -o $(lib_name) $(static_lib_name): $(objects) ar rcs $(static_lib_name) $(objects) +$(prism_static_lib): $(prism_objects) + ar rcs $(prism_static_lib) $(prism_objects) + +prism_lib: prism $(prism_static_lib) + +herb_lib: templates prism $(non_main_objects) + @echo "Herb objects built: $(non_main_objects)" + src/%.o: src/%.c templates $(cc) -c $(flags) -fPIC $< -o $@ +$(prism_src)/%.o: $(prism_src)/%.c prism + $(cc) -c $(flags) -fPIC $(prism_flags) $< -o $@ + +$(prism_src)/util/%.o: $(prism_src)/util/%.c prism + $(cc) -c $(flags) -fPIC $(prism_flags) $< -o $@ + test/%.o: test/%.c templates $(cc) -c $(test_cflags) $(test_flags) $(prism_flags) $< -o $@ -test: $(test_objects) $(non_main_objects) - $(cc) $(test_objects) $(non_main_objects) $(test_cflags) $(test_ldflags) -o $(test_exec) +test: $(test_objects) $(non_main_objects) $(prism_objects) + $(cc) $(test_objects) $(non_main_objects) $(prism_objects) $(test_cflags) $(test_ldflags) -o $(test_exec) clean: - rm -f $(exec) $(test_exec) $(lib_name) $(shared_lib_name) $(ruby_extension) - rm -rf $(objects) $(test_objects) $(extension_objects) lib/herb/*.bundle tmp - rm -rf $(prism_path) - rake prism:clean + rm -f $(exec) $(test_exec) $(lib_name) $(shared_lib_name) $(prism_static_lib) $(ruby_extension) + rm -rf $(objects) $(test_objects) $(prism_objects) $(extension_objects) lib/herb/*.bundle tmp + bundle exec rake prism:clean bundle_install: bundle install @@ -110,8 +110,7 @@ templates: bundle_install bundle exec rake templates prism: bundle_install - cd $(prism_path) && ruby templates/template.rb && make static && cd - - rake prism:vendor + bundle exec rake prism:vendor format: $(clang_format) -i $(project_and_extension_files) diff --git a/Rakefile b/Rakefile index 4f78fec4..ad2d6ffa 100644 --- a/Rakefile +++ b/Rakefile @@ -144,6 +144,11 @@ namespace :prism do exit 1 end + puts "Generating Prism templates..." + Dir.chdir(prism_bundle_path) do + system("ruby templates/template.rb", exception: true) + end + FileUtils.mkdir_p(prism_vendor_path) files = [ diff --git a/java/Makefile b/java/Makefile index 6a883fd1..d8933dff 100644 --- a/java/Makefile +++ b/java/Makefile @@ -24,42 +24,71 @@ endif BUILD_DIR = ../build SRC_DIR = ../src -PRISM_PATH = $(shell cd .. && bundle show prism) -PRISM_INCLUDE = $(PRISM_PATH)/include -PRISM_BUILD = $(PRISM_PATH)/build +PRISM_VENDOR_PATH = ../vendor/prism +PRISM_SRC = $(PRISM_VENDOR_PATH)/src +PRISM_INCLUDE = $(PRISM_VENDOR_PATH)/include +PRISM_LIB = $(BUILD_DIR)/libprism.a JAVAC = $(JAVA_HOME)/bin/javac JAVA_CMD = $(JAVA_HOME)/bin/java CFLAGS = -std=c99 -Wall -Wextra -fPIC -O2 -INCLUDES = -I. -I$(SRC_DIR)/include -I$(PRISM_INCLUDE) $(JNI_INCLUDES) +HERB_CFLAGS = $(CFLAGS) -Wno-unused-parameter +PRISM_CFLAGS = -std=c99 -fPIC -O2 +INCLUDES = -I. -I$(SRC_DIR)/include -I$(PRISM_INCLUDE) -I$(PRISM_SRC) $(JNI_INCLUDES) LDFLAGS = -shared -LIBS = $(PRISM_BUILD)/libprism.a -HERB_SOURCES = $(wildcard $(SRC_DIR)/*.c) $(wildcard $(SRC_DIR)/**/*.c) -HERB_OBJECTS = $(filter-out $(SRC_DIR)/main.o, $(HERB_SOURCES:.c=.o)) - -JNI_SOURCES = herb_jni.c extension_helpers.c -JNI_GENERATED_SOURCES = nodes.c error_helpers.c - -JNI_OBJECTS = $(JNI_SOURCES:.c=.o) $(JNI_GENERATED_SOURCES:.c=.o) +JNI_SOURCES = herb_jni.c extension_helpers.c nodes.c error_helpers.c +JNI_OBJECTS = $(JNI_SOURCES:.c=.o) JNI_LIB = $(BUILD_DIR)/$(JNI_LIB_PREFIX)herb_jni.$(JNI_LIB_EXT) JAVA_SOURCES = $(shell find org -name "*.java" 2>/dev/null) JAVA_TIMESTAMP = target/.java_compiled -.PHONY: all clean java jni test +.PHONY: all clean java jni setup templates prism prism_lib herb_objects help cli -all: templates jni java +all: jni java -templates: +# Setup: install deps, generate templates, vendor prism +setup: + cd .. && bundle install cd .. && bundle exec rake templates + cd .. && bundle exec rake prism:vendor -jni: $(JNI_LIB) +templates: + cd .. && bundle install && bundle exec rake templates + +prism: + cd .. && bundle install && bundle exec rake prism:vendor -$(JNI_LIB): $(JNI_OBJECTS) $(HERB_OBJECTS) +prism_lib: prism + @mkdir -p $(BUILD_DIR) + @echo "Compiling prism sources..." + @for src in $$(find $(PRISM_SRC) -name '*.c'); do \ + obj=$${src%.c}.o; \ + if [ ! -f "$$obj" ] || [ "$$src" -nt "$$obj" ]; then \ + echo " CC $$src"; \ + $(CC) $(PRISM_CFLAGS) -I$(PRISM_INCLUDE) -I$(PRISM_SRC) -c "$$src" -o "$$obj"; \ + fi; \ + done + @echo "Creating prism static library..." + ar rcs $(PRISM_LIB) $$(find $(PRISM_SRC) -name '*.o') + @echo "Built: $(PRISM_LIB)" + +herb_objects: templates + @echo "Compiling herb sources..." + @for src in $$(find $(SRC_DIR) -name '*.c' ! -name 'main.c'); do \ + obj=$${src%.c}.o; \ + if [ ! -f "$$obj" ] || [ "$$src" -nt "$$obj" ]; then \ + echo " CC $$src"; \ + $(CC) $(HERB_CFLAGS) $(INCLUDES) -c "$$src" -o "$$obj"; \ + fi; \ + done + @echo "Herb objects compiled" + +jni: prism_lib herb_objects $(JNI_OBJECTS) @mkdir -p $(BUILD_DIR) - $(CC) $(LDFLAGS) -o $@ $(JNI_OBJECTS) $(HERB_OBJECTS) $(LIBS) + $(CC) $(LDFLAGS) -o $(JNI_LIB) $(JNI_OBJECTS) $$(find $(SRC_DIR) -name '*.o' ! -name 'main.o') $(PRISM_LIB) @echo "Built JNI library: $(JNI_LIB)" %.o: %.c @@ -83,19 +112,25 @@ cli: all clean: rm -f $(JNI_OBJECTS) $(JNI_LIB) rm -rf target/ - rm -f nodes.o error_helpers.o + find $(SRC_DIR) -name '*.o' -delete 2>/dev/null || true + find $(PRISM_SRC) -name '*.o' -delete 2>/dev/null || true + rm -f $(PRISM_LIB) help: @echo "Herb Java/JNI Build System" @echo "" @echo "Targets:" - @echo " all - Build everything (templates + JNI + Java)" - @echo " templates - Generate code from ERB templates" - @echo " jni - Build JNI shared library" - @echo " java - Compile Java classes" - @echo " cli - Show CLI usage" - @echo " clean - Remove built files" - @echo " help - Show this help" + @echo " all - Build everything (JNI + Java)" + @echo " setup - Install deps, generate templates, vendor prism" + @echo " templates - Generate code from ERB templates" + @echo " prism - Vendor prism library sources" + @echo " prism_lib - Compile prism static library" + @echo " herb_objects - Compile herb source files" + @echo " jni - Build JNI shared library" + @echo " java - Compile Java classes" + @echo " cli - Show CLI usage" + @echo " clean - Remove built files" + @echo " help - Show this help" @echo "" @echo "Environment:" @echo " JAVA_HOME = $(JAVA_HOME)" diff --git a/rust/Makefile b/rust/Makefile index e462a861..cf50337a 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -5,18 +5,26 @@ BIN_NAME = herb-rust BIN_PATH = $(BUILD_DIR)/debug/$(BIN_NAME) RELEASE_BIN_PATH = $(BUILD_DIR)/release/$(BIN_NAME) -.PHONY: all build release clean test cli help templates format vendor +.PHONY: all build release clean test cli help setup templates prism format vendor -all: templates build +all: build -templates: +setup: + cd .. && bundle install cd .. && bundle exec rake templates + cd .. && bundle exec rake prism:vendor + +templates: + cd .. && bundle install && bundle exec rake templates + +prism: + cd .. && bundle install && bundle exec rake prism:vendor -build: templates +build: cargo +stable build --verbose --bin $(BIN_NAME) @echo "Built debug binary: $(BIN_PATH)" -release: templates +release: cargo build --release --bin $(BIN_NAME) @echo "Built release binary: $(RELEASE_BIN_PATH)" @@ -44,24 +52,25 @@ clean: cargo clean @echo "Cleaned Rust build artifacts" -vendor: +vendor: prism @echo "Vendoring C sources into vendor/libherb..." rm -rf vendor/ mkdir -p vendor/libherb/ mkdir -p vendor/prism/ cp -r ../src vendor/libherb/ @echo "Vendoring prism library..." - PRISM_PATH=$$(bundle show prism) && \ - cp -r "$$PRISM_PATH/src" vendor/prism/ && \ - cp -r "$$PRISM_PATH/include" vendor/prism/ + cp -r ../vendor/prism/src vendor/prism/ + cp -r ../vendor/prism/include vendor/prism/ @echo "Vendored C sources and prism successfully" help: @echo "Herb Rust Build System" @echo "" @echo "Targets:" - @echo " all - Build everything (templates + Rust)" + @echo " all - Build Rust binary" + @echo " setup - Install deps, generate templates, vendor prism" @echo " templates - Generate code from ERB templates" + @echo " prism - Vendor prism library sources" @echo " build - Build debug binary" @echo " release - Build release binary" @echo " cli - Show CLI usage"