diff --git a/.gitignore b/.gitignore index c2c8eb1..d210668 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +CMakeCache.txt .* !.editorconfig !.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt index 77cebcc..98bd6a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,24 +1,57 @@ cmake_minimum_required(VERSION 3.16) -project(fun VERSION 0.17.1 LANGUAGES C) +project(fun VERSION 0.17.2 LANGUAGES C) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) include(GNUInstallDirs) -# Optional PCSC support (enabled via -DFUN_WITH_PCSC=ON from Makefile) +# Defaults and options migrated from Makefile +# Convenience: default path to bundled stdlib +set(FUN_LIB "${CMAKE_SOURCE_DIR}/lib" CACHE PATH "Path to bundled Fun stdlib") + +# Optional: override default library directory for #include <...> lookups +# -DDEFAULT_LIB_DIR=/custom/fun/lib (trailing slash added automatically) +if(NOT DEFINED DEFAULT_LIB_DIR OR DEFAULT_LIB_DIR STREQUAL "") + if(WIN32) + set(_FUN_DEFAULT_LIB_DIR "C:/Users/Public/fun/lib") + elseif(APPLE) + set(_FUN_DEFAULT_LIB_DIR "/Library/Application Support/fun/lib") + else() + set(_FUN_DEFAULT_LIB_DIR "/usr/share/fun/lib") + endif() + set(DEFAULT_LIB_DIR "${_FUN_DEFAULT_LIB_DIR}" CACHE PATH "Default library directory for Fun stdlib (override with -DDEFAULT_LIB_DIR=...)" FORCE) +else() + set(DEFAULT_LIB_DIR "${DEFAULT_LIB_DIR}" CACHE PATH "Default library directory for Fun stdlib (override with -DDEFAULT_LIB_DIR=...)" FORCE) +endif() +# Ensure trailing slash +if(NOT DEFAULT_LIB_DIR MATCHES "/$") + set(DEFAULT_LIB_DIR "${DEFAULT_LIB_DIR}/") +endif() + +# Optional PCSC support (enabled via -DFUN_WITH_PCSC=ON) option(FUN_WITH_PCSC "Enable PCSC (pcsclite) support" OFF) +set(PCSC_LINK_LIBS "") +set(PCSC_INCLUDE_DIRS "") if(FUN_WITH_PCSC) message(STATUS "Building with PCSC support") add_definitions(-DFUN_WITH_PCSC) if(APPLE) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework PCSC") + list(APPEND PCSC_LINK_LIBS "-framework PCSC") else() - include_directories(/usr/include/PCSC) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lpcsclite") + list(APPEND PCSC_INCLUDE_DIRS "/usr/include/PCSC") + list(APPEND PCSC_LINK_LIBS pcsclite) endif() endif() +# Debug option to enable verbose parser/VM logging +option(FUN_DEBUG "Enable extra debug logging in Fun" OFF) + +# Threads (used by demos and optionally by the runtime) +if(UNIX) + find_package(Threads QUIET) +endif() + # Core VM/library sources add_library(fun_core src/bytecode.c @@ -31,13 +64,28 @@ target_include_directories(fun_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src ) -# Debug option to enable verbose parser/VM logging -option(FUN_DEBUG "Enable extra debug logging in Fun" OFF) +# Apply options to core if(FUN_DEBUG) message(STATUS "FUN_DEBUG enabled: building with verbose debug logging") target_compile_definitions(fun_core PUBLIC FUN_DEBUG=1) endif() +# Provide default stdlib directory to the runtime +target_compile_definitions(fun_core PUBLIC DEFAULT_LIB_DIR="${DEFAULT_LIB_DIR}") + +# PCSC include and link (if enabled) +if(PCSC_INCLUDE_DIRS) + target_include_directories(fun_core PRIVATE ${PCSC_INCLUDE_DIRS}) +endif() +if(PCSC_LINK_LIBS) + target_link_libraries(fun_core PUBLIC ${PCSC_LINK_LIBS}) +endif() + +# Link threads if available on UNIX +if(Threads_FOUND) + target_link_libraries(fun_core PUBLIC Threads::Threads) +endif() + # Playground / interpreter (future /usr/bin/fun) add_executable(fun src/fun.c @@ -57,8 +105,73 @@ add_executable(test_opcodes ) target_link_libraries(test_opcodes PRIVATE fun_core) -# Convenience targets for cleaning (optional) -add_custom_target(clean-build +# Convenience aggregate target (like 'build' in Makefile) +add_custom_target(build + DEPENDS fun fun_test test_opcodes +) + +# Convenience targets: repl, run, threads-demo, ops, examples +set(FUN_RUN_SCRIPT "" CACHE STRING "Script to run with the 'run' target, e.g. -DFUN_RUN_SCRIPT=examples/strings_test.fun") + +add_custom_target(repl + COMMAND $ + DEPENDS fun + USES_TERMINAL + COMMENT "Run Fun REPL" +) + +add_custom_target(run + COMMAND $ ${FUN_RUN_SCRIPT} + DEPENDS fun + USES_TERMINAL + COMMENT "Run Fun with script: ${FUN_RUN_SCRIPT}" +) + +add_custom_target(threads-demo + COMMAND ${CMAKE_COMMAND} -E echo "Running Thread class demo with FUN_LIB_DIR=${FUN_LIB}" + COMMAND ${CMAKE_COMMAND} -E env FUN_LIB_DIR="${FUN_LIB}" $ ${CMAKE_SOURCE_DIR}/examples/threads_demo.fun + DEPENDS fun + USES_TERMINAL +) + +# Python for helper scripts +find_package(Python3 QUIET COMPONENTS Interpreter) +if(Python3_Interpreter_FOUND) + set(_FUN_PY "${Python3_EXECUTABLE}") +else() + set(_FUN_PY "python3") +endif() + +add_custom_target(ops + COMMAND ${_FUN_PY} ${CMAKE_SOURCE_DIR}/scripts/check_op_includes.py --verbose + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + USES_TERMINAL + COMMENT "Verbose opcode include check" +) + +add_custom_target(ops-quiet + COMMAND ${_FUN_PY} ${CMAKE_SOURCE_DIR}/scripts/check_op_includes.py + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + USES_TERMINAL + COMMENT "Opcode include check" +) + +add_custom_target(examples + COMMAND ${CMAKE_COMMAND} -E env FUN_LIB_DIR="${FUN_LIB}" ${CMAKE_SOURCE_DIR}/scripts/run_examples.sh + DEPENDS fun + USES_TERMINAL + COMMENT "Build and run all examples" +) + +add_custom_target(run-examples + COMMAND ${CMAKE_COMMAND} -E env FUN_LIB_DIR="${FUN_LIB}" ${CMAKE_SOURCE_DIR}/scripts/run_examples.sh + DEPENDS fun + USES_TERMINAL + COMMENT "Build and run all examples" +) + +# Clean and distclean +add_custom_target(fun_clean COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target clean COMMENT "Clean build outputs (objects, binaries) in the build directory" ) diff --git a/Makefile b/Makefile deleted file mode 100644 index bcf34ec..0000000 --- a/Makefile +++ /dev/null @@ -1,118 +0,0 @@ -# Simple Makefile wrapper around CMake -BUILD_DIR ?= build -CMAKE ?= cmake -# Default to a build with extra logging disabled -CMAKE_FLAGS ?= -DFUN_DEBUG=OFF - -# Enable PCSC with: make PCSC=ON -ifeq ($(PCSC),ON) - CMAKE_FLAGS += -DFUN_WITH_PCSC=ON - CMAKE_C_FLAGS += -DFUN_WITH_PCSC - CMAKE_CXX_FLAGS += -DFUN_WITH_PCSC - ifeq ($(OS),Windows_NT) - # not supported here - else - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - CMAKE_FLAGS += -DCMAKE_EXE_LINKER_FLAGS="$(CMAKE_EXE_LINKER_FLAGS) -framework PCSC" - else - CMAKE_C_FLAGS += -I/usr/include/PCSC - CMAKE_CXX_FLAGS += -I/usr/include/PCSC - CMAKE_FLAGS += -DCMAKE_EXE_LINKER_FLAGS="$(CMAKE_EXE_LINKER_FLAGS) -lpcsclite" - endif - endif - # Apply accumulated flags to CMake call - CMAKE_FLAGS += -DCMAKE_C_FLAGS="$(CMAKE_C_FLAGS)" - CMAKE_FLAGS += -DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS)" -endif - -# Convenience: default path to bundled stdlib -FUN_LIB ?= $(CURDIR)/lib - -# Optional: override default library directory for #include <...> lookups -# Usage: make DEFAULT_LIB_DIR=/custom/fun/lib -# This injects a compiler define: -DDEFAULT_LIB_DIR="/custom/fun/lib/" -ifneq ($(strip $(DEFAULT_LIB_DIR)),) -CMAKE_FLAGS += -DCMAKE_C_FLAGS="$(CMAKE_C_FLAGS) -DDEFAULT_LIB_DIR=\\\"$(DEFAULT_LIB_DIR)/\\\"" -CMAKE_FLAGS += -DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS) -DDEFAULT_LIB_DIR=\\\"$(DEFAULT_LIB_DIR)/\\\"" -else -# Provide OS-specific defaults for Windows, macOS, Linux/Unix -ifeq ($(OS),Windows_NT) - CMAKE_FLAGS += -DCMAKE_C_FLAGS="$(CMAKE_C_FLAGS) -DDEFAULT_LIB_DIR=\\\"C:/Users/Public/fun/lib/\\\"" - CMAKE_FLAGS += -DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS) -DDEFAULT_LIB_DIR=\\\"C:/Users/Public/fun/lib/\\\"" -else - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - CMAKE_FLAGS += -DCMAKE_C_FLAGS="$(CMAKE_C_FLAGS) -DDEFAULT_LIB_DIR=\\\"/Library/Application Support/fun/lib/\\\"" - CMAKE_FLAGS += -DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS) -DDEFAULT_LIB_DIR=\\\"/Library/Application Support/fun/lib/\\\"" - CMAKE_FLAGS += -DCMAKE_EXE_LINKER_FLAGS="$(CMAKE_EXE_LINKER_FLAGS) -pthread" - else - CMAKE_FLAGS += -DCMAKE_C_FLAGS="$(CMAKE_C_FLAGS) -DDEFAULT_LIB_DIR=\\\"/usr/share/fun/lib/\\\"" - CMAKE_FLAGS += -DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS) -DDEFAULT_LIB_DIR=\\\"/usr/share/fun/lib/\\\"" - CMAKE_FLAGS += -DCMAKE_EXE_LINKER_FLAGS="$(CMAKE_EXE_LINKER_FLAGS) -pthread" - endif -endif -endif - -.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_DIR) --target clean || true - -# 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_DIR) - -# 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) - -# Run the OO threading demo with FUN_LIB_DIR set -threads-demo: fun - @echo "Running Thread class demo with FUN_LIB_DIR=$(FUN_LIB)" - FUN_LIB_DIR="$(FUN_LIB)" ./$(BUILD_DIR)/fun examples/threads_demo.fun - -# Additional convenience targets -.PHONY: verify-ops examples run-examples threads-demo ops ops-quiet - -# Shorthand aliases for opcode include check -ops: - @./scripts/check_op_includes.py --verbose - -ops-quiet: - @./scripts/check_op_includes.py - -# Build and run all examples (searches for the fun binary automatically) -examples run-examples: fun - @FUN_LIB_DIR="$(FUN_LIB)" ./scripts/run_examples.sh diff --git a/README.md b/README.md index 3febb58..a482381 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ This requires Cygwin to be installed and configured. I will not cover this here. - [GNU](https://gnu.org/)/[Linux](https://kernel.org/) ([Arch](https://archlinux.org/)/[Artix](https://artixlinux.org/), [Debian](https://www.debian.org/)) using [GCC](https://gcc.gnu.org/) and the [GNU C library](https://www.gnu.org/software/libc/) ([glibc](https://en.wikipedia.org/wiki/Glibc)) - GNU/Linux ([Alpine](https://alpinelinux.org/)) using GCC and the [musl libc](https://musl.libc.org/) - [FreeBSD](https://www.freebsd.org/) using [Clang](https://clang.llvm.org/) and the [BSD libc](https://en.wikipedia.org/wiki/C_standard_library#BSD_libc) -- [Windows](https://en.wikipedia.org/wiki/Microsoft_Windows) using [MinGW](https://en.wikipedia.org/wiki/MinGW) +- [Windows](https://en.wikipedia.org/wiki/Microsoft_Windows){:class="ext"} using [Cygwin](https://www.cygwin.com/){:class="ext"} and GCC. ### Other systems