diff --git a/.gitignore b/.gitignore index 16c8ed7..d493eb1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ /boids_main /libboids.so /game.fasl +/writeimage diff --git a/ECL-INSTALL b/ECL-INSTALL new file mode 100644 index 0000000..261fffb --- /dev/null +++ b/ECL-INSTALL @@ -0,0 +1,270 @@ +You will find detailed installation instructions in the ECL manual + https://common-lisp.net/project/ecl/static/manual/Building-ECL.html +If you do not have access to the online version, follow the following recipies. + +* Unix and similar platforms. +1. Type + ./configure --help + to get a list of the flags with which ECL can be configured. +2. Enter + ./configure ... + where "..." is the set of flags you have chosen. +3. Use "make" followed by "make install" to build and install ECL. + +* Windows with Visual Studio C++ 2008 +1. Open the Visual Studio x86 or x64 native tools command prompt +2. Enter the msvc directory +3. Read the file Makefile to find the configuration options. They + typically have the form ECL_UNICODE=1, ECL_THREADS=1, etc +4. Enter + nmake ... + followed by zero or more of those options +5. Use "nmake install" to create a directory called "package" with ECL in it. +6. Move that directory wherever you need. + +* Cross-compile for the android platform (from the UNIX machine) +1. Build the host ECL + #+BEGIN_SRC shell-script + # C99 complex numbers are not fully supported on Android + ./configure ABI=32 CFLAGS="-m32 -g -O2" LDFLAGS="-m32 -g -O2"\ + --prefix=`pwd`/ecl-android-host --disable-c99complex + make -j9 + make install + rm -r build + export ECL_TO_RUN=`pwd`/ecl-android-host/bin/ecl + #+END_SRC +2. Configure the toolchain (requires android-ndk version 15 or higher, known to work with version 17c) + and export the necessary paths: + #+BEGIN_SRC shell-script + export NDK_PATH=/opt/android-ndk + export ANDROID_API=23 + export TOOLCHAIN_PATH=`pwd`/android-toolchain + ${NDK_PATH}/build/tools/make_standalone_toolchain.py --arch arm --install-dir ${TOOLCHAIN_PATH} --api ${ANDROID_API} + export SYSROOT=${TOOLCHAIN_PATH}/sysroot + export PATH=${TOOLCHAIN_PATH}/bin:$PATH + #+END_SRC +3. Build and install the target library + #+BEGIN_SRC shell-script + # boehm GC is not compatible with ld.gold linker, force use of ld.bfd + export LDFLAGS="--sysroot=${SYSROOT} -D__ANDROID_API__=${ANDROID_API} -fuse-ld=bfd" + export CPPFLAGS="--sysroot=${SYSROOT} -D__ANDROID_API__=${ANDROID_API} -isystem ${SYSROOT}/usr/include/arm-linux-androideabi" + export CC=arm-linux-androideabi-clang + ./configure --host=arm-linux-androideabi \ + --prefix=`pwd`/ecl-android \ + --disable-c99complex \ + --with-cross-config=`pwd`/src/util/android-arm.cross_config + make -j9 + make install + #+END_SRC +4. Library and assets in the ecl-android directory are ready to run on + the Android system. + +** Building ecl-android on Darwin (OSX) +If your host platform is darwin, then the host compiler should be +built with the Apple's GCC (not the GCC from Macports). Using the +MacPort command: +#+BEGIN_SRC shell-script + sudo port select --set gcc none +#+END_SRC + +Hint provided by Pascal J. Bourguignon. + + +* Cross-compile for the iOS platform (needs Xcode 11 or higher) +1. Build the host ECL + #+BEGIN_SRC shell-script + ./configure CFLAGS="-DECL_C_COMPATIBLE_VARIADIC_DISPATCH" --prefix=`pwd`/ecl-iOS-host --disable-c99complex + make -j9 + make install + rm -r build + export ECL_TO_RUN=`pwd`/ecl-iOS-host/bin/ecl + #+END_SRC +2. Configure the toolchain + #+BEGIN_SRC shell-script + export IOS_VERSION_MIN="8.0" + export IOS_SDK_DIR="`xcode-select --print-path`/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/" + + export CC="clang" + export CXX="clang++" + + export CFLAGS="-arch arm64 -miphoneos-version-min=${IOS_VERSION_MIN} -isysroot ${IOS_SDK_DIR}" + export CFLAGS="$CFLAGS -pipe -Wno-trigraphs -Wreturn-type -Wunused-variable" + export CFLAGS="$CFLAGS -fpascal-strings -fasm-blocks -fmessage-length=0 -fvisibility=hidden" + export CFLAGS="$CFLAGS -O2 -DNO_ASM" + + export LD="ld" + export LDFLAGS="-arch arm64 -pipe -std=c99 -gdwarf-2 -isysroot ${IOS_SDK_DIR}" + export LIBS="-framework Foundation" + #+END_SRC +3. Build and install the target library + #+BEGIN_SRC shell-script + export CFLAGS="$CFLAGS -DGC_DISABLE_INCREMENTAL -DECL_RWLOCK" + export CXXFLAGS="$CFLAGS" + ./configure --host=aarch64-apple-darwin \ + --prefix=`pwd`/ecl-iOS \ + --disable-c99complex \ + --disable-shared \ + --with-cross-config=`pwd`/src/util/iOS-arm64.cross_config + make -j9 + make install + #+END_SRC +4. Library and assets in the ecl-iOS directory are ready to run on + the iOS system. + +* Cross-compile for the WASM platform (via emscripten) + +Emscripten target is a little fickle so keep in mind that: + +- shared libraries are supported but come with some drawbacks (e.g. + increased code size if used together with -sASYNCIFY), therefore the + build instructions default to disable-shared + +- disable-tcp is needed, because accept can't be found (lack of + -lsockets or something in this spirit?) + +- select for interactive streams does not work, because reading operations are + blocking (as they should be!), so there is no EOF returned -- clear-input will + hang without a proper file-cnt + +- to build emscripten you need to use their SDK that provides the toolchain, and + set the environment variable EMSDK_PATH + +- for the garbage collector to be able to identify roots on the stack, + you need to pass the -sBINARYEN_EXTRA_PASSES=--spill-pointers option + to the linker for all of your code that might store pointer on the + stack (for instance when embedding ECL) + +- the optimization level -O0 is used because higher optimization + levels seem to interfere with the binaryen options needed to get the + garbage collector to work correctly and tend slow down the program + (might be worth experimenting with the optimization options) + +1. Build the host ECL + +#+begin_src shell-script + ./configure ABI=32 CFLAGS="-m32 -g -O2 -DECL_C_COMPATIBLE_VARIADIC_DISPATCH" LDFLAGS="-m32 -g -O2" \ + --prefix=`pwd`/ecl-emscripten-host --disable-threads + + make -j16 && make install + rm -rf build/ +#+end_src + +2. Configure the toolchain + +Install the Emscripten SDK using the official instructions: + + https://emscripten.org/docs/getting_started/downloads.html + +These build instructions were tested against ~emsdk 3.1.41~. If things doesn't +work try that version instead of ~latest~. + +After that activate the toolchain and configure build flags: + +#+begin_src shell-script + source ${EMSDK_PATH}/emsdk_env.sh + export ECL_TO_RUN=`pwd`/ecl-emscripten-host/bin/ecl + # You may customize various emscripten flags here, i.e: + # export LDFLAGS="-sASYNCIFY=1" +#+end_src + +3. Build the core environment and install it + +#+begin_src shell-script + emconfigure ./configure \ + --host=wasm32-unknown-emscripten \ + --build=x86_64-pc-linux-gnu \ + --with-cross-config=`pwd`/src/util/wasm32-unknown-emscripten.cross_config \ + --prefix=`pwd`/ecl-emscripten \ + --disable-shared \ + --with-tcp=no \ + --with-cmp=no + + emmake make && emmake make install + + # some files need to be copied manually + cp build/bin/ecl.js build/bin/ecl.wasm ecl-emscripten/ +#+end_src + +4. ECL may be hosted on a web page. Assuming that you have quicklisp installed: + +#+begin_src shell-script + export WEBSERVER=`pwd`/src/util/webserver.lisp + pushd ecl-emscripten/ + lisp --load $WEBSERVER + # After the server is loaded run: + # firefox localhost:8888/ecl.html + popd +#+end_src + +If the output does not show on the webpage then open the javascript console. +This is a default html website produced by emscripten. + +5. Build an external program linked against libecl.a + +The default stack size proposed by emscripten is 64KB. This is too little for +ECL, so when you build a program that is linked against libecl.a, then it is +imoprtant to specify a different size. For example: + +#+begin_src shell-script + emcc program.c -sSTACK_SIZE=1048576 lib/*.a -I./include -o program.o +#+end_src + +* Build using Cosmopolitan toolchain (experimental) + +Binaries built with cosmopolitan toolchain can be executed on numerous platforms +without changes. An inititial ECL port has been completed. + +1. Download cosmopolitan toolchain and activate it + +Instructions for downloading the toolchain are available in its [[https://github.com/jart/cosmopolitan/blob/master/README.md ][repository]]. +For example: + +#+begin_src sh + mkdir cosmocc + pushd cosmocc + curl -o https://cosmo.zip/pub/cosmocc/cosmocc.zip + unzip *zip + bin/make --version # sanity test + export PATH="`pwd`/bin:${PATH}" + export CC=x86_64-unknown-cosmo-cc + export CXX=x86_64-unknown-cosmo-c++ + popd +#+end_src + +2. Build ECL + +#+begin_src sh + ./configure --disable-shared --prefix=/tmp/cosmo-cl + make -j15 + make install + # make check +#+end_src + +- The platform is reported in *FEATURES* as :COSMO and as :LINUX +- make check will fail because libc segfaults when using fenv.h + +This platform is not upstreamed yet in libgc, so it may be necessary to add the +following code to the file gcconfig.h: + +#+begin_src c +# if defined(__COSMOPOLITAN__) +# if defined(__x86_64__) +# define mach_type_known +# define X86_64 +# define LINUX // optional? +# elif defined(__aarch64__) +# define mach_type_known +# define AARCH64 +# define LINUX // optional? +# endif +# endif +#+end_src + +For details see: https://github.com/jart/cosmopolitan/issues/939. + +Cosmopolitan condition variables can't be used with mutexes that are not +initialized as PTHREAD_MUTEX_NORMAL. That means that recursive locks and +deterministic deadlock detection are not supported on this platform. + +Moreover floating point exception handling is not working and it is libc issue +that manifests itself with segfaults. diff --git a/README.org b/README.org new file mode 100644 index 0000000..5ab39d9 --- /dev/null +++ b/README.org @@ -0,0 +1,12 @@ + +#+begin_src shell + +gcc -lecl ecl_test.c -o test-game libtest-game.a +#+end_src + +#+begin_src lisp +(uiop:getcwd) +(uiop:chdir "Development/tinyswords/") +(compile-file "game.lisp" :system-p t) +(c:build-static-library "test-game" :lisp-files '("game.o") :init-name "game") +#+end_src diff --git a/ecl_test.c b/ecl_test.c new file mode 100644 index 0000000..0c2a39b --- /dev/null +++ b/ecl_test.c @@ -0,0 +1,15 @@ +#include + +extern void game(cl_object cblock); + +int main(int argc, char **argv) +{ + /* setup the lisp runtime */ + cl_boot(argc, argv); + /* call the init function via read_VV */ + read_VV(OBJNULL, game); + /* ... */ + /* shutdown the lisp runtime */ + cl_shutdown(); + return 0; +} diff --git a/game.lisp b/game.lisp index d400e1d..d8bd840 100644 --- a/game.lisp +++ b/game.lisp @@ -1,3 +1,5 @@ +(load "~/quicklisp/setup.lisp") + (eval-when (:compile-toplevel :load-toplevel :execute) (ql:quickload :cl-raylib)) @@ -66,7 +68,7 @@ :white) (rl:draw-fps 10 5)) -(defun main () +(defun game () (let* ((screen-width 900) (screen-height 500)) (rl:with-window (screen-width screen-height "RTS") @@ -80,4 +82,4 @@ (loop for value being the hash-values of (game-state-textures *game-state*) do (rl:unload-texture value))))) -(main) +(game)