diff --git a/CMakeLists.txt b/CMakeLists.txt index fd0b920..1b791a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(fun C) +project(fun VERSION 0.2.0 LANGUAGES C) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) @@ -30,6 +30,8 @@ endif() add_executable(fun src/fun.c ) +# Provide version string to the CLI +target_compile_definitions(fun PRIVATE FUN_VERSION=\"${PROJECT_VERSION}\") target_link_libraries(fun PRIVATE fun_core) # Internal test programs @@ -48,7 +50,7 @@ add_custom_target(clean-build COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target clean COMMENT "Clean build outputs (objects, binaries) in the build directory" ) -add_custom_target(dist-clean +add_custom_target(distclean COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target clean COMMAND ${CMAKE_COMMAND} -E rm -rf ${CMAKE_BINARY_DIR}/CMakeCache.txt diff --git a/Makefile b/Makefile index a91a46d..66550b3 100644 --- a/Makefile +++ b/Makefile @@ -1,28 +1,50 @@ -all: - make clean - make fun - make fun_test - make test_opcodes +# Simple Makefile wrapper around CMake -fun: - cmake -S . -B build -DFUN_DEBUG=ON - cmake --build build --target fun +BUILD_DIR ?= build +CMAKE ?= cmake +# Default to a debug build with extra logging enabled +CMAKE_FLAGS ?= -DFUN_DEBUG=ON -fun_test: - cmake -S . -B build -DFUN_DEBUG=ON - cmake --build build --target fun_test +.PHONY: all configure build fun fun_test test_opcodes clean distclean install repl run +all: clean fun fun_test test_opcodes + +# One-time configure (re-runs harmlessly) +configure: + $(CMAKE) -S . -B $(BUILD_DIR) $(CMAKE_FLAGS) + +# Build aggregate +build: configure + $(CMAKE) --build $(BUILD_DIR) + +fun: configure + $(CMAKE) --build $(BUILD_DIR) --target fun + +fun_test: configure + $(CMAKE) --build $(BUILD_DIR) --target fun_test + +test_opcodes: configure + $(CMAKE) --build $(BUILD_DIR) --target test_opcodes + +# Clean via CMake (if configured) clean: - cmake --build build --target clean-build + $(CMAKE) --build $(BUILD_DIR) --target clean || true -# Or set a custom prefix: cmake --install build --prefix "$HOME/.local" -# Defaults: -# Binary: /usr/bin/fun -# Docs: /share/doc/fun/README.md, LICENSE -# Examples: /share/fun/examples/*.fun +# Full clean: remove the build directory entirely +distclean: + $(CMAKE) --build $(BUILD_DIR) --target distclean || true + +# Install to fixed paths defined in CMake (may require sudo): +# - Binary : /usr/bin/fun +# - Examples : /usr/share/fun/examples/*.fun +# - Docs : /usr/share/doc/fun/README.md, LICENSE install: - cmake --install build + $(CMAKE) --install $(BUILD_DIR) -test_opcodes: - cmake -S . -B build -DFUN_DEBUG=ON - cmake --build build --target test_opcodes +# Convenience: run REPL +repl: fun + ./$(BUILD_DIR)/fun + +# Convenience: run a script (usage: make run SCRIPT=examples/strings_test.fun) +run: fun + ./$(BUILD_DIR)/fun $(SCRIPT) diff --git a/src/fun.c b/src/fun.c index e74a589..234a18e 100644 --- a/src/fun.c +++ b/src/fun.c @@ -6,6 +6,10 @@ #include #include +#ifndef FUN_VERSION +#define FUN_VERSION "0.0.0-dev" +#endif + static int is_blank_line(const char *s) { for (const char *p = s; *p; ++p) { if (*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n') return 0; @@ -13,10 +17,33 @@ static int is_blank_line(const char *s) { return 1; } +static void print_usage(const char *prog) { + printf("Fun %s\n", FUN_VERSION); + printf("Usage:\n"); + printf(" %s [script.fun]\n", prog ? prog : "fun"); + printf(" %s --help | -h\n", prog ? prog : "fun"); + printf(" %s --version | -V\n", prog ? prog : "fun"); + printf("\n"); + printf("When no script is provided, a REPL starts. Submit an empty line to execute the buffer.\n"); +} + int main(int argc, char **argv) { VM vm; vm_init(&vm); + // CLI flags + if (argc > 1) { + const char *arg = argv[1]; + if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) { + print_usage(argv[0]); + return 0; + } + if (strcmp(arg, "--version") == 0 || strcmp(arg, "-V") == 0) { + printf("Fun %s\n", FUN_VERSION); + return 0; + } + } + // If a script path is provided, parse and run it if (argc > 1) { const char *path = argv[1];