diff --git a/CMakeLists.txt b/CMakeLists.txt index 1624704..a41d73b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 3.24) project(tangerine DESCRIPTION "Procedural 3D model creation") +# Add find modules to the path +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/linux/cmake") + if (MSVC) message(FATAL_ERROR "Currently CMake is only used on the Linux platform.\ @@ -14,7 +17,8 @@ include(GNUInstallDirs) ## Build options: option(EMBED_LUA "Embed Lua support" ON) -option(EMBED_RACKET "Embed Racket support" OFF) +option(EMBED_RACKET "Embed Racket support" ON) #FIXME for testing +option(SELF_CONTAINED "Use directory tree instead of XDG_STATE_HOME" OFF) set(INSTALL_PKG_SUBPATH "tangerine" CACHE PATH "Subdirectory to form PKGDATADIR from DATADIR") @@ -28,7 +32,6 @@ find_package(Threads REQUIRED) set(CMAKE_CXX_STANDARD 17) set(CMAKE_C_STANDARD 17) - ####################################################################### ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++## ####################################################################### @@ -143,6 +146,7 @@ set_target_properties(tangerine RUNTIME_OUTPUT_DIRECTORY $) target_compile_definitions(tangerine PRIVATE + $<$:"TANGERINE_SELF_CONTAINED"> "TANGERINE_PKGDATADIR_FROM_BINDIR=${PKGDATADIR_FROM_BINDIR}") target_link_libraries(tangerine PRIVATE fmt @@ -181,4 +185,16 @@ target_compile_definitions(tangerine PRIVATE ####################################################################### ## Racket: -# FIXME! +if(EMBED_RACKET) + find_package(Racket REQUIRED) #FIXME or build our own + target_link_libraries(tangerine PRIVATE Racket::LibRacketCS) + target_compile_definitions(tangerine PRIVATE + "TANGERINE_RACKET_PETITE_BOOT=${Racket_PETITE_BOOT}" + "TANGERINE_RACKET_SCHEME_BOOT=${Racket_SCHEME_BOOT}" + "TANGERINE_RACKET_RACKET_BOOT=${Racket_RACKET_BOOT}" + "TANGERINE_RACKET_COLLECTS_DIR=${Racket_COLLECTS_DIR}" + "TANGERINE_RACKET_CONFIG_DIR=${Racket_CONFIG_DIR}" + "TANGERINE_USE_SYSTEM_RACKET=1") +endif() +target_compile_definitions(tangerine PRIVATE + "EMBED_RACKET=$") diff --git a/SDL2.dll b/SDL2.dll deleted file mode 100644 index ddba03c..0000000 Binary files a/SDL2.dll and /dev/null differ diff --git a/channels.scm b/channels.scm index ec4344d..a583cf1 100644 --- a/channels.scm +++ b/channels.scm @@ -1,11 +1,22 @@ (list (channel - (name 'guix) - (url "https://git.savannah.gnu.org/git/guix.git") - (branch "master") - (commit - "67d2f688fb89553df53e73a4c584b1b9eb7d5c24") - (introduction - (make-channel-introduction - "9edb3f66fd807b096b48283debdcddccfea34bad" - (openpgp-fingerprint - "BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA"))))) + (name 'guix-racket-experiment) + (url "https://gitlab.com/philip1/guix-racket-experiment.git") + (branch "main") + (commit + "7d3c3e2dbf72cf2dc9e89243b1de8a96f39dab8c") + (introduction + (make-channel-introduction + "ef0580fceb8d88453724b2a2aa6fc9631612033c" + (openpgp-fingerprint + "F465 ABAC D637 AEAC 1415 55CF CA03 638D FA3F 1C7A")))) + (channel + (name 'guix) + (url "https://git.savannah.gnu.org/git/guix.git") + (branch "master") + (commit + "8320c0c6b6486f1991aa99246460ec955add65c7") + (introduction + (make-channel-introduction + "9edb3f66fd807b096b48283debdcddccfea34bad" + (openpgp-fingerprint + "BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA"))))) diff --git a/guix.scm b/guix.scm index db2e0fe..b735cc6 100644 --- a/guix.scm +++ b/guix.scm @@ -3,6 +3,7 @@ (use-modules (gnu packages cmake) (gnu packages ncurses) + ((gnu packages racket) #:select (racket-vm-cs)) (gnu packages sdl) (guix build-system cmake) (guix gexp) @@ -10,39 +11,88 @@ ((guix licenses) #:prefix license:) (guix packages) (guix utils) - (ice-9 regex)) + (ice-9 ftw) + (ice-9 regex) + (ice-9 vlist) + (wip-gnu packages racket) + (wip-guix build-system racket)) -(define-public %tangerine-origin - (local-file - "." "tangerine-src" - #:recursive? #t - #:select? - (let* ((src-dir (current-source-directory)) - (checked-in? - (or (and src-dir - (git-predicate (canonicalize-path src-dir))) - (lambda (path stat) - #t))) - (so-dll-rx - (make-regexp "\\.(so|dll)$")) - (so-or-dll? - (lambda (path stat) - (regexp-exec so-dll-rx path))) - (source-file? - (lambda (path stat) - (and (checked-in? path stat) - (not (so-or-dll? path stat)))))) - source-file?))) + +(define %tangerine-revision "0") + + +(define-values (%tangerine-racket-origin %tangerine-cxx-origin) + ;; separate origins to reduce rebuilds + (let () + (define src-dir + (current-source-directory)) + (define (stat->identity stat) + (cons (stat:dev stat) (stat:ino stat))) + (define racket-src-identities + (delay + (if src-dir + (let* ((enter? (const #t)) + (leaf (lambda (path stat result) + (vhash-cons (stat->identity stat) #t result))) + (down leaf) + (up (lambda (path stat result) + result)) + (skip up) + (error (lambda (name stat errno result) + result)) + (ids + (file-system-fold enter? leaf down up skip error + vlist-null + (string-append src-dir "/package")))) + ids) + vlist-null))) + (define checked-in? + ;; TODO: This excluded linux/cmake/FindRacket.scm before I + ;; checked it in, which was very confusing. Probably better + ;; to use a predicate like git-ignored-file?, or something + ;; like the logic from `nix flake. + ;; (It even excludes staged files.) + (if src-dir + (git-predicate (canonicalize-path src-dir)) + (lambda (path stat) + #t))) + (define so-dll-rx + (make-regexp "\\.(so|dll)$")) + (define (so-or-dll? path stat) + (regexp-exec so-dll-rx path)) + (define guix-file-rx + (make-regexp "(channels|guix)\\.scm$")) + (define (guix-file? path stat) + (regexp-exec guix-file-rx path)) + (define (source-file? path stat) + (and (checked-in? path stat) + (not (guix-file? path stat)) + (not (so-or-dll? path stat)))) + (define (non-racket-source-file? path stat) + (and (source-file? path stat) + (not (vhash-assoc (stat->identity stat) + (force racket-src-identities))))) + (values + (local-file "package" "tangerine-racket-src" + #:recursive? #t + #:select? source-file?) + (local-file "." "tangerine-cxx-src" + #:recursive? #t + #:select? non-racket-source-file?)))) (define-public tangerine (package (name "tangerine") (version "0.0") - (source %tangerine-origin) + (source %tangerine-cxx-origin) (outputs '("out" "debug")) (build-system cmake-build-system) (inputs (list ncurses/tinfo ; for -ltinfo + tangerine-racket-layer + racket-vm-cs + (lookup-package-input racket-vm-cs "zlib") + (lookup-package-input racket-vm-cs "lz4") sdl2 ;; are the rest needed? sdl2-image @@ -50,6 +100,7 @@ sdl2-ttf)) (arguments (list + ;#:phases #~(modify-phases %standard-phases (add-before 'configure 'stop (lambda args (error "stop")))) #:cmake cmake ; newer than cmake-minimal #:tests? #f)) (home-page "https://github.com/Aeva/tangerine") @@ -61,4 +112,91 @@ operators. Models are written in Lua, and may be either rendered directly or exported to a variety of common 3D model file formats.") (license license:asl2.0))) +(define-public racket-vec-lib + (let ((commit "7ed2f1e43668d230cc411b326f7ace746f5d76de") + (revision "1")) ; Guix package revision + (package + (name "racket-vec-lib") + (version (git-version "0.0" revision commit)) + (source (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/Aeva/vec") + (commit commit))) + (sha256 + (base32 + "0l515l9kx39xqa9skj7pj54gwffypa1d9pri7daj7kdzqs6d8cc8")) + (file-name (git-file-name name version)))) + (build-system racket-build-system) + (outputs `("out" "pkgs")) + (inputs + (list racket-base)) + (arguments + (list #:path "vec-lib")) + (home-page "https://pkgs.racket-lang.org/package/vec-lib") + (synopsis "Simple vector math library (implementation part)") + (description + "This package provides a simple Racket library for vector math, +developed for Tangerine. For documentation, see the Racket package +@code{vec}.") + (license license:asl2.0)))) + +(define-public racket-tangerine-x86-64-linux + (package + (name "racket-tangerine-x86-64-linux") + (version (git-version "0.0" %tangerine-revision "develop")) + (source %tangerine-racket-origin) + (build-system racket-build-system) + (outputs `("out" "pkgs")) + (inputs + (list racket-base)) + (arguments + (list + #:path "tangerine-x86_64-linux" + #:phases + #~(modify-phases %standard-phases + (add-after 'unpack 'patch-info-rkt + (lambda args + (substitute* "info.rkt" + (("[(]define copy-foreign-libs") + "#;(define copy-foreign-libs"))))))) + (home-page "https://pkgs.racket-lang.org/package/tangerine-x86-64-linux") + (synopsis "") + (description "") + (license license:asl2.0))) + +(define-public racket-tangerine + (package + (name "racket-tangerine") + (version (git-version "0.0" %tangerine-revision "develop")) + (source %tangerine-racket-origin) + (build-system racket-build-system) + (outputs `("out" "pkgs")) + (inputs + (list racket-base + racket-sandbox-lib + racket-tangerine-x86-64-linux + racket-vec-lib)) + (arguments + (list #:path "tangerine")) + (home-page "https://pkgs.racket-lang.org/package/tangerine-x86-64-linux") + (synopsis "") + (description "") + (license license:asl2.0))) + +(define-public tangerine-racket-layer + ;; opt/racket-vm/lib/{libracketcs.a,*.boot} + ;; opt/racket-vm/include/{chezscheme,racketcs,racketcsboot}.h + ;; etc/racket/config.rktd + (package + (inherit (make-racket-installation + #:name "tangerine-racket-layer" + #:tethered? #f + #:racket racket-vm-cs + #:packages (delay (list racket-tangerine)))) + (synopsis "Racket installation layer for Tangerine") + (description + "") + (license (list license:asl2.0 license:expat)))) + tangerine diff --git a/libracketcs_db9xz4.dll b/libracketcs_db9xz4.dll deleted file mode 100644 index 895992e..0000000 Binary files a/libracketcs_db9xz4.dll and /dev/null differ diff --git a/linux/cmake/FindLZ4.cmake b/linux/cmake/FindLZ4.cmake new file mode 100644 index 0000000..fc3ba5c --- /dev/null +++ b/linux/cmake/FindLZ4.cmake @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: (Apache-2.0 OR MIT) +# SPDX-FileCopyrightText: © 2023 Philip McGrath + +#[=======================================================================[.rst: + +FindLZ4 +------- + +Finds the LZ4 library. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module provides the following imported targets, if found: + +``LZ4::LZ4`` + The LZ4 library + +Output Variables +^^^^^^^^^^^^^^^^ + +The following output variables are set: + +``Racket_FOUND`` + True if the system has LZ4. + +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: + +``LZ4_LIBRARY`` + Path to ``LZ4::LZ4``. +``LZ4_INCLUDE_DIR`` + Include directory for ````, if found. + +#]=======================================================================] + +# Model: https://cmake.org/cmake/help/latest/manual/cmake-developer.7.html#find-modules + +include(FindPackageHandleStandardArgs) + +find_package(PkgConfig) +pkg_check_modules(PC_LZ4 QUIET liblz4) +set(LZ4_VERSION ${PC_LZ4_VERSION}) +find_library(LZ4_LIBRARY + NAMES lz4 + PATHS ${PC_LZ4_LIBRARY_DIRS} + PATH_SUFFIXES lz4 + DOC "The LZ4 library." +) +find_path(LZ4_INCLUDE_DIR + NAMES lz4.h + PATHS ${PC_LZ4_INCLUDE_DIRS} + PATH_SUFFIXES lz4 + DOC "The include directory for ." +) +find_package_handle_standard_args(LZ4 + REQUIRED_VARS + LZ4_LIBRARY + VERSION_VAR LZ4_VERSION +) +if(LZ4_FOUND AND NOT TARGET LZ4::LZ4) + add_library(LZ4::LZ4 UNKNOWN IMPORTED) + set_target_properties(LZ4::LZ4 PROPERTIES + IMPORTED_LOCATION "${LZ4_LIBRARY}" + ) + if(LZ4_INCLUDE_DIR) + target_include_directories(LZ4::LZ4 INTERFACE "${LZ4_INCLUDE_DIR}") + endif() +endif() diff --git a/linux/cmake/FindRacket.cmake b/linux/cmake/FindRacket.cmake new file mode 100644 index 0000000..62dbed5 --- /dev/null +++ b/linux/cmake/FindRacket.cmake @@ -0,0 +1,195 @@ +# SPDX-License-Identifier: (Apache-2.0 OR MIT) +# SPDX-FileCopyrightText: © 2023 Philip McGrath + +#[=======================================================================[.rst: + +FindRacket +---------- + +Finds Racket. Currently focused on Racket CS for embedding. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module provides the following imported targets, if found: + +``Racket::LibRacketCS`` + The Racket CS library + +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: + +``Racket_PETITE_BOOT`` + Path to ``petite.boot``. +``Racket_SCHEME_BOOT`` + Path to ``scheme.boot``. +``Racket_RACKET_BOOT`` + Path to ``racket.boot``. +``Racket_CONFIG_DIR`` + Path to a main configuration directory like the ``-G``/``--config`` option to ``racket``. +``Racket_COLLECTS_DIR`` + Path to a main collections directory like the ``-X``/``--collects`` option to ``racket``. + +Less Useful Variables +^^^^^^^^^^^^^^^^^^^^^ + +These cache variables may also be set, but they are less likely to be useful to your code: + +``Racket_racketcs_LIBRARY`` + Path to the library ``Racket::LibRacketCS``. +``Racket_racketcs_INCLUDE_DIR`` + Path to the directory for ``racketcs.h``. +``Racket_chezscheme_INCLUDE_DIR`` + Likewise, but for ``chezscheme.h`` (likely the same directory). + +The following non-cache output variables will be set (but prefer ``Racket::LibRacketCS``): + +``Racket_FOUND`` + True if the system has Racket. +``Racket_INCLUDE_DIRS`` + Include directories needed to embed Racket. +``Foo_LIBRARIES`` + Libraries needed to link to Racket (i.e. ``Racket::LibRacketCS``). + +#]=======================================================================] + +# Model: https://cmake.org/cmake/help/latest/manual/cmake-developer.7.html#find-modules + +include(FindPackageHandleStandardArgs) +include(RacketParseConfigFile) + +cmake_path(CONVERT "$ENV{Racket_ROOT}" TO_CMAKE_PATH_LIST _env_Racket_ROOT) +cmake_path(CONVERT "$ENV{CMAKE_PREFIX_PATH}" TO_CMAKE_PATH_LIST _env_CMAKE_PREFIX_PATH) +set(_toSearch "") +foreach(dir IN LISTS Racket_ROOT _env_Racket_ROOT CMAKE_PREFIX_PATH _env_CMAKE_PREFIX_PATH) + list(APPEND _toSearch ${dir}) +endforeach() +cmake_path(CONVERT "$ENV{LIB}" TO_CMAKE_PATH_LIST _env_LIB) +cmake_path(CONVERT "$ENV{INCLUDE}" TO_CMAKE_PATH_LIST _env_INCLUDE) +cmake_path(CONVERT "$ENV{PATH}" TO_CMAKE_PATH_LIST _env_PATH) +foreach(dir IN LISTS _env_LIB _env_INCLUDE _env_PATH) + cmake_path(GET dir PARENT_PATH _updir) + list(APPEND _toSearch ${_updir}) +endforeach() +foreach(dir IN LISTS CMAKE_INSTALL_PREFIX CMAKE_STAGING_PREFIX CMAKE_SYSTEM_PREFIX_PATH) + list(APPEND _toSearch ${dir}) +endforeach() +list(REMOVE_DUPLICATES _toSearch) + +set(Racket_CONFIG_FILE NO) + +#if(NOT $CACHE{Racket_CONFIG_DIR}) +# FIXME maybe https://cmake.org/cmake/help/latest/command/cmake_language.html#defer + set(_toSearch_etc_racket "") + set(_toSearch_etc "") + foreach(dir IN LISTS _toSearch) + cmake_path(APPEND dir "etc" OUTPUT_VARIABLE _etc) + cmake_path(APPEND _etc "racket" OUTPUT_VARIABLE _rkt) + list(APPEND _toSearch_etc_racket ${_rkt}) + list(APPEND _toSearch_etc ${_etc}) + endforeach() + foreach(dir IN LISTS _toSearch_etc_racket _toSearch_etc) + cmake_path(APPEND dir "config.rktd" OUTPUT_VARIABLE _file) + if(EXISTS ${_file}) + set(Racket_CONFIG_DIR ${dir} CACHE PATH "Like the --config argument at the command line.") + set(Racket_CONFIG_FILE ${_file}) # FIXME set this outside to work even if we got Racket_CONFIG_DIR from the user (we may still need to find others + break() + endif() + endforeach() +#endif() + + +racket_parse_config_file(${Racket_CONFIG_FILE} + NAME _installationName + LIB_DIRS _configLibDirs + INCLUDE_DIRS _configIncludeDirs +) + + +find_library(Racket_racketcs_LIBRARY + NAMES racketcs libracketcs NAMES_PER_DIR + HINTS ${_configLibDirs} + PATH_SUFFIXES "racket" + DOC "Racket CS library for embedding." +) + + +find_path(Racket_racketcs_INCLUDE_DIR + NAMES racketcs.h + HINTS ${_configIncludeDirs} + PATH_SUFFIXES "Directory to include for ." +) +# Prefer the sibling of "racketcs.h" if it exists, search otherwise. +find_path(Racket_chezscheme_INCLUDE_DIR + NAMES chezscheme.h + HINTS ${Racket_racketcs_INCLUDE_DIR} + NO_DEFAULT_PATH + PATH_SUFFIXES "Directory to include for ." +) +find_path(Racket_chezscheme_INCLUDE_DIR + NAMES chezscheme.h + HINTS ${_configIncludeDirs} + PATH_SUFFIXES "Directory to include for ." +) + + +# We would like to use the default paths from `find_library`, +# but it insists on appending ".so" or ".a". +# No PATH_SUFFIXES needed as _configLibDirs handles it. +find_file(Racket_PETITE_BOOT + "petite.boot" + HINTS ${_configLibDirs} + NO_DEFAULT_PATH + DOC "Bootfile for Petite Chez Scheme." +) +find_file(Racket_SCHEME_BOOT + "scheme.boot" + HINTS ${_configLibDirs} + NO_DEFAULT_PATH + DOC "Bootfile for Chez Scheme." +) +find_file(Racket_RACKET_BOOT + "racket.boot" + HINTS ${_configLibDirs} + NO_DEFAULT_PATH + DOC "Bootfile for Racket." +) + +find_path(Racket_COLLECTS_DIR + "racket/base.rkt" + HINTS ${_configLibDirs} + PATH_SUFFIXES "../collects" "../../collects" "../../share/racket/collects" "../share/racket/collects" + DOC "Like the --collects argument at the command line." +) + + +find_package_handle_standard_args(Racket + REQUIRED_VARS + Racket_CONFIG_DIR Racket_COLLECTS_DIR + Racket_racketcs_LIBRARY + Racket_racketcs_INCLUDE_DIR Racket_chezscheme_INCLUDE_DIR + Racket_PETITE_BOOT Racket_SCHEME_BOOT Racket_RACKET_BOOT +) +mark_as_advanced( + Racket_CONFIG_DIR +) +if(Racket_FOUND AND NOT TARGET Racket::LibRacketCS) + # per cmake docs, Racket_INCLUDE_DIRS "should not be a cache entry" + set(Racket_INCLUDE_DIRS ${Racket_racketcs_INCLUDE_DIR} ${Racket_chezscheme_INCLUDE_DIR}) + list(REMOVE_DUPLICATES Racket_INCLUDE_DIRS) + find_package(ZLIB) + find_package(LZ4) + add_library(Racket::LibRacketCS UNKNOWN IMPORTED) + set_target_properties(Racket::LibRacketCS PROPERTIES + IMPORTED_LOCATION ${Racket_racketcs_LIBRARY} + ) + target_include_directories(Racket::LibRacketCS + INTERFACE "${Racket_INCLUDE_DIRS}" + ) + target_link_libraries(Racket::LibRacketCS + INTERFACE ZLIB::ZLIB LZ4::LZ4 + ) + set(Racket_LIBRARIES Racket::LibRacketCS) +endif() diff --git a/linux/cmake/RacketParseConfigFile.cmake b/linux/cmake/RacketParseConfigFile.cmake new file mode 100644 index 0000000..20d3100 --- /dev/null +++ b/linux/cmake/RacketParseConfigFile.cmake @@ -0,0 +1,120 @@ +# SPDX-License-Identifier: (Apache-2.0 OR MIT) +# SPDX-FileCopyrightText: © 2023 Philip McGrath + +#[=======================================================================[.rst: + +RacketParseConfigFile +--------------------- + +#]=======================================================================] + +function(racket_extract_config_pair entryId) + # FRAGILE: breaks if there is a ")" in the string + # Also, note that the result might not `read` as a Racket pair, e.g. for `(k . ())` + set(_options "") + set(_oneValKeys FROM OUTPUT_VARIABLE) + set(_multiValKeys "") + cmake_parse_arguments(PARSE_ARGV 1 "parse" "${_options}" "${_oneValKeys}" "${_multiValKeys}") + # parse_UNPARSED_ARGUMENTS + # parse_KEYWORDS_MISSING_VALUES + # message(WARNING "unparsed: ${parse_UNPARSED_ARGUMENTS}") + # message(WARNING "missing: ${parse_KEYWORDS_MISSING_VALUES}") + string(REGEX MATCH "[(][ \t\r\n]*${entryId}[ \t\r\n]+\.[ \t\r\n]+[^)]+[)]" + _found + ${parse_FROM} + ) + set(${parse_OUTPUT_VARIABLE} ${_found} PARENT_SCOPE) +endfunction() + +function(racket_extract_strings) + # FRAGILE: breaks if there is a "\"" in the string + set(_options "") + set(_oneValKeys FROM OUTPUT_VARIABLE) + set(_multiValKeys "") + cmake_parse_arguments(PARSE_ARGV 0 "parse" "${_options}" "${_oneValKeys}" "${_multiValKeys}") + # parse_UNPARSED_ARGUMENTS + # parse_KEYWORDS_MISSING_VALUES + # message(WARNING "unparsed: ${parse_UNPARSED_ARGUMENTS}") + # message(WARNING "missing: ${parse_KEYWORDS_MISSING_VALUES}") + string(REGEX MATCHALL "\"[^\"]*[\"]" + _allRaw + ${parse_FROM} + ) + set(_allTrimmed "") + foreach(_raw IN LISTS _allRaw) + # remove the opening and closing "\"" + string(LENGTH ${_raw} _lenRaw) + math(EXPR _lenTrimmed "${_lenRaw} - 2") + string(SUBSTRING ${_raw} 1 ${_lenTrimmed} _trimmed) + list(APPEND _allTrimmed ${_trimmed}) + endforeach() + set(${parse_OUTPUT_VARIABLE} ${_allTrimmed} PARENT_SCOPE) +endfunction() + +function(racket_parse_config_entry entryId) + # Not correct in general (see comments above), but good enough for hints + set(_options "") + set(_oneValKeys FROM OUTPUT_VARIABLE) + set(_multiValKeys "") + cmake_parse_arguments(PARSE_ARGV 1 "parse" "${_options}" "${_oneValKeys}" "${_multiValKeys}") + # parse_UNPARSED_ARGUMENTS + # parse_KEYWORDS_MISSING_VALUES + # message(WARNING "unparsed: ${parse_UNPARSED_ARGUMENTS}") + # message(WARNING "missing: ${parse_KEYWORDS_MISSING_VALUES}") + racket_extract_config_pair(${entryId} FROM ${parse_FROM} OUTPUT_VARIABLE _pair) + racket_extract_strings(FROM ${_pair} OUTPUT_VARIABLE _string) + #message(NOTICE "========\nFound:\n-----\n${entryId}\n${_string}\n========") + set(${parse_OUTPUT_VARIABLE} ${_string} PARENT_SCOPE) +endfunction() + +function(racket_parse_config_search_path dirId searchDirsID) + # Not correct in general (see comments above), but good enough for hints + set(_options "") + set(_oneValKeys FROM OUTPUT_VARIABLE) + set(_multiValKeys "") + cmake_parse_arguments(PARSE_ARGV 2 "parse" "${_options}" "${_oneValKeys}" "${_multiValKeys}") + # parse_UNPARSED_ARGUMENTS + # parse_KEYWORDS_MISSING_VALUES + # message(WARNING "unparsed: ${parse_UNPARSED_ARGUMENTS}") + # message(WARNING "missing: ${parse_KEYWORDS_MISSING_VALUES}") + racket_parse_config_entry(${dirId} + FROM ${parse_FROM} + OUTPUT_VARIABLE _ret + ) + racket_parse_config_entry(${searchDirsID} + FROM ${parse_FROM} + OUTPUT_VARIABLE _more + ) + list(APPEND _ret "${_more}") + set(${parse_OUTPUT_VARIABLE} ${_ret} PARENT_SCOPE) +endfunction() + +function(racket_parse_config_file Racket_CONFIG_FILE) + set(_options "") + set(_oneValKeys NAME LIB_DIRS INCLUDE_DIRS) + set(_multiValKeys "") + cmake_parse_arguments(PARSE_ARGV 1 "parse" "${_options}" "${_oneValKeys}" "${_multiValKeys}") + # parse_UNPARSED_ARGUMENTS + file(READ ${Racket_CONFIG_FILE} _Racket_CONFIG_FILE_content) + if(DEFINED parse_NAME) + racket_parse_config_entry("installation-name" + FROM ${_Racket_CONFIG_FILE_content} + OUTPUT_VARIABLE _installationName + ) + set(${parse_NAME} ${_installationName} PARENT_SCOPE) + endif() + if(DEFINED parse_LIB_DIRS) + racket_parse_config_search_path("lib-dir" "lib-search-dirs" + FROM ${_Racket_CONFIG_FILE_content} + OUTPUT_VARIABLE _configLibSearchDirs + ) + set(${parse_LIB_DIRS} ${_configLibSearchDirs} PARENT_SCOPE) + endif() + if(DEFINED parse_INCLUDE_DIRS) + racket_parse_config_search_path("include-dir" "include-search-dirs" + FROM ${_Racket_CONFIG_FILE_content} + OUTPUT_VARIABLE _configIncludeSearchDirs + ) + set(${parse_INCLUDE_DIRS} ${_configIncludeSearchDirs} PARENT_SCOPE) + endif() +endfunction() diff --git a/linux/cmake/script.cmake b/linux/cmake/script.cmake new file mode 100755 index 0000000..f76a393 --- /dev/null +++ b/linux/cmake/script.cmake @@ -0,0 +1,15 @@ +#!/usr/bin/env -S guix shell cmake -- cmake -P + +cmake_minimum_required(VERSION 3.24) + +include(RacketParseConfigFile.cmake) + +racket_parse_config_file("/gnu/store/al90nb7vrjhgbzr71x037c7ny73b03sb-tangerine-racket-layer-8.7/etc/racket/config.rktd" + NAME _installationName + LIB_DIRS _configLibDirs + INCLUDE_DIRS _configIncludeDirs +) + +message(NOTICE "Got:\n${_installationName}") +message(WARNING "Got:\n${_configLibDirs}") +message(NOTICE "Got:\n${_configIncludeDirs}") diff --git a/package/tangerine/ffi.rkt b/package/tangerine/ffi.rkt index 7fc4349..6bfffa8 100644 --- a/package/tangerine/ffi.rkt +++ b/package/tangerine/ffi.rkt @@ -25,13 +25,13 @@ (define-runtime-path tangerine-dll '(so "tangerine")) -(define-ffi-definer - define-backend - (begin +(define-ffi-definer define-backend + (let* ([fail (λ () #f)]) ; If the symbols are not already available to the process, attempt to load tangerine.dll, - ; wherever it may be. - (unless (ffi-obj-ref "EvalTree" (ffi-lib #f) (λ () #f)) - (ffi-lib tangerine-dll)) + ; wherever it may be. If Racket is embeded in Tangerine, the library + ; won't be there, so fail gracefully. + (unless (ffi-obj-ref "EvalTree" (ffi-lib #f) fail) + (ffi-lib tangerine-dll #:fail fail)) ; Then return the ffi-lib for the entire process either way. If loading the dll was ; required (and successful), this will include those foreign symbols, along with diff --git a/package/tangerine/info.rkt b/package/tangerine/info.rkt index de6a5f1..39c5f3a 100644 --- a/package/tangerine/info.rkt +++ b/package/tangerine/info.rkt @@ -14,6 +14,6 @@ (define deps '("base" "sandbox-lib" - "vec" + "vec-lib" ["tangerine-x86_64-linux" #:platform #rx"^x86_64-linux(?:-natipkg)?$"] ["tangerine-x86_64-win32" #:platform "win32\\x86_64"])) diff --git a/racket/etc/config.rktd b/racket/etc/config.rktd deleted file mode 100644 index 0ec6537..0000000 --- a/racket/etc/config.rktd +++ /dev/null @@ -1 +0,0 @@ -#hash((build-stamp . "") (catalogs . ("https://download.racket-lang.org/releases/8.5/catalog/" #f)) (doc-search-url . "https://download.racket-lang.org/releases/8.5/doc/local-redirect/index.html")) diff --git a/racket/petite.boot b/racket/petite.boot deleted file mode 100644 index 5b29806..0000000 Binary files a/racket/petite.boot and /dev/null differ diff --git a/racket/racket.boot b/racket/racket.boot deleted file mode 100644 index f48b520..0000000 Binary files a/racket/racket.boot and /dev/null differ diff --git a/racket/scheme.boot b/racket/scheme.boot deleted file mode 100644 index 7f0268e..0000000 Binary files a/racket/scheme.boot and /dev/null differ diff --git a/tangerine/.dir-locals.el b/tangerine/.dir-locals.el new file mode 100644 index 0000000..d73e3c6 --- /dev/null +++ b/tangerine/.dir-locals.el @@ -0,0 +1,4 @@ +((auto-mode-alist . (("\\.h\\'" . c++-mode))) + (c++-mode . ((c-file-style . "linux") + (c-basic-offset . 4) + (indent-tabs-mode . t)))) diff --git a/tangerine/installation.cpp b/tangerine/installation.cpp index df64458..7a87051 100644 --- a/tangerine/installation.cpp +++ b/tangerine/installation.cpp @@ -17,20 +17,44 @@ #if !_WIN64 #include +#include +#include +#include +#include +#include #endif +#if EMBED_RACKET +#include +#include +#endif + +namespace fs = std::filesystem; + +#if !_WIN64 +const char *const tangerine_app_id = + // TODO: consider a reverse-dns name with the escaping recommended in: + // https://docs.gtk.org/gio/type_func.Application.id_is_valid.html + // See rationale in: https://docs.gtk.org/gtk4/migrating-3to4.html#set-a-proper-application-id + "tangerine"; +std::optional tangerine_get_xdg_state_home(); +#endif TangerinePaths::TangerinePaths(int argc, char* argv[]) { + fs::path ExecutablePath; #if _WIN64 // TODO: This is fine for standalone builds, but we will want to do something // else for future library builds. Maybe GetModuleFileNameW? - ExecutablePath = std::filesystem::absolute(argv[0]); + ExecutablePath = fs::absolute(argv[0]); #elif EMBED_RACKET - ExecutablePath = std::filesystem::path(racket_get_self_exe_path(argv[0])); + // On Windows, `racket_get_self_exe_path()` returns UTF-8. + ExecutablePath = fs::path(racket_get_self_exe_path(argv[0])); #else + // The happy path is based on `racket_get_self_exe_path()`. + // License: (Apache-2.0 OR MIT) { char* Path = nullptr; ssize_t PathLength = 0; @@ -49,30 +73,159 @@ TangerinePaths::TangerinePaths(int argc, char* argv[]) if (PathLength < 0) { // Possibly in a chroot environment where "/proc" is not available, so fall back to generic approach. - ExecutablePath = std::filesystem::absolute(argv[0]); + ExecutablePath = fs::absolute(argv[0]); } else { Path[PathLength] = 0; - ExecutablePath = std::filesystem::path(Path); + ExecutablePath = fs::path(Path); } free(Path); } #endif - ExecutableDir = ExecutablePath.parent_path(); + fs::path ExecutableDir = ExecutablePath.parent_path(); #ifdef TANGERINE_PKGDATADIR_FROM_BINDIR #define STRINGIFY(x) #x #define EXPAND_AS_STR(x) STRINGIFY(x) - PkgDataDir = ExecutableDir / std::filesystem::path(EXPAND_AS_STR(TANGERINE_PKGDATADIR_FROM_BINDIR)); + fs::path PkgDataDir = ExecutableDir / fs::path(EXPAND_AS_STR(TANGERINE_PKGDATADIR_FROM_BINDIR)); #undef EXPAND_AS_STR #undef STRINGIFY #else - PkgDataDir = ExecutableDir; + fs::path PkgDataDir = ExecutableDir; #endif - ShadersDir = PkgDataDir / std::filesystem::path("shaders"); - ModelsDir = PkgDataDir / std::filesystem::path("models"); + ShadersDir = PkgDataDir / fs::path("shaders"); + ModelsDir = PkgDataDir / fs::path("models"); + +#if defined(TANGERINE_SELF_CONTAINED) + BookmarksPath = PkgDataDir / fs::path("bookmarks.txt"); +#elif !_WIN64 + if (std::optional dir = tangerine_get_xdg_state_home()) + { + BookmarksPath = dir.value() / fs::path(tangerine_app_id) / fs::path("bookmarks.txt"); + } + else + { + BookmarksPath = std::nullopt; + } +#else // shouldn't get here: handled in "installation.h" +# error "Windows currently requires TANGERINE_SELF_CONTAINED." + // Using %APPDATA% / CSIDL_APPDATA / FOLDERID_RoamingAppData might be useful, though +#endif +} + + +#if !_WIN64 +std::optional tangerine_get_home_dir() { + // Based on `rktio_expand_user_tilde()`. + // License: (Apache-2.0 OR MIT) + + // $HOME overrides everything. + if (const char *home = std::getenv("HOME")) + { + return fs::path(home); + } + + // $USER and $LOGNAME (in that order) override `getuid()`. + const char *alt_user_var = "USER"; + const char *alt_user = std::getenv(alt_user_var); + if (!alt_user) + { + alt_user_var = "LOGNAME"; + alt_user = std::getenv(alt_user_var); + } + + /* getpwdnam(3) man page says: "If one wants to check errno after the + call, it should be set to zero before the call." */ + errno = 0; + struct passwd* info = + alt_user ? getpwnam(alt_user) : getpwuid(getuid()); + int info_error = errno; + + // Did we find it? + if (info && info->pw_dir) + { + if (0 == info_error) + { + std::cout << "Warning: Found home directory, but "; + std::cout << (alt_user ? "getpwnam" : "getpwuid"); + std::cout << " reported an error.\n"; + } + else + { + // No warning + return fs::path(info->pw_dir); + } + } + else if (info) + { + std::cout << "Warning: User exists, but does not have a home directory.\n"; + } + else + { + std::cout << "Warning: Could not find home directory: user not found.\n"; + } + + // Add warning details: + // Was `getuid()` overridden? + if (alt_user) + { + std::cout << " user: " << alt_user << " (from $" << alt_user_var << ");\n"; + } + // Report system error. + if (0 == info_error) + { + std::cout << " error: " << std::strerror(info_error) << "\n"; + std::cout << " errno: " << info_error << "\n"; + } + else + { + std::cout << " errno: not set by "; + std::cout << (alt_user ? "getpwnam" : "getpwuid"); + std::cout << "\n"; + } + + if (info && info->pw_dir) + { + return fs::path(info->pw_dir); + } + else + { + return {}; + } +} + +std::optional tangerine_get_xdg_state_home() +{ + // Based on `rktio_system_path()`. + // License: (Apache-2.0 OR MIT) + + const char *envvar = "XDG_STATE_HOME"; + const char *default_subpath = ".local/state"; + + // Check the environment variable. + if (const char *from_env = std::getenv(envvar)) + { + fs::path candidate = fs::path(from_env); + /* We must ignore the environment variable if it is not an + absolute path. */ + if (candidate.is_absolute()) { + return candidate; + } + } + + + // Environment variable was unset or is invalid. + if (std::optional home = tangerine_get_home_dir()) + { + return home.value() / fs::path(default_subpath); + } + else + { + return {}; + } } +#endif /* !_WIN64 */ diff --git a/tangerine/installation.h b/tangerine/installation.h index 435f49d..0015497 100644 --- a/tangerine/installation.h +++ b/tangerine/installation.h @@ -15,17 +15,21 @@ #pragma once #include +#include #include "embedding.h" +#ifndef TANGERINE_SELF_CONTAINED +# ifdef _WIN64 +# define TANGERINE_SELF_CONTAINED +# endif +#endif struct TangerinePaths { TangerinePaths() {} TangerinePaths(int argc, char* argv[]); - std::filesystem::path ExecutablePath; - std::filesystem::path ExecutableDir; - std::filesystem::path PkgDataDir; std::filesystem::path ShadersDir; std::filesystem::path ModelsDir; + std::optional BookmarksPath; }; diff --git a/tangerine/racket_env.cpp b/tangerine/racket_env.cpp index 1e12232..b262fda 100644 --- a/tangerine/racket_env.cpp +++ b/tangerine/racket_env.cpp @@ -57,18 +57,52 @@ void RacketEnvironment::LoadFromString(std::string Source) LoadModelCommon(LoadAndProcess); } -void BootRacket() +#if !defined(TANGERINE_RACKET_PETITE_BOOT) +#define TANGERINE_RACKET_PETITE_BOOT ./racket/petite.boot +#endif +#if !defined(TANGERINE_RACKET_SCHEME_BOOT) +#define TANGERINE_RACKET_SCHEME_BOOT ./racket/scheme.boot +#endif +#if !defined(TANGERINE_RACKET_RACKET_BOOT) +#define TANGERINE_RACKET_RACKET_BOOT ./racket/racket.boot +#endif +#if !defined(TANGERINE_RACKET_COLLECTS_DIR) +#define TANGERINE_RACKET_COLLECTS_DIR ./racket/collects +#endif +#if !defined(TANGERINE_RACKET_CONFIG_DIR) +#define TANGERINE_RACKET_CONFIG_DIR ./racket/etc +#endif + +void BootRacket(int argc, char* argv[]) { std::cout << "Setting up Racket CS... "; racket_boot_arguments_t BootArgs; memset(&BootArgs, 0, sizeof(BootArgs)); - BootArgs.boot1_path = "./racket/petite.boot"; - BootArgs.boot2_path = "./racket/scheme.boot"; - BootArgs.boot3_path = "./racket/racket.boot"; - BootArgs.exec_file = "tangerine.exe"; - BootArgs.collects_dir = "./racket/collects"; - BootArgs.config_dir = "./racket/etc"; + BootArgs.exec_file = argv[0]; +#define STRINGIFY(x) #x +#if !defined(TANGERINE_USE_SYSTEM_RACKET) + char *SelfExe = racket_get_self_exe_path(BootArgs.exec_file); +#define RESOLVE(sym) racket_path_replace_filename(SelfExe,STRINGIFY(sym)) +#else +#define RESOLVE(sym) STRINGIFY(sym) +#endif + BootArgs.boot1_path = RESOLVE(TANGERINE_RACKET_PETITE_BOOT); + BootArgs.boot2_path = RESOLVE(TANGERINE_RACKET_SCHEME_BOOT); + BootArgs.boot3_path = RESOLVE(TANGERINE_RACKET_RACKET_BOOT); + BootArgs.collects_dir = RESOLVE(TANGERINE_RACKET_COLLECTS_DIR); + BootArgs.config_dir = RESOLVE(TANGERINE_RACKET_CONFIG_DIR); +#undef RESOLVE +#undef STRINGIFY racket_boot(&BootArgs); + std::cout << "Done!\n"; +#if !defined(TANGERINE_USE_SYSTEM_RACKET) + free(SelfExe); + free(BootArgs.boot1_path); + free(BootArgs.boot2_path); + free(BootArgs.boot3_path); + free(BootArgs.collects_dir); + free(BootArgs.config_dir); +#endif } #endif //EMBED_RACKET diff --git a/tangerine/racket_env.h b/tangerine/racket_env.h index 179071d..e58e0b5 100644 --- a/tangerine/racket_env.h +++ b/tangerine/racket_env.h @@ -33,6 +33,6 @@ struct RacketEnvironment : public ScriptEnvironment virtual ~RacketEnvironment() {} }; -void BootRacket(); +void BootRacket(int argc, char* argv[]); #endif //EMBED_RACKET diff --git a/tangerine/tangerine.cpp b/tangerine/tangerine.cpp index 038d73b..1e64f15 100644 --- a/tangerine/tangerine.cpp +++ b/tangerine/tangerine.cpp @@ -1747,11 +1747,10 @@ void RenderUI(SDL_Window* Window, bool& Live) void LoadBookmarks() { - std::filesystem::path BookmarksPath = - // FIXME might be read-only - Installed.ExecutableDir / "bookmarks.txt"; - if (std::filesystem::is_regular_file(BookmarksPath)) + std::optional maybe = Installed.BookmarksPath; + if (maybe && std::filesystem::is_regular_file(maybe.value())) { + std::filesystem::path BookmarksPath = maybe.value(); std::ifstream BookmarksFile; BookmarksFile.open(BookmarksPath); std::string Bookmark; @@ -1772,12 +1771,16 @@ void LoadBookmarks() void SaveBookmarks() { - std::filesystem::path BookmarksPath = - // FIXME might be read-only - Installed.ExecutableDir / "bookmarks.txt"; + std::optional maybe = Installed.BookmarksPath; + if (!maybe) + { + return; + } + std::filesystem::path BookmarksPath = maybe.value(); const std::vector& Bookmarks = ifd::FileDialog::Instance().GetFavorites(); if (Bookmarks.size() > 0) { + std::filesystem::create_directories(BookmarksPath.parent_path()); std::ofstream BookmarksFile; BookmarksFile.open(BookmarksPath); for (const std::string& Bookmark : Bookmarks) @@ -1786,6 +1789,10 @@ void SaveBookmarks() } BookmarksFile.close(); } + else if (std::filesystem::exists(BookmarksPath)) + { + std::filesystem::remove(BookmarksPath); + } } @@ -1931,7 +1938,7 @@ StatusCode Boot(int argc, char* argv[]) { MainEnvironment = new NullEnvironment(); #if EMBED_RACKET - BootRacket(); + BootRacket(argc, argv); #endif } { diff --git a/third_party/racket/LICENSE.txt b/third_party/racket/CMakeLists.txt similarity index 100% rename from third_party/racket/LICENSE.txt rename to third_party/racket/CMakeLists.txt diff --git a/third_party/racket/include/chezscheme.h b/third_party/racket/include/chezscheme.h deleted file mode 100644 index 013e0e0..0000000 --- a/third_party/racket/include/chezscheme.h +++ /dev/null @@ -1,262 +0,0 @@ -/* scheme.h for Chez Scheme Version 9.5.7.6 (ta6nt) */ - -/* Do not edit this file. It is automatically generated and */ -/* specifically tailored to the version of Chez Scheme named */ -/* above. Always be certain that you have the correct scheme.h */ -/* for the version of Chez Scheme you are using. */ - -/* Warning: Some macros may evaluate arguments more than once. */ - -/* Enable function prototypes by default. */ -#ifndef PROTO -#define PROTO(x) x -#endif - -/* Specify declaration of exports. */ -#ifdef _WIN32 -# if __cplusplus -# ifdef SCHEME_IMPORT -# define EXPORT extern "C" __declspec (dllimport) -# elif SCHEME_STATIC -# define EXPORT extern "C" -# else -# define EXPORT extern "C" __declspec (dllexport) -# endif -# else -# ifdef SCHEME_IMPORT -# define EXPORT extern __declspec (dllimport) -# elif SCHEME_STATIC -# define EXPORT extern -# else -# define EXPORT extern __declspec (dllexport) -# endif -# endif -#else -# if __cplusplus -# define EXPORT extern "C" -# else -# define EXPORT extern -# endif -#endif - -/* Chez Scheme Version and machine type */ -#define VERSION "9.5.7.6" -#define MACHINE_TYPE "ta6nt" - -/* All Scheme objects are of type ptr. Type iptr and */ -/* uptr are signed and unsigned ints of the same size */ -/* as a ptr */ -typedef void * ptr; -typedef long long int iptr; -typedef unsigned long long int uptr; -typedef ptr xptr; - -/* The `uptr` and `ptr` types are the same width, but `ptr` */ -/* can be either an integer type or a pointer type; it may */ -/* be larger than a pointer type. */ -/* Use `TO_VOIDP` to get from the `uptr`/`ptr` world to the */ -/* C pointer worlds, and use `TO_PTR` to go the other way. */ -#ifdef PORTABLE_BYTECODE -# define TO_VOIDP(p) ((void *)(intptr_t)(p)) -# define TO_PTR(p) ((ptr)(intptr_t)(p)) -#else -# define TO_VOIDP(p) ((void *)(p)) -# define TO_PTR(p) ((ptr)(p)) -#endif - -/* String elements are 32-bit tagged char objects */ -typedef unsigned int string_char; - -/* Bytevector elements are 8-bit unsigned "octets" */ -typedef unsigned char octet; - -/* Type predicates */ -#define Sfixnump(x) (((uptr)(x)&0x7)==0x0) -#define Scharp(x) (((uptr)(x)&0xFF)==0x16) -#define Snullp(x) ((uptr)(x)==0x26) -#define Seof_objectp(x) ((uptr)(x)==0x36) -#define Sbwp_objectp(x) ((uptr)(x)==0x4E) -#define Sbooleanp(x) (((uptr)(x)&0xF7)==0x6) -#define Spairp(x) (((uptr)(x)&0x7)==0x1) -#define Ssymbolp(x) (((uptr)(x)&0x7)==0x3) -#define Sprocedurep(x) (((uptr)(x)&0x7)==0x5) -#define Sflonump(x) (((uptr)(x)&0x7)==0x2) -#define Svectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ - (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x0)) -#define Sfxvectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ - (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xF)==0x3)) -#define Sflvectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ - (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xF)==0xB)) -#define Sbytevectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ - (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3)==0x1)) -#define Sstringp(x) ((((uptr)(x)&0x7)==0x7) &&\ - (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x2)) -#define Sstencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ - (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3F)==0x1E)) -#define Sbignump(x) ((((uptr)(x)&0x7)==0x7) &&\ - (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1F)==0x6)) -#define Sboxp(x) ((((uptr)(x)&0x7)==0x7) &&\ - (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7F)==0xE)) -#define Sinexactnump(x) ((((uptr)(x)&0x7)==0x7) &&\ - ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x36)) -#define Sexactnump(x) ((((uptr)(x)&0x7)==0x7) &&\ - ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x56)) -#define Sratnump(x) ((((uptr)(x)&0x7)==0x7) &&\ - ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x16)) -#define Sinputportp(x) ((((uptr)(x)&0x7)==0x7) &&\ - (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1FF)==0x1CE)) -#define Soutputportp(x) ((((uptr)(x)&0x7)==0x7) &&\ - (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x2FF)==0x2CE)) -#define Srecordp(x) ((((uptr)(x)&0x7)==0x7) &&\ - (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x7)) - -/* Accessors */ -#define Sfixnum_value(x) ((iptr)(x)/8) -#define Schar_value(x) ((string_char)((uptr)(x)>>8)) -#define Sboolean_value(x) ((x) != Sfalse) -#define Scar(x) (*((ptr *)TO_VOIDP((uptr)(x)+7))) -#define Scdr(x) (*((ptr *)TO_VOIDP((uptr)(x)+15))) -#define Sflonum_value(x) (*((double *)TO_VOIDP((uptr)(x)+6))) -#define Svector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) -#define Svector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) -#define Sfxvector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) -#define Sfxvector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) -#define Sflvector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) -#define Sflvector_ref(x,i) (((double *)TO_VOIDP((uptr)(x)+9))[i]) -#define Sbytevector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>3)) -#define Sbytevector_u8_ref(x,i) (((octet *)TO_VOIDP((uptr)(x)+9))[i]) -/* Warning: Sbytevector_data(x) returns a pointer into x. */ -#define Sbytevector_data(x) &Sbytevector_u8_ref(x,0) -#define Sstring_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) -#define Sstring_ref(x,i) Schar_value(((string_char *)TO_VOIDP((uptr)(x)+9))[i]) -#define Sunbox(x) (*((ptr *)TO_VOIDP((uptr)(x)+9))) -#define Sstencil_vector_length(x) Spopcount(((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1))))>>6) -#define Sstencil_vector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) -EXPORT iptr Sinteger_value PROTO((ptr)); -#define Sunsigned_value(x) (uptr)Sinteger_value(x) -EXPORT int Sinteger32_value PROTO((ptr)); -#define Sunsigned32_value(x) (unsigned int)Sinteger32_value(x) -EXPORT long long Sinteger64_value PROTO((ptr)); -#define Sunsigned64_value(x) (unsigned long long)Sinteger64_value(x) - -/* Mutators */ -EXPORT void Sset_box PROTO((ptr, ptr)); -EXPORT void Sset_car PROTO((ptr, ptr)); -EXPORT void Sset_cdr PROTO((ptr, ptr)); -#define Sstring_set(x,i,c) ((void)((((string_char *)TO_VOIDP((uptr)(x)+9))[i]) = (string_char)(uptr)Schar(c))) -#define Sfxvector_set(x,i,n) ((void)(Sfxvector_ref(x,i) = (n))) -#define Sflvector_set(x,i,n) ((void)(Sflvector_ref(x,i) = (n))) -#define Sbytevector_u8_set(x,i,n) ((void)(Sbytevector_u8_ref(x,i) = (n))) -EXPORT void Svector_set PROTO((ptr, iptr, ptr)); - -/* Constructors */ -#define Sfixnum(x) ((ptr)(uptr)((x)*8)) -#define Schar(x) ((ptr)(uptr)((x)<<8|0x16)) -#define Snil ((ptr)0x26) -#define Strue ((ptr)0xE) -#define Sfalse ((ptr)0x6) -#define Sboolean(x) ((x)?Strue:Sfalse) -#define Sbwp_object ((ptr)0x4E) -#define Seof_object ((ptr)0x36) -#define Svoid ((ptr)0x3E) -EXPORT ptr Scons PROTO((ptr, ptr)); -EXPORT ptr Sstring_to_symbol PROTO((const char *)); -EXPORT ptr Ssymbol_to_string PROTO((ptr)); -EXPORT ptr Sflonum PROTO((double)); -EXPORT ptr Smake_vector PROTO((iptr, ptr)); -EXPORT ptr Smake_fxvector PROTO((iptr, ptr)); -EXPORT ptr Smake_flvector PROTO((iptr, ptr)); -EXPORT ptr Smake_bytevector PROTO((iptr, int)); -EXPORT ptr Smake_string PROTO((iptr, int)); -EXPORT ptr Smake_uninitialized_string PROTO((iptr)); -EXPORT ptr Sstring PROTO((const char *)); -EXPORT ptr Sstring_of_length PROTO((const char *, iptr)); -EXPORT ptr Sstring_utf8 PROTO((const char*, iptr)); -EXPORT ptr Sbox PROTO((ptr)); -EXPORT ptr Sinteger PROTO((iptr)); -EXPORT ptr Sunsigned PROTO((uptr)); -EXPORT ptr Sinteger32 PROTO((int)); -EXPORT ptr Sunsigned32 PROTO((unsigned int)); -EXPORT ptr Sinteger64 PROTO((long long)); -EXPORT ptr Sunsigned64 PROTO((unsigned long long)); - -/* Records */ -#define Srecord_uniform_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) -EXPORT ptr Srecord_type PROTO((ptr)); -EXPORT ptr Srecord_type_parent PROTO((ptr)); -EXPORT int Srecord_type_uniformp PROTO((ptr)); -EXPORT uptr Srecord_type_size PROTO((ptr)); - -/* Miscellaneous */ -EXPORT ptr Stop_level_value PROTO((ptr)); -EXPORT void Sset_top_level_value PROTO((ptr, ptr)); -EXPORT void Slock_object PROTO((ptr)); -EXPORT void Sunlock_object PROTO((ptr)); -EXPORT int Slocked_objectp PROTO((ptr)); -EXPORT void Sforeign_symbol PROTO((const char *, void *)); -EXPORT void Sregister_symbol PROTO((const char *, void *)); - -/* Support for calls into Scheme */ -EXPORT ptr Scall0 PROTO((ptr)); -EXPORT ptr Scall1 PROTO((ptr, ptr)); -EXPORT ptr Scall2 PROTO((ptr, ptr, ptr)); -EXPORT ptr Scall3 PROTO((ptr, ptr, ptr, ptr)); -EXPORT void Sinitframe PROTO((iptr)); -EXPORT void Sput_arg PROTO((iptr, ptr)); -EXPORT ptr Scall PROTO((ptr, iptr)); -/* Warning: Sforeign_callable_entry_point(x) returns a pointer into x. */ -#define Sforeign_callable_entry_point(x) ((void (*) PROTO((void)))TO_VOIDP((uptr)(x)+65)) -#define Sforeign_callable_code_object(x) ((ptr)TO_VOIDP((uptr)(x)-65)) - -/* Customization support. */ -EXPORT const char * Skernel_version PROTO((void)); -EXPORT void Sretain_static_relocation PROTO((void)); -EXPORT void Sset_verbose PROTO((int)); -EXPORT void Sscheme_init PROTO((void (*)(void))); -EXPORT void Sregister_boot_file PROTO((const char *)); -EXPORT void Sregister_boot_direct_file PROTO((const char *)); -EXPORT void Sregister_boot_file_fd PROTO((const char *, int fd)); -EXPORT void Sregister_boot_file_fd_region PROTO((const char *, int fd, iptr offset, iptr len, int close_after)); -EXPORT void Sregister_heap_file PROTO((const char *)); -EXPORT void Scompact_heap PROTO((void)); -EXPORT void Ssave_heap PROTO((const char *, int)); -EXPORT void Sbuild_heap PROTO((const char *, void (*)(void))); -EXPORT void Senable_expeditor PROTO((const char *)); -EXPORT int Sscheme_start PROTO((int, const char *[])); -EXPORT int Sscheme_script PROTO((const char *, int, const char *[])); -EXPORT int Sscheme_program PROTO((const char *, int, const char *[])); -EXPORT void Sscheme_deinit PROTO((void)); -EXPORT void Sscheme_register_signal_registerer PROTO((void (*f)(int))); - -/* Thread support. */ -EXPORT int Sactivate_thread PROTO((void)); -EXPORT void Sdeactivate_thread PROTO((void)); -EXPORT int Sdestroy_thread PROTO((void)); - -/* Windows support. */ -#include -EXPORT char * Sgetenv PROTO((const char *)); -EXPORT wchar_t * Sutf8_to_wide PROTO((const char *)); -EXPORT char * Swide_to_utf8 PROTO((const wchar_t *)); - -/* Features. */ -#define FEATURE_ICONV -#define FEATURE_EXPEDITOR -#define FEATURE_PTHREADS -#define FEATURE_WINDOWS - -/* Locking macros. */ -#define INITLOCK(addr) (*((long long *) addr) = 0) - -#define SPINLOCK(addr) \ -{ \ - while (_InterlockedExchange64(addr, 1) != 0) { \ - while(*((long long *) addr) != 0); \ - } \ -} while(0) - -#define UNLOCK(addr) (*((long long *) addr) = 0) - -#define LOCKED_INCR(addr, res) (res = (-1 == _InterlockedExchangeAdd64(addr, 1))) - -#define LOCKED_DECR(addr, res) (res = (1 == _InterlockedExchangeAdd64(addr, -1))) diff --git a/third_party/racket/include/racketcs.h b/third_party/racket/include/racketcs.h deleted file mode 100644 index 0ee37b9..0000000 --- a/third_party/racket/include/racketcs.h +++ /dev/null @@ -1,31 +0,0 @@ -/* include "chezscheme.h" before this file */ - -#ifndef RACKETCS_H -#define RACKETCS_H - -#ifndef RACKET_API_EXTERN -# define RACKET_API_EXTERN EXPORT -#endif - -#ifndef RACKETCS_BOOT_H -# define BOOT_EXTERN EXPORT -# include "racketcsboot.h" -#endif - -RACKET_API_EXTERN ptr racket_apply(ptr proc, ptr arg_list); - -RACKET_API_EXTERN ptr racket_primitive(const char *name); - -RACKET_API_EXTERN ptr racket_eval(ptr s_expr); -RACKET_API_EXTERN ptr racket_dynamic_require(ptr module_path, ptr sym_or_false); -RACKET_API_EXTERN void racket_namespace_require(ptr module_path); - -RACKET_API_EXTERN void racket_embedded_load_bytes(const char *code, uptr len, int as_predefined); -RACKET_API_EXTERN void racket_embedded_load_file(const char *path, int as_predefined); -RACKET_API_EXTERN void racket_embedded_load_file_region(const char *path, uptr start, uptr end, int as_predefined); - -RACKET_API_EXTERN void *racket_cpointer_address(ptr cptr); -RACKET_API_EXTERN void *racket_cpointer_base_address(ptr cptr); -RACKET_API_EXTERN iptr racket_cpointer_offset(ptr cptr); - -#endif diff --git a/third_party/racket/include/racketcsboot.h b/third_party/racket/include/racketcsboot.h deleted file mode 100644 index e7af141..0000000 --- a/third_party/racket/include/racketcsboot.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef RACKETCS_BOOT_H -#define RACKETCS_BOOT_H - -/* This structure type can change, but NULL/0 will be supported as a - default for any new field that is added. */ -typedef struct racket_boot_arguments_t { - /* Boot files --- potentially the same path with different offsets. - If a boot image is embedded in a larger file, it must be - terminated with "\177". */ - const char *boot1_path; /* REQUIRED; path to "petite.boot" */ - long boot1_offset; - long boot1_len; /* 0 => unknown length */ - const char *boot2_path; /* REQUIRED; path to "scheme.boot" */ - long boot2_offset; - long boot2_len; /* 0 => unknown length */ - const char *boot3_path; /* REQUIRED; path to "racket.boot" */ - long boot3_offset; - long boot3_len; /* 0 => unknown length */ - - /* Command-line arguments are handled in the same way as the - `racket` exectuable. The `argv` array should *not* include the - executable name like `argv` passed to `main`. */ - int argc; - char **argv; /* NULL => "-n", which does nothing after booting */ - - /* Racket path configuration, mostly setting the results of - `(find-system-path ...)`: */ - const char *exec_file; /* REQUIRED; usually the original argv[0] */ - const char *run_file; /* can be NULL to mean the same as `exec_file` */ - const char *collects_dir; /* can be NULL or "" to disable collection path */ - const char *config_dir; /* use NULL or "etc" if you don't care */ - /* wchar_t * */void *dll_dir; /* can be NULL for default */ - const char *k_file; /* for -k; can be NULL for the same as `exec_file` */ - - /* How to initialize `use-compiled-file-paths`: */ - int cs_compiled_subdir; /* true => subdirectory of "compiled" */ - - /* Embedded-code offset, which is added to any `-k` argument. */ - long segment_offset; /* use 0 if no `-k` embedding */ - - /* For embedded DLLs on Windows, if non-NULL: */ - void *dll_open; - void *dll_find_object; - void *dll_close; - - /* Whether to run as command-line Racket or in embedded mode: */ - int exit_after; /* 1 => exit after handling the command-line */ - - /* For GUI applications; use 0 and "" as defaults: */ - int is_gui; - int wm_is_gracket_or_x11_arg_count; - char *gracket_guid_or_x11_args; -} racket_boot_arguments_t; - -BOOT_EXTERN void racket_boot(racket_boot_arguments_t *boot_args); - -/* Same as `racket_boot` prototype; but in type form: */ -typedef void (*racket_boot_t)(racket_boot_arguments_t *boot_args); - -#endif diff --git a/third_party/racket/lib/libracketcs_db9xz4.def b/third_party/racket/lib/libracketcs_db9xz4.def deleted file mode 100644 index 4b67c2d..0000000 --- a/third_party/racket/lib/libracketcs_db9xz4.def +++ /dev/null @@ -1,21 +0,0 @@ -EXPORTS -racket_boot -declare_modules -Scons -Sstring_to_symbol -Sstring -Sstring_utf8 -Snil -Sflonum -Sinteger -racket_dynamic_require -racket_embedded_load_bytes -racket_embedded_load_file -Smake_bytevector -racket_namespace_require -racket_eval -racket_apply -Ssymbol_to_string -Sinteger32_value -Sactivate_thread -Sdeactivate_thread