Skip to content

Instantly share code, notes, and snippets.

@privet-kitty
Last active October 29, 2022 16:59
Show Gist options
  • Save privet-kitty/4b2b811cf2cee94b8a502b930f542fb3 to your computer and use it in GitHub Desktop.
Save privet-kitty/4b2b811cf2cee94b8a502b930f542fb3 to your computer and use it in GitHub Desktop.
faslize
#!/usr/bin/env bash
# Copyright 2020 Hugo Sansaqua
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# This shell script compiles a lisp file and converts the fasl to a submittable
# format using Base64. The main targets are CS Academy and HackerEarth, which
# don't precompile a lisp file but execute it directly by --script option.
set -ue -o pipefail
IMPL="" # TODO: better default
OMIT_SOURCE=0
VERSION=""
PRESET_NAME="none"
if [ $(uname) != "Linux" ]; then
echo "WARNING (uname: $(uname)): non-Linux may cause a trouble" 1>&2
fi
USAGE="Usage: $0 [-s] [-p csa|he] [-L impl/version] [-v version] lisp_file
Options:
-s : don't attach original source
-p csa|he: use preset (CS Academy or HackerEarth)
-L impl/version : pass impl/version to ros -L (e.g. sbcl-bin/2.0.6)
-v version : overwrite version string (e.g. 2.0.6.debian)
Example:
faslize -p csa main.lisp | xsel -bi"
usage_exit() {
echo "${USAGE}" 1>&2
exit 1
}
set_csacademy() {
PRESET_NAME="CS Academy"
IMPL="sbcl-bin/2.0.6"
VERSION="2.0.6.debian"
}
set_hackerearth() {
PRESET_NAME="HackerEarth"
IMPL="sbcl-bin/1.3.1"
VERSION="1.3.1.debian"
}
while getopts sp:L:v: OPT; do
case "$OPT" in
p)
case "$OPTARG" in
csa) set_csacademy
;;
he) set_hackerearth
;;
*) usage_exit
;;
esac
;;
s) OMIT_SOURCE=1
;;
L) IMPL="$OPTARG"
;;
v) VERSION="$OPTARG"
;;
\?) usage_exit
;;
esac
done
shift $((OPTIND - 1))
if [ $# -ne 1 ]; then
usage_exit
fi
LISP_PATHNAME="$1"
BASENAME=$(echo ${LISP_PATHNAME} | sed 's/\.[^\.]*$//')
FASL_PATHNAME="${BASENAME}.fasl"
if [ -n "$IMPL" ]; then
IMPL_OPTION="-L $IMPL"
else
IMPL_OPTION=""
fi
ROS_COMMAND="ros run ${IMPL_OPTION} +Q -- --no-sysinit --no-userinit --noprint --disable-debugger"
if [ -n "$VERSION" ]; then
${ROS_COMMAND} \
--eval "(sb-ext:unlock-package :cl)" \
--eval "(setf (symbol-function 'lisp-implementation-version) (lambda () \"$VERSION\"))" \
--eval "(sb-ext:lock-package :cl)" \
--eval "(compile-file \"${LISP_PATHNAME}\" :verbose nil :print nil)" \
--quit
else
${ROS_COMMAND} \
--eval "(compile-file \"${LISP_PATHNAME}\" :verbose nil :print nil)" \
--quit
fi
BASE64=$(base64 ${FASL_PATHNAME})
if [ $OMIT_SOURCE -eq 0 ]; then
HEADER_COMMENT=";; Source code is attached to the bottom."
else
HEADER_COMMENT=""
fi
if [ -z "$VERSION" ]; then
VERSION=$(${ROS_COMMAND} --eval "(write-string (lisp-implementation-version))" --quit)
fi
if [ -z "$IMPL" ]; then
IMPL="$(ros config show default.lisp)/$(ros config show sbcl-bin.version)"
fi
echo "Preset name: ${PRESET_NAME}" 1>&2
echo "Compiler: ${IMPL}" 1>&2
echo "Version string: ${VERSION}" 1>&2
TEMPLATE=";; This file is compiled by ${IMPL} with version string ${VERSION}.
${HEADER_COMMENT}
(defpackage :faslize (:use :cl) (:export #:*fasl-pathname*))
(in-package :faslize)
(defparameter *fasl64* \"${BASE64}\")
(defparameter *fasl-pathname* (make-pathname :defaults *load-pathname* :type \"fasl\"))
;; KLUDGE: Some judge (e.g. HackerEarth) doesn't allow writing to /tmp
(let ((tmpdir (namestring (make-pathname :defaults *load-pathname* :name nil :type nil)))
(saved #'sb-impl::get-temporary-directory))
(sb-ext:unlock-package :sb-impl)
(setf (symbol-function 'sb-impl::get-temporary-directory) (lambda () tmpdir))
(with-open-file (out *fasl-pathname* :direction :output
:if-exists :supersede
:element-type '(unsigned-byte 8))
(sb-ext:run-program \"base64\" '(\"-id\" \"-\")
:search t
:input (make-string-input-stream *fasl64*)
:output out))
(setf (symbol-function 'sb-impl::get-temporary-directory) saved)
(sb-ext:lock-package :sb-impl))
(in-package :cl-user)
(load faslize:*fasl-pathname*)
(sb-ext:quit)
"
echo "${TEMPLATE}"
if [ ${OMIT_SOURCE} -eq 0 ]; then
echo ";;;"
echo ";;; Original source"
echo ";;;"
echo ""
echo "#|"
cat "${LISP_PATHNAME}"
echo "|#"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment