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 <flags>
   where <flags> is the set of flags you have chosen.
3. Use "make" followed by "make install" to build and install ECL.

* MacOS/arm64 (Apple M)

The process is similar to a typical UNIX, but ~configure~ and ~make~ must be
preceeded with the architecture specification:

#+begin_src sh
  arch -arm64 ./configure
  arch -arm64 make
  make install
#+end_src

* Cross-compile for Windows64 using MinGW
1. Install MinGW64 toolchain, for example:
   #+begin_src shell-scrip
     sudo zypper install mingw64-cross-gcc
   #+end_src
   If GMP does not build, see whether the repository has a prepackaged version.
2. Build and install ECL
   #+begin_src shell-lsscript
     ./configure --host=x86_64-w64-mingw32 --prefix=`pwd`/ecl-win64 --with-cross-config=`pwd`/src/util/x86_64-w64-mingw32.cross_config
     make && make install
   #+end_src
   Note that ~mingw32~ is an arbitrary suffix and not a typo, we are still
   bulding for 64-bit Windows.
3. Run application using Wine
   #+begin_src shell-script
     pushd ecl-win64
     wine ecl.exe
   #+end_src
   It may happen that wine is not configured to know where are libraries
   provided by MinGW. In that case they need to be linked or copied here.
   #+begin_src shell-script
     pushd ecl-win64
     ln -s /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libgcc_s_seh-1.dll .
     ln -s /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libgmp-10.dll .
     ln -s /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll .
     wine ecl.exe
   #+end_src

* Cross-compile for Windows32 using MinGW
1. Install MinGW64 toolchain, for example:
   #+begin_src shell-scrip
     sudo zypper install mingw32-cross-gcc
   #+end_src
   If GMP does not build, see whether the repository has a prepackaged version.
2. Build and install ECL
   #+begin_src shell-script
     ./configure --host=i686-w64-mingw32 --prefix=`pwd`/ecl-win32 --with-cross-config=`pwd`/src/util/i686-w64-mingw32.cross_config
     make && make install
   #+end_src
3. Run application using Wine
   #+begin_src shell-script
     pushd ecl-win32
     wine ecl.exe
   #+end_src
   It may happen that wine is not configured to know where are libraries
   provided by MinGW. In that case they need to be linked or copied here.
   #+begin_src shell-script
     pushd ecl-win32
     ln -s /usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_seh-1.dll .
     ln -s /usr/i686-w64-mingw32/sys-root/mingw/bin/libgmp-10.dll .
     ln -s /usr/i686-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll .
     wine ecl.exe
   #+end_src

* Cross-compile for the android platform (from the UNIX machine)
1. Configure the toolchain (requires android-ndk version 22 or higher, known to work with version 28b)
   and export the necessary paths:
   #+BEGIN_SRC shell-script
     export NDK_PATH=/opt/android-ndk
     export ANDROID_API=23
     export TOOLCHAIN_PATH=${NDK_PATH}/toolchains/llvm/prebuilt/linux-x86_64 # use darwin instead of linux if compiling on Mac OS host
     export TARGET=armv7a-linux-androideabi
  #+END_SRC
2. Build and install the target library
   #+BEGIN_SRC shell-script
	  export CC="${TOOLCHAIN_PATH}/bin/clang --target=${TARGET}${ANDROID_API}"
	  export LD=${TOOLCHAIN_PATH}/bin/ld
	  export AR=${TOOLCHAIN_PATH}/bin/llvm-ar
	  export RANLIB=${TOOLCHAIN_PATH}/bin/llvm-ranlib
     export ECL_TO_RUN=/usr/local/bin/ecl
    ./configure --host=${TARGET} \
                 --prefix=`pwd`/ecl-android \
                 --disable-c99complex \
                 --with-cross-config=`pwd`/src/util/android-arm.cross_config
     make -j9
     make install
   #+END_SRC
3. Library and assets in the ecl-android directory are ready to run on
   the Android system.


* Cross-compile for the iOS platform (needs Xcode 11 or higher)
1. 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
2. Build and install the target library
   #+BEGIN_SRC shell-script
     export CFLAGS="$CFLAGS -DGC_DISABLE_INCREMENTAL -DECL_RWLOCK"
     export CXXFLAGS="$CFLAGS"
     export ECL_TO_RUN=/usr/local/bin/ecl
     ./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
3. 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. 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 4.0.12~. 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
  # You may customize various emscripten flags here, i.e:
  # export LDFLAGS="-sASYNCIFY=1"
#+end_src

2. Build the core environment and install it

#+begin_src shell-script
  export ECL_TO_RUN=/usr/local/bin/ecl
  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

3. 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.

4. 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
  LSP_FEATURES=":cosmo" ./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.
