From 501be417e847e9aa8f4b2af2a1edbc4d049614e7 Mon Sep 17 00:00:00 2001 From: hanez Date: Thu, 15 Jan 2026 22:57:54 +0100 Subject: [PATCH] Massive CMake refactoring... No code changes. (0.37.55) --- .gitignore | 2 +- CMakeLists.txt | 577 +----------------------------- cmake/Dependencies.cmake | 14 + cmake/Extensions/CURL.cmake | 17 + cmake/Extensions/Extensions.cmake | 39 ++ cmake/Extensions/INI.cmake | 27 ++ cmake/Extensions/JSON.cmake | 17 + cmake/Extensions/LIBSQL.cmake | 27 ++ cmake/Extensions/NOTCURSES.cmake | 20 ++ cmake/Extensions/PCRE2.cmake | 17 + cmake/Extensions/PCSC.cmake | 13 + cmake/Extensions/REPL.cmake | 2 + cmake/Extensions/SQLITE.cmake | 22 ++ cmake/Extensions/TCLTK.cmake | 46 +++ cmake/Extensions/XML2.cmake | 25 ++ cmake/Options.cmake | 35 ++ cmake/Platform/Linux.cmake | 24 ++ cmake/Platform/Windows.cmake | 10 + cmake/Platform/macOS.cmake | 10 + cmake/Targets.cmake | 130 +++++++ make | 2 + src/CMakeLists.txt | 5 + 22 files changed, 513 insertions(+), 568 deletions(-) create mode 100644 cmake/Dependencies.cmake create mode 100644 cmake/Extensions/CURL.cmake create mode 100644 cmake/Extensions/Extensions.cmake create mode 100644 cmake/Extensions/INI.cmake create mode 100644 cmake/Extensions/JSON.cmake create mode 100644 cmake/Extensions/LIBSQL.cmake create mode 100644 cmake/Extensions/NOTCURSES.cmake create mode 100644 cmake/Extensions/PCRE2.cmake create mode 100644 cmake/Extensions/PCSC.cmake create mode 100644 cmake/Extensions/REPL.cmake create mode 100644 cmake/Extensions/SQLITE.cmake create mode 100644 cmake/Extensions/TCLTK.cmake create mode 100644 cmake/Extensions/XML2.cmake create mode 100644 cmake/Options.cmake create mode 100644 cmake/Platform/Linux.cmake create mode 100644 cmake/Platform/Windows.cmake create mode 100644 cmake/Platform/macOS.cmake create mode 100644 cmake/Targets.cmake create mode 100644 src/CMakeLists.txt diff --git a/.gitignore b/.gitignore index a28170a..ceee666 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ CMakeCache.txt !.gitignore .venv build* -cmake* +cmake_install.cmake database.sqlite demo_* dist/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 39899b5..f8ef705 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,543 +1,15 @@ cmake_minimum_required(VERSION 3.10) -project(fun VERSION 0.37.54 LANGUAGES C) +project(fun VERSION 0.37.55 LANGUAGES C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) include(GNUInstallDirs) -# 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() - -# Optional: build using musl libc instead of glibc on Linux (OFF by default) -# Note: Switching CMAKE_C_COMPILER must happen before the first project() call. -option(FUN_USE_MUSL "Use musl libc toolchain when available (Linux only)" OFF) - -if(FUN_USE_MUSL AND UNIX AND NOT APPLE) - # Try to find a musl toolchain wrapper - find_program(_FUN_MUSL_CC NAMES musl-gcc musl-clang) - if(_FUN_MUSL_CC) - message(STATUS "FUN_USE_MUSL=ON: using musl toolchain: ${_FUN_MUSL_CC}") - # Force C compiler to musl wrapper before project() so the whole toolchain is configured accordingly - set(CMAKE_C_COMPILER "${_FUN_MUSL_CC}" CACHE FILEPATH "C compiler" FORCE) - set(FUN_LIBC "musl" CACHE STRING "Selected C library") - else() - message(WARNING "FUN_USE_MUSL=ON but no musl toolchain (musl-gcc or musl-clang) found. Falling back to default compiler (likely glibc).") - set(FUN_LIBC "glibc" CACHE STRING "Selected C library") - endif() -else() - # Default remains the system toolchain (typically glibc on Linux) - set(FUN_LIBC "glibc" CACHE STRING "Selected C library") -endif() - -# Expose a preprocessor macro indicating selected C library -if(FUN_LIBC STREQUAL "musl") - add_definitions(-DFUN_LIBC_MUSL) -else() - add_definitions(-DFUN_LIBC_GLIBC) -endif() - -# Optional: build statically linked executables -# When enabled, prefer static libraries for all dependencies and request -# fully static linking for executables where the platform/toolchain allows it. -option(FUN_LINK_STATIC "Link fun and tests fully static where possible" OFF) - -if(FUN_LINK_STATIC) - message(STATUS "Building Fun statically linked") - # Prefer static libraries for all add_library without explicit type - set(BUILD_SHARED_LIBS OFF) - - # Make pkg-config choose static libs - set(PKG_CONFIG_USE_STATIC_LIBS ON) - - # Hint find_library to choose static archives first on Unix (not macOS) - # Prefer .a but still allow falling back to shared if static is unavailable. - if(UNIX AND NOT APPLE) - set(CMAKE_FIND_LIBRARY_SUFFIXES .a;.so;.so.0;.so.1) - endif() - - # Toolchain-specific static link flags - # Use a "mostly static" approach by default to avoid requiring static - # variants of every system/third-party library. This keeps libgcc and - # libstdc++ static while allowing shared deps when needed. - if(UNIX AND NOT APPLE AND CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") - set(_FUN_STATIC_LINK_FLAGS -static-libgcc -static-libstdc++) - endif() - - # On MSVC, prefer the static runtime - if(MSVC) - foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE - CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_MINSIZEREL) - if(DEFINED ${flag_var}) - string(REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") - endif() - endforeach() - endif() -endif() - -# Optional Tcl/Tk GUI support (embedded interpreter) -option(FUN_WITH_TCLTK "Enable Tcl/Tk GUI support" OFF) -set(TCL_INCLUDE_DIRS "") -set(TCL_LINK_LIBS "") -if(FUN_WITH_TCLTK) - message(STATUS "Building with Tcl/Tk support") - add_definitions(-DFUN_WITH_TCLTK) - # Try pkg-config first - find_package(PkgConfig QUIET) - if(PKG_CONFIG_FOUND) - pkg_check_modules(TCL QUIET tcl) - pkg_check_modules(TK QUIET tk) - endif() - if(TCL_FOUND OR TK_FOUND) - if(TCL_FOUND) - list(APPEND TCL_INCLUDE_DIRS ${TCL_INCLUDE_DIRS} ${TCL_INCLUDE_DIRS}) - list(APPEND TCL_LINK_LIBS ${TCL_LINK_LIBS} ${TCL_LIBRARIES}) - endif() - if(TK_FOUND) - list(APPEND TCL_INCLUDE_DIRS ${TCL_INCLUDE_DIRS} ${TK_INCLUDE_DIRS}) - list(APPEND TCL_LINK_LIBS ${TCL_LINK_LIBS} ${TK_LIBRARIES}) - endif() - if(TCL_INCLUDE_DIRS) - include_directories(${TCL_INCLUDE_DIRS}) - endif() - else() - # Fallbacks by platform (best-effort) - find_path(TCL_INCLUDE_DIR tcl.h PATH_SUFFIXES tcl8.7 tcl8.6 include) - find_library(TCL_LIB NAMES tcl8.7 tcl8.6 tcl) - find_library(TK_LIB NAMES tk8.7 tk8.6 tk) - if(TCL_INCLUDE_DIR) - list(APPEND TCL_INCLUDE_DIRS ${TCL_INCLUDE_DIR}) - include_directories(${TCL_INCLUDE_DIR}) - endif() - if(TCL_LIB) - list(APPEND TCL_LINK_LIBS ${TCL_LIB}) - endif() - if(TK_LIB) - list(APPEND TCL_LINK_LIBS ${TK_LIB}) - endif() - if(APPLE) - # On macOS additional frameworks are usually not required; Homebrew libs suffice - elseif(WIN32) - # Typical Windows GUI libs - list(APPEND TCL_LINK_LIBS user32 gdi32 comctl32) - else() - # X11 may be required on some Linux setups - find_package(X11 QUIET) - if(X11_FOUND) - include_directories(${X11_INCLUDE_DIR}) - list(APPEND TCL_LINK_LIBS ${X11_LIBRARIES}) - endif() - endif() - if(NOT TCL_LINK_LIBS) - message(WARNING "Tcl/Tk libraries not found via pkg-config or fallbacks. FUN_WITH_TCLTK is enabled, but linking may fail.") - endif() - endif() -endif() -# Ensure trailing slash -if(NOT DEFAULT_LIB_DIR MATCHES "/$") - set(DEFAULT_LIB_DIR "${DEFAULT_LIB_DIR}/") -endif() - -# Optional SQLite support -option(FUN_WITH_SQLITE "Enable SQLite (sqlite3) support" OFF) -set(SQLITE3_INCLUDE_DIRS "") -set(SQLITE3_LINK_LIBS "") -if(FUN_WITH_SQLITE) - message(STATUS "Building with SQLite support") - add_definitions(-DFUN_WITH_SQLITE) - find_package(PkgConfig QUIET) - if(PKG_CONFIG_FOUND) - pkg_check_modules(SQLITE3 QUIET sqlite3) - endif() - if(SQLITE3_FOUND) - list(APPEND SQLITE3_INCLUDE_DIRS ${SQLITE3_INCLUDE_DIRS} ${SQLITE3_INCLUDE_DIRS}) - list(APPEND SQLITE3_LINK_LIBS ${SQLITE3_LINK_LIBS} ${SQLITE3_LIBRARIES}) - include_directories(${SQLITE3_INCLUDE_DIRS}) - else() - find_library(SQLITE3_LIB sqlite3) - if(SQLITE3_LIB) - list(APPEND SQLITE3_LINK_LIBS ${SQLITE3_LIB}) - else() - message(FATAL_ERROR "sqlite3 not found. Install sqlite3 (dev headers) or disable FUN_WITH_SQLITE.") - endif() - endif() -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) - list(APPEND PCSC_LINK_LIBS "-framework PCSC") - else() - list(APPEND PCSC_INCLUDE_DIRS "/usr/include/PCSC") - list(APPEND PCSC_LINK_LIBS pcsclite) - endif() -endif() - -# Optional JSON (json-c) support -option(FUN_WITH_JSON "Enable JSON (json-c) support" OFF) -set(JSONC_INCLUDE_DIRS "") -set(JSONC_LINK_LIBS "") -if(FUN_WITH_JSON) - message(STATUS "Building with JSON (json-c) support") - add_definitions(-DFUN_WITH_JSON) - find_package(PkgConfig QUIET) - if(PKG_CONFIG_FOUND) - pkg_check_modules(JSONC QUIET json-c) - endif() - if(JSONC_FOUND) - list(APPEND JSONC_INCLUDE_DIRS ${JSONC_INCLUDE_DIRS} ${JSONC_INCLUDE_DIRS}) - list(APPEND JSONC_LINK_LIBS ${JSONC_LINK_LIBS} ${JSONC_LIBRARIES}) - include_directories(${JSONC_INCLUDE_DIRS}) - else() - # Fallback: try plain -ljson-c - list(APPEND JSONC_LINK_LIBS json-c) - endif() -endif() - -# Optional INI (iniparser 4.2.6) support -option(FUN_WITH_INI "Enable INI (iniparser) support" OFF) -set(INIPARSER_INCLUDE_DIRS "") -set(INIPARSER_LINK_LIBS "") -if(FUN_WITH_INI) - message(STATUS "Building with INI (iniparser) support") - add_definitions(-DFUN_WITH_INI) - find_package(PkgConfig QUIET) - if(PKG_CONFIG_FOUND) - pkg_check_modules(INIPARSER QUIET iniparser) - endif() - if(INIPARSER_FOUND) - list(APPEND INIPARSER_INCLUDE_DIRS ${INIPARSER_INCLUDE_DIRS} ${INIPARSER_INCLUDE_DIRS}) - list(APPEND INIPARSER_LINK_LIBS ${INIPARSER_LINK_LIBS} ${INIPARSER_LIBRARIES}) - else() - # Fallback: try to locate headers and library manually - find_path(INIPARSER_INCLUDE_DIR iniparser.h) - find_library(INIPARSER_LIB NAMES iniparser) - if(INIPARSER_INCLUDE_DIR) - list(APPEND INIPARSER_INCLUDE_DIRS ${INIPARSER_INCLUDE_DIR}) - endif() - if(INIPARSER_LIB) - list(APPEND INIPARSER_LINK_LIBS ${INIPARSER_LIB}) - endif() - if(NOT INIPARSER_INCLUDE_DIRS OR NOT INIPARSER_LINK_LIBS) - message(FATAL_ERROR "iniparser not found. Install iniparser (>=4.2.6) or disable FUN_WITH_INI.") - endif() - endif() -endif() - -# Optional XML (libxml2) support -option(FUN_WITH_XML2 "Enable XML (libxml2) support" OFF) -set(LIBXML2_INCLUDE_DIRS "") -set(LIBXML2_LINK_LIBS "") -if(FUN_WITH_XML2) - message(STATUS "Building with XML (libxml2) support") - add_definitions(-DFUN_WITH_XML2) - find_package(PkgConfig QUIET) - if(PKG_CONFIG_FOUND) - pkg_check_modules(LIBXML2 QUIET libxml-2.0) - endif() - if(LIBXML2_FOUND) - list(APPEND LIBXML2_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIRS}) - list(APPEND LIBXML2_LINK_LIBS ${LIBXML2_LINK_LIBS} ${LIBXML2_LIBRARIES}) - include_directories(${LIBXML2_INCLUDE_DIRS}) - else() - find_library(LIBXML2_LIB NAMES xml2 libxml2) - if(LIBXML2_LIB) - list(APPEND LIBXML2_LINK_LIBS ${LIBXML2_LIB}) - # Common system include location for libxml2 headers - if(EXISTS "/usr/include/libxml2") - list(APPEND LIBXML2_INCLUDE_DIRS "/usr/include/libxml2") - include_directories(${LIBXML2_INCLUDE_DIRS}) - endif() - else() - message(FATAL_ERROR "libxml2 not found. Install libxml2 (dev headers) or disable FUN_WITH_XML2.") - endif() - endif() - # As a robust fallback, add standard system include path for libxml2 if present - if(EXISTS "/usr/include/libxml2") - include_directories("/usr/include/libxml2") - endif() -endif() - -# Optional libsql support (independent from SQLite) -option(FUN_WITH_LIBSQL "Enable libsql (Turso) client support" OFF) -set(LIBSQL_INCLUDE_DIRS "") -set(LIBSQL_LINK_LIBS "") -if(FUN_WITH_LIBSQL) - message(STATUS "Building with libSQL support") - add_definitions(-DFUN_WITH_LIBSQL) - # Try pkg-config for libsql first; some systems expose libsql-client - find_package(PkgConfig QUIET) - if(PKG_CONFIG_FOUND) - pkg_check_modules(LIBSQL QUIET libsql) - if(NOT LIBSQL_FOUND) - pkg_check_modules(LIBSQL_CLIENT QUIET libsql-client) - if(LIBSQL_CLIENT_FOUND) - set(LIBSQL_FOUND TRUE) - set(LIBSQL_INCLUDE_DIRS ${LIBSQL_CLIENT_INCLUDE_DIRS}) - set(LIBSQL_LINK_LIBS ${LIBSQL_CLIENT_LIBRARIES}) - endif() - endif() - endif() - if(LIBSQL_FOUND) - include_directories(${LIBSQL_INCLUDE_DIRS}) - else() - # Fallback: many libsql deployments provide a sqlite3-compatible client lib - # so try linking against sqlite3 as a compatibility layer. - find_library(LIBSQL_LIB sqlite3) - if(LIBSQL_LIB) - list(APPEND LIBSQL_LINK_LIBS ${LIBSQL_LIB}) - else() - message(FATAL_ERROR "libsql not found. Install libsql (or compatible sqlite3 client) or disable FUN_WITH_LIBSQL.") - endif() - endif() -endif() - -# Optional PCRE2 support -option(FUN_WITH_PCRE2 "Enable PCRE2 (Perl Compatible Regular Expressions) support" OFF) -set(PCRE2_INCLUDE_DIRS "") -set(PCRE2_LINK_LIBS "") -if(FUN_WITH_PCRE2) - message(STATUS "Building with PCRE2 support") - add_definitions(-DFUN_WITH_PCRE2) - # Try pkg-config first - find_package(PkgConfig QUIET) - if(PKG_CONFIG_FOUND) - pkg_check_modules(PCRE2 QUIET libpcre2-8) - endif() - if(PCRE2_FOUND) - list(APPEND PCRE2_INCLUDE_DIRS ${PCRE2_INCLUDE_DIRS} ${PCRE2_INCLUDE_DIRS}) - list(APPEND PCRE2_LINK_LIBS ${PCRE2_LINK_LIBS} ${PCRE2_LIBRARIES}) - include_directories(${PCRE2_INCLUDE_DIRS}) - else() - # Fallback: common defaults - list(APPEND PCRE2_LINK_LIBS pcre2-8) - endif() -endif() - -# Optional CURL (libcurl) support -option(FUN_WITH_CURL "Enable libcurl HTTP client support" OFF) -set(CURL_INCLUDE_DIRS "") -set(CURL_LINK_LIBS "") -if(FUN_WITH_CURL) - message(STATUS "Building with libcurl support") - add_definitions(-DFUN_WITH_CURL) - find_package(PkgConfig QUIET) - if(PKG_CONFIG_FOUND) - pkg_check_modules(LIBCURL QUIET libcurl) - endif() - if(LIBCURL_FOUND) - list(APPEND CURL_INCLUDE_DIRS ${LIBCURL_INCLUDE_DIRS}) - list(APPEND CURL_LINK_LIBS ${LIBCURL_LIBRARIES}) - include_directories(${CURL_INCLUDE_DIRS}) - else() - list(APPEND CURL_LINK_LIBS curl) - 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 - src/parser.c - src/value.c - src/vm.c -) - -target_include_directories(fun_core PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src -) - -# Apply options to core -if(FUN_DEBUG) - message(STATUS "FUN_DEBUG enabled: building with verbose debug logging") - target_compile_definitions(fun_core PUBLIC FUN_VERSION="${PROJECT_VERSION}") - target_compile_definitions(fun_core PUBLIC FUN_DEBUG=1) -endif() - -# Provide default stdlib directory to the runtime -target_compile_definitions(fun_core PUBLIC FUN_VERSION="${PROJECT_VERSION}") -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() - -# json-c include and link (if enabled) -if(JSONC_INCLUDE_DIRS) - target_include_directories(fun_core PRIVATE ${JSONC_INCLUDE_DIRS}) -endif() -if(JSONC_LINK_LIBS) - target_link_libraries(fun_core PUBLIC ${JSONC_LINK_LIBS}) -endif() - -# pcre2 include and link (if enabled) -if(PCRE2_INCLUDE_DIRS) - target_include_directories(fun_core PRIVATE ${PCRE2_INCLUDE_DIRS}) -endif() -if(PCRE2_LINK_LIBS) - target_link_libraries(fun_core PUBLIC ${PCRE2_LINK_LIBS}) -endif() - -# libcurl include and link (if enabled) -if(CURL_INCLUDE_DIRS) - target_include_directories(fun_core PRIVATE ${CURL_INCLUDE_DIRS}) -endif() -if(CURL_LINK_LIBS) - target_link_libraries(fun_core PUBLIC ${CURL_LINK_LIBS}) -endif() - -# sqlite3 include and link (if enabled) -if(SQLITE3_INCLUDE_DIRS) - target_include_directories(fun_core PRIVATE ${SQLITE3_INCLUDE_DIRS}) -endif() -if(SQLITE3_LINK_LIBS) - target_link_libraries(fun_core PUBLIC ${SQLITE3_LINK_LIBS}) -endif() - -# iniparser include and link (if enabled) -if(INIPARSER_INCLUDE_DIRS) - target_include_directories(fun_core PRIVATE ${INIPARSER_INCLUDE_DIRS}) -endif() -if(INIPARSER_LINK_LIBS) - target_link_libraries(fun_core PUBLIC ${INIPARSER_LINK_LIBS}) -endif() - -# libsql include and link (if enabled) -if(LIBSQL_INCLUDE_DIRS) - target_include_directories(fun_core PRIVATE ${LIBSQL_INCLUDE_DIRS}) -endif() -if(LIBSQL_LINK_LIBS) - target_link_libraries(fun_core PUBLIC ${LIBSQL_LINK_LIBS}) -endif() - -# libxml2 include and link (if enabled) -if(LIBXML2_INCLUDE_DIRS) - target_include_directories(fun_core PRIVATE ${LIBXML2_INCLUDE_DIRS}) -endif() -if(LIBXML2_LINK_LIBS) - target_link_libraries(fun_core PUBLIC ${LIBXML2_LINK_LIBS}) -endif() -if(FUN_WITH_XML2) - if(EXISTS "/usr/include/libxml2") - target_include_directories(fun_core PRIVATE "/usr/include/libxml2") - endif() -endif() - -# Tcl/Tk include and link (if enabled) -if(TCL_INCLUDE_DIRS) - target_include_directories(fun_core PRIVATE ${TCL_INCLUDE_DIRS}) -endif() -if(TCL_LINK_LIBS) - target_link_libraries(fun_core PUBLIC ${TCL_LINK_LIBS}) -endif() - -# Link threads if available on UNIX -if(Threads_FOUND) - target_link_libraries(fun_core PUBLIC Threads::Threads) -endif() - -# Link libm for C99 math functions if available -find_library(M_LIB m) -if(M_LIB) - target_link_libraries(fun_core PUBLIC ${M_LIB}) -endif() - -# Optional Notcurses TUI support (per-opcode files under src/vm/notcurses) -option(FUN_WITH_NOTCURSES "Enable Notcurses TUI support" OFF) -set(NOTCURSES_INCLUDE_DIRS "") -set(NOTCURSES_LINK_LIBS "") -if(FUN_WITH_NOTCURSES) - message(STATUS "FUN_WITH_NOTCURSES=ON: enabling Notcurses TUI ops") - add_definitions(-DFUN_WITH_NOTCURSES) - find_package(PkgConfig QUIET) - if(PkgConfig_FOUND) - # Prefer full 'notcurses', fall back to 'notcurses-core' - pkg_check_modules(NOTCURSES QUIET notcurses) - if(NOT NOTCURSES_FOUND) - pkg_check_modules(NOTCURSES QUIET notcurses-core) - endif() - endif() - if(NOTCURSES_FOUND) - list(APPEND NOTCURSES_INCLUDE_DIRS ${NOTCURSES_INCLUDE_DIRS} ${NOTCURSES_INCLUDE_DIRS}) - list(APPEND NOTCURSES_LINK_LIBS ${NOTCURSES_LINK_LIBS} ${NOTCURSES_LIBRARIES}) - include_directories(${NOTCURSES_INCLUDE_DIRS}) - else() - message(FATAL_ERROR "FUN_WITH_NOTCURSES=ON but notcurses was not found via pkg-config (tried notcurses and notcurses-core). Install notcurses or configure with -DFUN_WITH_NOTCURSES=OFF") - endif() -endif() - -# notcurses include and link (if enabled) -if(NOTCURSES_INCLUDE_DIRS) - target_include_directories(fun_core PRIVATE ${NOTCURSES_INCLUDE_DIRS}) -endif() -if(NOTCURSES_LINK_LIBS) - target_link_libraries(fun_core PUBLIC ${NOTCURSES_LINK_LIBS}) -endif() - -# Interpreter /usr/bin/fun -option(FUN_WITH_REPL "Enable interactive REPL in the fun CLI" OFF) -add_executable(fun - src/fun.c -) -# Provide version string to the CLI -if(FUN_WITH_REPL) - # Enable REPL compilation path and add the REPL source - target_compile_definitions(fun PRIVATE FUN_WITH_REPL=1) - target_sources(fun PRIVATE src/repl.c) -endif() -target_link_libraries(fun PRIVATE fun_core) - -# Internal test programs -add_executable(fun_test - src/fun_test.c -) -target_link_libraries(fun_test PRIVATE fun_core) - -add_executable(test_opcodes - src/test_opcodes.c -) -target_link_libraries(test_opcodes PRIVATE fun_core) - -# If static linking is requested, apply linker flags to executables -if(FUN_LINK_STATIC AND DEFINED _FUN_STATIC_LINK_FLAGS) - foreach(tgt fun fun_test test_opcodes) - if(TARGET ${tgt}) - target_link_options(${tgt} PRIVATE ${_FUN_STATIC_LINK_FLAGS}) - endif() - endforeach() -endif() +include(${CMAKE_SOURCE_DIR}/cmake/Options.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Dependencies.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/Extensions.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Targets.cmake) # Convenience aggregate target (like 'build' in Makefile) add_custom_target(build @@ -549,11 +21,11 @@ set(FUN_RUN_SCRIPT "" CACHE STRING "Script to run with the 'run' target, e.g. -D if(FUN_WITH_REPL) add_custom_target(repl - COMMAND $ - DEPENDS fun - USES_TERMINAL - COMMENT "Run Fun REPL" -) + COMMAND $ + DEPENDS fun + USES_TERMINAL + COMMENT "Run Fun REPL" + ) endif() add_custom_target(run @@ -563,21 +35,6 @@ add_custom_target(run 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} @@ -592,20 +49,6 @@ add_custom_target(ops-quiet COMMENT "Opcode include check" ) -add_custom_target(examples - COMMAND ${CMAKE_COMMAND} -E env FUN_LIB_DIR="${FUN_LIB}" FUN_WITH_INI=$,1,0> ${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}" FUN_WITH_INI=$,1,0> ${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 diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake new file mode 100644 index 0000000..6546c4c --- /dev/null +++ b/cmake/Dependencies.cmake @@ -0,0 +1,14 @@ +# Common dependency discovery used across the project + +# Threads (used by demos and optionally by the runtime) +if(UNIX) + find_package(Threads QUIET) +endif() + +# 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() diff --git a/cmake/Extensions/CURL.cmake b/cmake/Extensions/CURL.cmake new file mode 100644 index 0000000..bbce9da --- /dev/null +++ b/cmake/Extensions/CURL.cmake @@ -0,0 +1,17 @@ +# CURL +option(FUN_WITH_CURL "Enable libcurl HTTP client support" OFF) +set(CURL_INCLUDE_DIRS "") +set(CURL_LINK_LIBS "") +if(FUN_WITH_CURL) + add_definitions(-DFUN_WITH_CURL) + find_package(PkgConfig QUIET) + if(PKG_CONFIG_FOUND) + pkg_check_modules(LIBCURL QUIET libcurl) + endif() + if(LIBCURL_FOUND) + list(APPEND CURL_INCLUDE_DIRS ${LIBCURL_INCLUDE_DIRS}) + list(APPEND CURL_LINK_LIBS ${LIBCURL_LIBRARIES}) + else() + list(APPEND CURL_LINK_LIBS curl) + endif() +endif() diff --git a/cmake/Extensions/Extensions.cmake b/cmake/Extensions/Extensions.cmake new file mode 100644 index 0000000..070f410 --- /dev/null +++ b/cmake/Extensions/Extensions.cmake @@ -0,0 +1,39 @@ +# Toggleable optional features live in per-file modules. These populate *_INCLUDE_DIRS and *_LINK_LIBS +list(PREPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules") + +# Helper to report feature status nicely +function(_fun_print_feature name flag) + if(${flag}) + message(STATUS " ${name}: ENABLED") + else() + message(STATUS " ${name}: DISABLED") + endif() +endfunction() + +# Include each extension module +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/TCLTK.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/SQLITE.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/PCSC.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/JSON.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/INI.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/XML2.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/LIBSQL.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/PCRE2.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/CURL.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/NOTCURSES.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Extensions/REPL.cmake) + +# Summary of extension toggles +message(STATUS "---- Fun extension summary ----") +_fun_print_feature("Tcl/Tk (FUN_WITH_TCLTK)" FUN_WITH_TCLTK) +_fun_print_feature("SQLite (FUN_WITH_SQLITE)" FUN_WITH_SQLITE) +_fun_print_feature("PCSC (FUN_WITH_PCSC)" FUN_WITH_PCSC) +_fun_print_feature("JSON-C (FUN_WITH_JSON)" FUN_WITH_JSON) +_fun_print_feature("INI/iniparser (FUN_WITH_INI)" FUN_WITH_INI) +_fun_print_feature("libxml2 (FUN_WITH_XML2)" FUN_WITH_XML2) +_fun_print_feature("libsql (FUN_WITH_LIBSQL)" FUN_WITH_LIBSQL) +_fun_print_feature("PCRE2 (FUN_WITH_PCRE2)" FUN_WITH_PCRE2) +_fun_print_feature("libcurl (FUN_WITH_CURL)" FUN_WITH_CURL) +_fun_print_feature("Notcurses (FUN_WITH_NOTCURSES)" FUN_WITH_NOTCURSES) +_fun_print_feature("REPL (FUN_WITH_REPL)" FUN_WITH_REPL) +message(STATUS "--------------------------------") diff --git a/cmake/Extensions/INI.cmake b/cmake/Extensions/INI.cmake new file mode 100644 index 0000000..1fe6a4c --- /dev/null +++ b/cmake/Extensions/INI.cmake @@ -0,0 +1,27 @@ +# INI (iniparser) +option(FUN_WITH_INI "Enable INI (iniparser) support" OFF) +set(INIPARSER_INCLUDE_DIRS "") +set(INIPARSER_LINK_LIBS "") +if(FUN_WITH_INI) + add_definitions(-DFUN_WITH_INI) + find_package(PkgConfig QUIET) + if(PKG_CONFIG_FOUND) + pkg_check_modules(INIPARSER QUIET iniparser) + endif() + if(INIPARSER_FOUND) + list(APPEND INIPARSER_INCLUDE_DIRS ${INIPARSER_INCLUDE_DIRS} ${INIPARSER_INCLUDE_DIRS}) + list(APPEND INIPARSER_LINK_LIBS ${INIPARSER_LINK_LIBS} ${INIPARSER_LIBRARIES}) + else() + find_path(INIPARSER_INCLUDE_DIR iniparser.h) + find_library(INIPARSER_LIB NAMES iniparser) + if(INIPARSER_INCLUDE_DIR) + list(APPEND INIPARSER_INCLUDE_DIRS ${INIPARSER_INCLUDE_DIR}) + endif() + if(INIPARSER_LIB) + list(APPEND INIPARSER_LINK_LIBS ${INIPARSER_LIB}) + endif() + if(NOT INIPARSER_INCLUDE_DIRS OR NOT INIPARSER_LINK_LIBS) + message(FATAL_ERROR "iniparser not found. Install iniparser (>=4.2.6) or disable FUN_WITH_INI.") + endif() + endif() +endif() diff --git a/cmake/Extensions/JSON.cmake b/cmake/Extensions/JSON.cmake new file mode 100644 index 0000000..b640793 --- /dev/null +++ b/cmake/Extensions/JSON.cmake @@ -0,0 +1,17 @@ +# JSON (json-c) +option(FUN_WITH_JSON "Enable JSON (json-c) support" OFF) +set(JSONC_INCLUDE_DIRS "") +set(JSONC_LINK_LIBS "") +if(FUN_WITH_JSON) + add_definitions(-DFUN_WITH_JSON) + find_package(PkgConfig QUIET) + if(PKG_CONFIG_FOUND) + pkg_check_modules(JSONC QUIET json-c) + endif() + if(JSONC_FOUND) + list(APPEND JSONC_INCLUDE_DIRS ${JSONC_INCLUDE_DIRS} ${JSONC_INCLUDE_DIRS}) + list(APPEND JSONC_LINK_LIBS ${JSONC_LINK_LIBS} ${JSONC_LIBRARIES}) + else() + list(APPEND JSONC_LINK_LIBS json-c) + endif() +endif() diff --git a/cmake/Extensions/LIBSQL.cmake b/cmake/Extensions/LIBSQL.cmake new file mode 100644 index 0000000..4272d02 --- /dev/null +++ b/cmake/Extensions/LIBSQL.cmake @@ -0,0 +1,27 @@ +# libsql +option(FUN_WITH_LIBSQL "Enable libsql (Turso) client support" OFF) +set(LIBSQL_INCLUDE_DIRS "") +set(LIBSQL_LINK_LIBS "") +if(FUN_WITH_LIBSQL) + add_definitions(-DFUN_WITH_LIBSQL) + find_package(PkgConfig QUIET) + if(PKG_CONFIG_FOUND) + pkg_check_modules(LIBSQL QUIET libsql) + if(NOT LIBSQL_FOUND) + pkg_check_modules(LIBSQL_CLIENT QUIET libsql-client) + if(LIBSQL_CLIENT_FOUND) + set(LIBSQL_FOUND TRUE) + set(LIBSQL_INCLUDE_DIRS ${LIBSQL_CLIENT_INCLUDE_DIRS}) + set(LIBSQL_LINK_LIBS ${LIBSQL_CLIENT_LIBRARIES}) + endif() + endif() + endif() + if(NOT LIBSQL_FOUND) + find_library(LIBSQL_LIB sqlite3) + if(LIBSQL_LIB) + list(APPEND LIBSQL_LINK_LIBS ${LIBSQL_LIB}) + else() + message(FATAL_ERROR "libsql not found. Install libsql (or compatible sqlite3 client) or disable FUN_WITH_LIBSQL.") + endif() + endif() +endif() diff --git a/cmake/Extensions/NOTCURSES.cmake b/cmake/Extensions/NOTCURSES.cmake new file mode 100644 index 0000000..84abbee --- /dev/null +++ b/cmake/Extensions/NOTCURSES.cmake @@ -0,0 +1,20 @@ +# Notcurses +option(FUN_WITH_NOTCURSES "Enable Notcurses TUI support" OFF) +set(NOTCURSES_INCLUDE_DIRS "") +set(NOTCURSES_LINK_LIBS "") +if(FUN_WITH_NOTCURSES) + add_definitions(-DFUN_WITH_NOTCURSES) + find_package(PkgConfig QUIET) + if(PkgConfig_FOUND) + pkg_check_modules(NOTCURSES QUIET notcurses) + if(NOT NOTCURSES_FOUND) + pkg_check_modules(NOTCURSES QUIET notcurses-core) + endif() + endif() + if(NOT NOTCURSES_FOUND) + message(FATAL_ERROR "FUN_WITH_NOTCURSES=ON but notcurses was not found via pkg-config (tried notcurses and notcurses-core). Install notcurses or configure with -DFUN_WITH_NOTCURSES=OFF") + else() + list(APPEND NOTCURSES_INCLUDE_DIRS ${NOTCURSES_INCLUDE_DIRS} ${NOTCURSES_INCLUDE_DIRS}) + list(APPEND NOTCURSES_LINK_LIBS ${NOTCURSES_LINK_LIBS} ${NOTCURSES_LIBRARIES}) + endif() +endif() diff --git a/cmake/Extensions/PCRE2.cmake b/cmake/Extensions/PCRE2.cmake new file mode 100644 index 0000000..618a481 --- /dev/null +++ b/cmake/Extensions/PCRE2.cmake @@ -0,0 +1,17 @@ +# PCRE2 +option(FUN_WITH_PCRE2 "Enable PCRE2 (Perl Compatible Regular Expressions) support" OFF) +set(PCRE2_INCLUDE_DIRS "") +set(PCRE2_LINK_LIBS "") +if(FUN_WITH_PCRE2) + add_definitions(-DFUN_WITH_PCRE2) + find_package(PkgConfig QUIET) + if(PKG_CONFIG_FOUND) + pkg_check_modules(PCRE2 QUIET libpcre2-8) + endif() + if(PCRE2_FOUND) + list(APPEND PCRE2_INCLUDE_DIRS ${PCRE2_INCLUDE_DIRS} ${PCRE2_INCLUDE_DIRS}) + list(APPEND PCRE2_LINK_LIBS ${PCRE2_LINK_LIBS} ${PCRE2_LIBRARIES}) + else() + list(APPEND PCRE2_LINK_LIBS pcre2-8) + endif() +endif() diff --git a/cmake/Extensions/PCSC.cmake b/cmake/Extensions/PCSC.cmake new file mode 100644 index 0000000..fa94f75 --- /dev/null +++ b/cmake/Extensions/PCSC.cmake @@ -0,0 +1,13 @@ +# PCSC +option(FUN_WITH_PCSC "Enable PCSC (pcsclite) support" OFF) +set(PCSC_LINK_LIBS "") +set(PCSC_INCLUDE_DIRS "") +if(FUN_WITH_PCSC) + add_definitions(-DFUN_WITH_PCSC) + if(APPLE) + list(APPEND PCSC_LINK_LIBS "-framework PCSC") + else() + list(APPEND PCSC_INCLUDE_DIRS "/usr/include/PCSC") + list(APPEND PCSC_LINK_LIBS pcsclite) + endif() +endif() diff --git a/cmake/Extensions/REPL.cmake b/cmake/Extensions/REPL.cmake new file mode 100644 index 0000000..9ac79f4 --- /dev/null +++ b/cmake/Extensions/REPL.cmake @@ -0,0 +1,2 @@ +# REPL toggle (affects sources of the fun executable) +option(FUN_WITH_REPL "Enable interactive REPL in the fun CLI" OFF) diff --git a/cmake/Extensions/SQLITE.cmake b/cmake/Extensions/SQLITE.cmake new file mode 100644 index 0000000..a92475e --- /dev/null +++ b/cmake/Extensions/SQLITE.cmake @@ -0,0 +1,22 @@ +# SQLite +option(FUN_WITH_SQLITE "Enable SQLite (sqlite3) support" OFF) +set(SQLITE3_INCLUDE_DIRS "") +set(SQLITE3_LINK_LIBS "") +if(FUN_WITH_SQLITE) + add_definitions(-DFUN_WITH_SQLITE) + find_package(PkgConfig QUIET) + if(PKG_CONFIG_FOUND) + pkg_check_modules(SQLITE3 QUIET sqlite3) + endif() + if(SQLITE3_FOUND) + list(APPEND SQLITE3_INCLUDE_DIRS ${SQLITE3_INCLUDE_DIRS} ${SQLITE3_INCLUDE_DIRS}) + list(APPEND SQLITE3_LINK_LIBS ${SQLITE3_LINK_LIBS} ${SQLITE3_LIBRARIES}) + else() + find_library(SQLITE3_LIB sqlite3) + if(SQLITE3_LIB) + list(APPEND SQLITE3_LINK_LIBS ${SQLITE3_LIB}) + else() + message(FATAL_ERROR "sqlite3 not found. Install sqlite3 (dev headers) or disable FUN_WITH_SQLITE.") + endif() + endif() +endif() diff --git a/cmake/Extensions/TCLTK.cmake b/cmake/Extensions/TCLTK.cmake new file mode 100644 index 0000000..471c4f6 --- /dev/null +++ b/cmake/Extensions/TCLTK.cmake @@ -0,0 +1,46 @@ +# Tcl/Tk GUI support +option(FUN_WITH_TCLTK "Enable Tcl/Tk GUI support" OFF) +set(TCL_INCLUDE_DIRS "") +set(TCL_LINK_LIBS "") +if(FUN_WITH_TCLTK) + add_definitions(-DFUN_WITH_TCLTK) + find_package(PkgConfig QUIET) + if(PKG_CONFIG_FOUND) + pkg_check_modules(TCL QUIET tcl) + pkg_check_modules(TK QUIET tk) + endif() + if(TCL_FOUND OR TK_FOUND) + if(TCL_FOUND) + list(APPEND TCL_INCLUDE_DIRS ${TCL_INCLUDE_DIRS} ${TCL_INCLUDE_DIRS}) + list(APPEND TCL_LINK_LIBS ${TCL_LINK_LIBS} ${TCL_LIBRARIES}) + endif() + if(TK_FOUND) + list(APPEND TCL_INCLUDE_DIRS ${TCL_INCLUDE_DIRS} ${TK_INCLUDE_DIRS}) + list(APPEND TCL_LINK_LIBS ${TCL_LINK_LIBS} ${TK_LIBRARIES}) + endif() + else() + find_path(TCL_INCLUDE_DIR tcl.h PATH_SUFFIXES tcl8.7 tcl8.6 include) + find_library(TCL_LIB NAMES tcl8.7 tcl8.6 tcl) + find_library(TK_LIB NAMES tk8.7 tk8.6 tk) + if(TCL_INCLUDE_DIR) + list(APPEND TCL_INCLUDE_DIRS ${TCL_INCLUDE_DIR}) + endif() + if(TCL_LIB) + list(APPEND TCL_LINK_LIBS ${TCL_LIB}) + endif() + if(TK_LIB) + list(APPEND TCL_LINK_LIBS ${TK_LIB}) + endif() + if(APPLE) + # macOS frameworks often unnecessary when using Homebrew tcl/tk + elseif(WIN32) + list(APPEND TCL_LINK_LIBS user32 gdi32 comctl32) + else() + find_package(X11 QUIET) + if(X11_FOUND) + list(APPEND TCL_INCLUDE_DIRS ${X11_INCLUDE_DIR}) + list(APPEND TCL_LINK_LIBS ${X11_LIBRARIES}) + endif() + endif() + endif() +endif() diff --git a/cmake/Extensions/XML2.cmake b/cmake/Extensions/XML2.cmake new file mode 100644 index 0000000..01858b1 --- /dev/null +++ b/cmake/Extensions/XML2.cmake @@ -0,0 +1,25 @@ +# XML (libxml2) +option(FUN_WITH_XML2 "Enable XML (libxml2) support" OFF) +set(LIBXML2_INCLUDE_DIRS "") +set(LIBXML2_LINK_LIBS "") +if(FUN_WITH_XML2) + add_definitions(-DFUN_WITH_XML2) + find_package(PkgConfig QUIET) + if(PKG_CONFIG_FOUND) + pkg_check_modules(LIBXML2 QUIET libxml-2.0) + endif() + if(LIBXML2_FOUND) + list(APPEND LIBXML2_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIRS}) + list(APPEND LIBXML2_LINK_LIBS ${LIBXML2_LINK_LIBS} ${LIBXML2_LIBRARIES}) + else() + find_library(LIBXML2_LIB NAMES xml2 libxml2) + if(LIBXML2_LIB) + list(APPEND LIBXML2_LINK_LIBS ${LIBXML2_LIB}) + if(EXISTS "/usr/include/libxml2") + list(APPEND LIBXML2_INCLUDE_DIRS "/usr/include/libxml2") + endif() + else() + message(FATAL_ERROR "libxml2 not found. Install libxml2 (dev headers) or disable FUN_WITH_XML2.") + endif() + endif() +endif() diff --git a/cmake/Options.cmake b/cmake/Options.cmake new file mode 100644 index 0000000..92a5fb8 --- /dev/null +++ b/cmake/Options.cmake @@ -0,0 +1,35 @@ +# Global options and defaults + +# Convenience: default path to bundled stdlib +set(FUN_LIB "${CMAKE_SOURCE_DIR}/lib" CACHE PATH "Path to bundled Fun stdlib") + +# Optional: build using musl libc instead of glibc on Linux (OFF by default) +option(FUN_USE_MUSL "Use musl libc toolchain when available (Linux only)" OFF) + +# Platform-specific configuration (DEFAULT_LIB_DIR defaults, libc defines/toolchain tweaks) +if(WIN32) + include(${CMAKE_SOURCE_DIR}/cmake/Platform/Windows.cmake) +elseif(APPLE) + include(${CMAKE_SOURCE_DIR}/cmake/Platform/macOS.cmake) +elseif(UNIX) + include(${CMAKE_SOURCE_DIR}/cmake/Platform/Linux.cmake) +endif() + +# If user provided DEFAULT_LIB_DIR, keep it; otherwise it should be set by platform include above +set(DEFAULT_LIB_DIR "${DEFAULT_LIB_DIR}" CACHE PATH "Default library directory for Fun stdlib (override with -DDEFAULT_LIB_DIR=...)" FORCE) + +# Ensure trailing slash for DEFAULT_LIB_DIR if it is defined +if(DEFINED DEFAULT_LIB_DIR AND NOT DEFAULT_LIB_DIR STREQUAL "") + if(NOT DEFAULT_LIB_DIR MATCHES "/$") + set(DEFAULT_LIB_DIR "${DEFAULT_LIB_DIR}/") + endif() +endif() + +# Static linking is deprecated/unsupported: always build dynamically +option(FUN_LINK_STATIC "(Deprecated) Attempt to link statically — ignored; dynamic linking is enforced" OFF) +if(FUN_LINK_STATIC) + message(WARNING "FUN_LINK_STATIC is deprecated and ignored. Building with dynamic linking.") +endif() + +# Debug option to enable verbose parser/VM logging +option(FUN_DEBUG "Enable extra debug logging in Fun" OFF) diff --git a/cmake/Platform/Linux.cmake b/cmake/Platform/Linux.cmake new file mode 100644 index 0000000..0c4147e --- /dev/null +++ b/cmake/Platform/Linux.cmake @@ -0,0 +1,24 @@ +# Linux-specific configuration for Fun + +# Default library directory (only set if not provided by user) +if(NOT DEFINED DEFAULT_LIB_DIR OR DEFAULT_LIB_DIR STREQUAL "") + set(DEFAULT_LIB_DIR "/usr/share/fun/lib" CACHE PATH "Default library directory for Fun stdlib (override with -DDEFAULT_LIB_DIR=...)" FORCE) +endif() + +# Handle musl toolchain selection when requested +if(FUN_USE_MUSL) + find_program(_FUN_MUSL_CC NAMES musl-gcc musl-clang) + if(_FUN_MUSL_CC) + message(STATUS "FUN_USE_MUSL=ON: using musl toolchain: ${_FUN_MUSL_CC}") + set(CMAKE_C_COMPILER "${_FUN_MUSL_CC}" CACHE FILEPATH "C compiler" FORCE) + set(FUN_LIBC "musl" CACHE STRING "Selected C library") + add_compile_definitions(FUN_LIBC_MUSL) + else() + message(WARNING "FUN_USE_MUSL=ON but no musl toolchain (musl-gcc or musl-clang) found. Falling back to default compiler (likely glibc).") + set(FUN_LIBC "glibc" CACHE STRING "Selected C library") + add_compile_definitions(FUN_LIBC_GLIBC) + endif() +else() + set(FUN_LIBC "glibc" CACHE STRING "Selected C library") + add_compile_definitions(FUN_LIBC_GLIBC) +endif() diff --git a/cmake/Platform/Windows.cmake b/cmake/Platform/Windows.cmake new file mode 100644 index 0000000..2be11ec --- /dev/null +++ b/cmake/Platform/Windows.cmake @@ -0,0 +1,10 @@ +# Windows-specific configuration for Fun + +# Default library directory (only set if not provided by user) +if(NOT DEFINED DEFAULT_LIB_DIR OR DEFAULT_LIB_DIR STREQUAL "") + set(DEFAULT_LIB_DIR "C:/Users/Public/fun/lib" CACHE PATH "Default library directory for Fun stdlib (override with -DDEFAULT_LIB_DIR=...)" FORCE) +endif() + +# libc macro (non-musl path) +set(FUN_LIBC "glibc" CACHE STRING "Selected C library") +add_compile_definitions(FUN_LIBC_GLIBC) diff --git a/cmake/Platform/macOS.cmake b/cmake/Platform/macOS.cmake new file mode 100644 index 0000000..eabaf85 --- /dev/null +++ b/cmake/Platform/macOS.cmake @@ -0,0 +1,10 @@ +# macOS-specific configuration for Fun + +# Default library directory (only set if not provided by user) +if(NOT DEFINED DEFAULT_LIB_DIR OR DEFAULT_LIB_DIR STREQUAL "") + set(DEFAULT_LIB_DIR "/Library/Application Support/fun/lib" CACHE PATH "Default library directory for Fun stdlib (override with -DDEFAULT_LIB_DIR=...)" FORCE) +endif() + +# libc macro (non-musl path) +set(FUN_LIBC "glibc" CACHE STRING "Selected C library") +add_compile_definitions(FUN_LIBC_GLIBC) diff --git a/cmake/Targets.cmake b/cmake/Targets.cmake new file mode 100644 index 0000000..c1db251 --- /dev/null +++ b/cmake/Targets.cmake @@ -0,0 +1,130 @@ +# Targets for Fun project (moved from src/CMakeLists.txt) + +# Core VM/library sources +add_library(fun_core + ${CMAKE_SOURCE_DIR}/src/bytecode.c + ${CMAKE_SOURCE_DIR}/src/parser.c + ${CMAKE_SOURCE_DIR}/src/value.c + ${CMAKE_SOURCE_DIR}/src/vm.c +) + +# NOTE: Do not compile src/vm/*/*.c as independent units. +# Those files are meant to be included by src/vm.c inside a big switch. + +target_include_directories(fun_core PUBLIC + ${CMAKE_SOURCE_DIR}/src +) + +# Apply options to core +if(FUN_DEBUG) + message(STATUS "FUN_DEBUG enabled: building with verbose debug logging") + target_compile_definitions(fun_core PUBLIC FUN_VERSION="${PROJECT_VERSION}") + target_compile_definitions(fun_core PUBLIC FUN_DEBUG=1) +endif() + +# Provide default stdlib directory and version to the runtime +target_compile_definitions(fun_core PUBLIC FUN_VERSION="${PROJECT_VERSION}") +target_compile_definitions(fun_core PUBLIC DEFAULT_LIB_DIR="${DEFAULT_LIB_DIR}") + +# Apply extension include/link variables discovered in cmake/Extensions +foreach(var_pair + PCSC + JSONC + PCRE2 + CURL + SQLITE3 + INIPARSER + LIBSQL + LIBXML2 + TCL + NOTCURSES) + if(${var_pair}_INCLUDE_DIRS) + target_include_directories(fun_core PRIVATE ${${var_pair}_INCLUDE_DIRS}) + endif() + if(${var_pair}_LINK_LIBS) + target_link_libraries(fun_core PUBLIC ${${var_pair}_LINK_LIBS}) + endif() +endforeach() + +# Ensure feature compile definitions are applied to fun_core so +# conditional code blocks (#ifdef FUN_WITH_*) are compiled as expected. + +# Feature-specific sources and compile definitions +if(FUN_WITH_PCSC) + target_compile_definitions(fun_core PUBLIC FUN_WITH_PCSC=1) +endif() + +if(FUN_WITH_JSON) + target_compile_definitions(fun_core PUBLIC FUN_WITH_JSON=1) +endif() + +if(FUN_WITH_INI) + target_compile_definitions(fun_core PUBLIC FUN_WITH_INI=1) +endif() + +if(FUN_WITH_XML2) + target_compile_definitions(fun_core PUBLIC FUN_WITH_XML2=1) +endif() + +if(FUN_WITH_LIBSQL) + target_compile_definitions(fun_core PUBLIC FUN_WITH_LIBSQL=1) +endif() + +if(FUN_WITH_PCRE2) + target_compile_definitions(fun_core PUBLIC FUN_WITH_PCRE2=1) +endif() + +if(FUN_WITH_CURL) + target_compile_definitions(fun_core PUBLIC FUN_WITH_CURL=1) +endif() + +if(FUN_WITH_NOTCURSES) + target_compile_definitions(fun_core PUBLIC FUN_WITH_NOTCURSES=1) +endif() + +if(FUN_WITH_SQLITE) + target_compile_definitions(fun_core PUBLIC FUN_WITH_SQLITE=1) +endif() + +if(FUN_WITH_TCLTK) + target_compile_definitions(fun_core PUBLIC FUN_WITH_TCLTK=1) +endif() + +# Special case for libxml2 system include path if enabled +if(FUN_WITH_XML2) + if(EXISTS "/usr/include/libxml2") + target_include_directories(fun_core PRIVATE "/usr/include/libxml2") + endif() +endif() + +# Link threads if available on UNIX +if(Threads_FOUND) + target_link_libraries(fun_core PUBLIC Threads::Threads) +endif() + +# Link libm for C99 math functions if available +find_library(M_LIB m) +if(M_LIB) + target_link_libraries(fun_core PUBLIC ${M_LIB}) +endif() + +# Executable: fun (CLI) +add_executable(fun + ${CMAKE_SOURCE_DIR}/src/fun.c +) +if(FUN_WITH_REPL) + target_compile_definitions(fun PRIVATE FUN_WITH_REPL=1) + target_sources(fun PRIVATE ${CMAKE_SOURCE_DIR}/src/repl.c) +endif() +target_link_libraries(fun PRIVATE fun_core) + +# Internal test programs +add_executable(fun_test + ${CMAKE_SOURCE_DIR}/src/fun_test.c) +target_link_libraries(fun_test PRIVATE fun_core) + +add_executable(test_opcodes + ${CMAKE_SOURCE_DIR}/src/test_opcodes.c) +target_link_libraries(test_opcodes PRIVATE fun_core) + +# Static linking flags are intentionally not applied (deprecated behavior) diff --git a/make b/make index a6a0205..a168844 100755 --- a/make +++ b/make @@ -30,6 +30,7 @@ if [ "$target" = "all" ]; then -DFUN_WITH_JSON=ON \ -DFUN_WITH_TCLTK=ON \ -DFUN_WITH_INI=ON \ + -DFUN_WITH_NOTCURSES=ON \ -DFUN_LINK_STATIC=OFF \ -DFUN_USE_MUSL=OFF \ -DFUN_DEBUG=OFF \ @@ -65,6 +66,7 @@ elif [ "$target" = "alpine" ]; then -DFUN_WITH_TCLTK=OFF \ -DFUN_WITH_INI=ON \ -DFUN_LINK_STATIC=OFF \ + -DFUN_USE_MUSL=ON \ -DFUN_DEBUG=OFF \ && cmake --build build --target fun elif [ "$target" = "debug" ]; then diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..6aacbbd --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,5 @@ +# This file is intentionally minimal. Targets have been moved to cmake/Targets.cmake +# to keep the source tree clean. Keeping this include preserves compatibility if +# someone adds this directory as a subdirectory in the future. + +include(${CMAKE_SOURCE_DIR}/cmake/Targets.cmake)