Last active
August 29, 2015 14:16
-
-
Save ralt/cf5bbacb126e81b65b72 to your computer and use it in GitHub Desktop.
SBCL install easy - source: http://plaster.tymoon.eu/view/85
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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