Skip to content

Instantly share code, notes, and snippets.

@ralt
Last active August 29, 2015 14:16
Show Gist options
  • Save ralt/cf5bbacb126e81b65b72 to your computer and use it in GitHub Desktop.
Save ralt/cf5bbacb126e81b65b72 to your computer and use it in GitHub Desktop.
SBCL install easy - source: http://plaster.tymoon.eu/view/85
#!/bin/bash
# This script requires sbcl git repo at /home/florian/Applications/sbcl/sbcl
# git checkout at the tag you want, and run ./build-sbcl.sh
readonly SBCL_REPO="git://sbcl.git.sourceforge.net/gitroot/sbcl/sbcl.git"
readonly BASE_DIR="/tmp/sbcl-git-build"
readonly SOURCE_DIR="/home/florian/Applications/sbcl/sbcl"
readonly BUILD_DIR="$BASE_DIR/build"
readonly CROSS_COMPILE_HOST="sbcl --disable-debugger --no-userinit --no-sysinit"
########################################################################
## SCRIPT
readonly PROGNAME=$(basename $0)
readonly PROGDIR=$(readlink -m $(dirname $0))
readonly ARGS="$@"
readonly DEFAULT_ACTIONS=(build install install-sources);
readonly DEFAULT_ENABLED_FEATURES=":sb-thread :sb-safepoint :sb-thruption :sb-wtimer :sb-core-compression"
readonly DEFAULT_DISABLED_FEATURES=":largefile :sb-ldb"
readonly DEFAULT_DYNAMIC_SPACE_SIZE="1Gb"
readonly DEFAULT_INSTALL_TARGET="/usr/local"
usage() {
cat <<- EOF
usage: $PROGNAME options
Easily build and install SBCL from source.
Sources are downloaded to $SOURCE_DIR
fetching them from $SBCL_REPO
and building them in $BUILD_DIR
OPTIONS:
-a --actions Specify the actions to perform, should be a
space delimited string of the following choices:
download prepare build test build-docs install install-sources cleanup
Defaults to "${DEFAULT_ACTIONS[@]}"
if -a, -b, and -i are not specified.
-b --build Adds "download prepare build" to the actions.
-d --disable Disable certain SBCL features.
Defaults to "$DEFAULT_DISABLED_FEATURES"
-e --enable Enable certain SBCL features.
Defaults to "$DEFAULT_ENABLED_FEATURES"
-i --install Adds "install install-sources" to the actions.
-t --target Specify the directory to install SBCL to.
Defaults to "$DEFAULT_INSTALL_TARGET"
-h --help Display this help.
EOF
}
contains_element() {
local e
for e in "${@:2}"; do
[ "$e" = "$1" ] && return 0;
done
return 1
}
status() {
echo -e "\n\e[0;33m>> \e[0;32m" $@ "\e[0m"
sleep 1
}
eexit() {
echo -e "\n\e[0;33m>> \e[0;31mError: " $@ "\e[0m"
exit 1
}
try_run() {
echo "$1" | bash \
|| eexit "$2"
}
try_run_sudo() {
echo "$1" | sudo bash \
|| eexit "$2"
}
is_downloaded() {
return [ -d "$SOURCE_DIR" ]
}
is_prepared() {
return [ -d "$BUILD_DIR" ]
}
is_built() {
return [ -d "$BUILD_DIR/output" ]
}
check_downloaded() {
[ ! is_downloaded ] \
&& eexit "Sources are not available! Run `$PROGNAME -a download` first."
}
check_prepared() {
[ ! is_prepared ] \
&& eexit "Build directory is not available! Run `$PROGNAME -a prepare` first."
}
check_built() {
[ ! is_built ] \
&& eexit "SBCL has not been built yet! Run `$PROGNAME -a \"build\"` first."
}
download_source() {
status "Downloading source..."
mkdir -p "$SOURCE_DIR"
if [ -d "$SOURCE_DIR/.git" ]; then
cd "$SOURCE_DIR"
git pull \
|| eexit "Failed to download source."
else
git clone "$SBCL_REPO" "$SOURCE_DIR" \
|| eexit "Failed to download source."
fi
}
prepare_build() {
status "Preparing build..."
check_downloaded
[ -d "$BUILD_DIR" ] \
&& cleanup_build
git clone "$SOURCE_DIR" "$BUILD_DIR" \
|| eexit "Failed to prepare build."
cd "$BUILD_DIR"
cat >customize-target-features.lisp <<EOF
(lambda (features)
(flet ((enable (x) (pushnew x features))
(disable (x) (setf features (remove x features))))
(dolist (feature '($ENABLED_FEATURES))
(enable feature))
(dolist (feature '($DISABLED_FEATURES))
(disable feature)))
features)
EOF
}
build_sbcl() {
status "Building SBCL..."
check_prepared
cd "$BUILD_DIR"
export CFLAGS="${CFLAGS} -fno-omit-frame-pointer -D_GNU_SOURCE"
sh make.sh --dynamic-space-size=$DYNAMIC_SPACE_SIZE \
|| eexit "SBCL build failed."
}
test_sbcl() {
status "Testing SBCL..."
check_built
cd "$BUILD_DIR/tests"
sh ./run-tests.sh \
|| eexit "SBCL tests failed."
}
build_sbcl_docs() {
status "Building SBCL docs..."
check_built
cd "$BUILD_DIR/doc/manual"
make \
|| eexit "Failed to build SBCL docs."
}
install_sbcl() {
local command
status "Installing SBCL..."
check_built
cd "$BUILD_DIR"
unset SBCL_HOME
command="INSTALL_ROOT=\"$INSTALL_TARGET\" sh install.sh"
# Attempt to create directory always, suppressing errors
# This way the -w test will truly check for permissions.
[ ! -d "$INSTALL_TARGET" ] \
&& mkdir -p "$INSTALL_TARGET" &>/dev/null
if [ -w "$INSTALL_TARGET" ]; then
try_run "$command" "SBCL install failed."
else
status "Super User privileges required to install to $INSTALL_TARGET"
try_run_sudo "$command" "SBCL install failed."
fi
}
install_sources() {
local sources_dir="$INSTALL_TARGET/share/sbcl-source"
local copy_command="cp -R -t \"$sources_dir\" \"$BUILD_DIR/src\" \"$BUILD_DIR/contrib\""
local clean_command="find \"$sources_dir\" \
-name \"*.fasl\" -or \
-name \"*.o\" -or \
-name \"*.log\" -or \
-name \"*.so\" -or \
-name \"a.out\" -delete"
local core_command="mv \"$BUILD_DIR/sbcl-sources.core\" \"$INSTALL_TARGET/lib/sbcl/sbcl.core\""
status "Installing sources..."
check_built
cd "$BUILD_DIR"
cat >setup-sources.lisp <<EOF
(in-package #:cl-user)
(let* ((parent (parse-namestring "$sources_dir/")))
(setf (logical-pathname-translations "SYS")
\`(("SYS:SRC;**;*.*.*" ,(merge-pathnames "src/" parent))
("SYS:CONTRIB;**;*.*.*" ,(merge-pathnames "contrib/" parent)))))
(ignore-errors
(sb-ext:gc :full t)
(sb-ext:enable-debugger)
(sb-ext:save-lisp-and-die "$BUILD_DIR/sbcl-sources.core"))
EOF
status "Creating proper core..."
src/runtime/sbcl --core output/sbcl.core --no-userinit --no-sysinit --script "$BUILD_DIR/setup-sources.lisp"
status "Copying..."
[ ! -d "$sources_dir" ] \
&& mkdir -p "$sources_dir" &>/dev/null
if [ -w "$sources_dir" ]; then
try_run "$copy_command" "Source copying failed."
try_run "$clean_command" "Source cleaning failed."
try_run "$core_command" "Core copying failed."
else
status "Super User privileges required to install sources to $sources_dir"
try_run_sudo "mkdir -p \"$sources_dir\"" "Failed to create sources dir."
try_run_sudo "$copy_command" "Source copying failed."
try_run_sudo "$clean_command" "Source cleaning failed."
try_run_sudo "$core_command" "Core copying failed."
fi
}
cleanup_build() {
status "Cleaning up build..."
rm -rf "$BUILD_DIR"
}
perform_actions(){
local a=("${@}")
status "Performing actions: ${a[@]}"
contains_element download "${a[@]}" \
&& download_source
contains_element prepare "${a[@]}" \
&& prepare_build
contains_element build "${a[@]}" \
&& build_sbcl
contains_element test "${a[@]}" \
&& test_sbcl
contains_element build-docs "${a[@]}" \
&& build_sbcl_docs
contains_element install "${a[@]}" \
&& install_sbcl
contains_element install-sources "${a[@]}" \
&& install_sources
contains_element cleanup "${a[@]}" \
&& cleanup_build
status "All done."
}
cmdline() {
local arg=
for arg; do
local delim=""
case "$arg" in
--actions) args="${args}-a ";;
--build) args="${args}-b ";;
--disable) args="${args}-d ";;
--enable) args="${args}-e ";;
--help) args="${args}-h ";;
--install) args="${args}-i ";;
--target) args="${args}-t ";;
# Pass through anything else
*) [[ "${arg:0:1}" == "-" ]] || delim="\""
args="${args}${delim}${arg}${delim} ";;
esac
done
eval set -- $args
local current_actions=()
while getopts "a:be:d:hit:" OPTION; do
case $OPTION in
a)
current_actions=($OPTARG)
;;
b)
current_actions+=(download prepare build)
;;
d)
readonly DISABLED_FEATURES="$OPTARG"
;;
e)
readonly ENABLED_FEATURES="$OPTARG"
;;
h)
usage
exit 0
;;
i)
current_actions+=(install install-sources)
;;
t)
readonly INSTALL_TARGET="$OPTARG"
;;
*)
eexit "Unknown option given"
;;
esac
done
## Defaulting & Setting
[ ${#current_actions[@]} -eq 0 ] \
&& readonly ACTIONS=("${DEFAULT_ACTIONS[@]}") \
|| readonly ACTIONS=("${current_actions[@]}")
[ -z ${ENABLED_FEATURES+x} ] \
&& readonly ENABLED_FEATURES="$DEFAULT_ENABLED_FEATURES"
[ -z ${DISABLED_FEATURES+x} ] \
&& readonly DISABLED_FEATURES="$DEFAULT_DISABLED_FEATURES"
[ -z ${INSTALL_TARGET+x} ] \
&& readonly INSTALL_TARGET="$DEFAULT_INSTALL_TARGET"
[ -z ${DYNAMIC_SPACE_SIZE+x} ] \
&& readonly DYNAMIC_SPACE_SIZE="$DEFAULT_DYNAMIC_SPACE_SIZE"
perform_actions "${ACTIONS[@]}"
}
main() {
cmdline $ARGS
exit 0
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment