From 92b82c4a3e4883f364d1a37734a891f2ea9db6ca Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sun, 30 Sep 2018 19:39:40 +0800 Subject: [PATCH] Allow to build from source, fixes #2 --- .travis.sh | 3 ++ .travis.yml | 23 +++++++++ README.md | 4 +- ghcup | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 168 insertions(+), 3 deletions(-) diff --git a/.travis.sh b/.travis.sh index 25b359c..5c85482 100755 --- a/.travis.sh +++ b/.travis.sh @@ -18,6 +18,9 @@ set -e # set GHC ./ghcup -v set 8.2.2 +# compile GHC from source +./ghcup -v compile 8.4.3 ghc-8.2.2 + # install cabal-install ./ghcup -v install-cabal diff --git a/.travis.yml b/.travis.yml index d835145..c0d40e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,29 @@ language: bash # Use container-based infrastructure for quicker build start-up sudo: false +addons: + apt: + # for building GHC + sources: + - llvm-toolchain-trusty-5.0 + packages: + - autoconf + - automake + - build-dep + - g++ + - gcc + - git + - libgmp-dev + - libllvm5.0 + - libtinfo-dev + - libtool + - llvm-5.0 + - llvm-5.0-dev + - make + - ncurses-dev + - python3 + - xz-utils + # TODO: also run checkbashisms.pl (currently two instances of non-compliance) script: - ./.travis.sh diff --git a/README.md b/README.md index cadab2e..7eeadbe 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ This uses precompiled GHC binaries that have been compiled on fedora/debian by [upstream GHC](https://www.haskell.org/ghc/download_ghc_8_6_1.html#binaries). +Alternatively, you can also tell it to compile from source (note that this might +fail due to missing requirements). In addition this script can also install `cabal-install`. @@ -57,7 +59,7 @@ See `ghcup --help`. ## Feature considerations -- [ ] Allow to compile from source ([#2](https://github.com/hasufell/ghcup/issues/2)) +- [x] Allow to compile from source ([#2](https://github.com/hasufell/ghcup/issues/2)) - [x] Allow to install cabal-install as well ([#3](https://github.com/hasufell/ghcup/issues/3)) ## Known problems diff --git a/ghcup b/ghcup index cdaf5be..5461469 100755 --- a/ghcup +++ b/ghcup @@ -27,6 +27,8 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. +# TODO: +# - make removal more robust @@ -96,6 +98,12 @@ GHC_DOWNLOAD_BASEURL="https://downloads.haskell.org/~ghc" # which a pre-built binary exists. KNOWN_GOOD_CABAL="2.2.0.0" +# @VARIABLE: JOBS +# @DESCRIPTION: +# How many jobs to use for compiling GHC. +JOBS="1" + + #################### #--[ Print Help ]--# @@ -148,6 +156,7 @@ USAGE: FLAGS: -h, --help Prints help information -f, --force Overwrite already existing installation + -j, --jobs How many jobs for installation ARGS: E.g. \"8.4.3\" or \"8.6.1\" @@ -269,6 +278,37 @@ DISCUSSION: exit 1 } +# @FUNCTION: compile_usage +# @DESCRIPTION: +# Print the help message for 'ghcup compile' to STDERR +# and exit the script with status code 1. +compile_usage() { + (>&2 echo "ghcup-compile +Compile and install the specified GHC version + +USAGE: + ${SCRIPT} compile [FLAGS] + +FLAGS: + -h, --help Prints help information + -f, --force Overwrite already existing installation + -j, --jobs How many jobs for compilation + +ARGS: + E.g. \"8.4.3\" or \"8.6.1\" + E.g. \"ghc-8.2.2\" or a full path + +DISCUSSION: + Compiles and installs the specified GHC version into + a self-contained \"~/.ghcup/ghc/\" directory + and symlinks the ghc binaries to \"~/.ghcup/bin/-\". + +EXAMPLE: + ghcup -v compile -f -j 4 8.4.2 ghc-8.2.2 +") + exit 1 +} + @@ -566,7 +606,7 @@ install_ghc() { debug_message "Installing GHC into ${inst_location}" edo ./configure --prefix="${inst_location}" - edo make install + edo make -j${JOBS} install # clean up edo cd .. @@ -780,7 +820,7 @@ install_cabal() { ( edo cd "$(mktemp -d)" - edo download "https://www.haskell.org/cabal/release/cabal-install-${mycabalver}/cabal-install-${mycabalver}-${myarch}-unknown-linux.tar.gz" + edo download "https://downloads.haskell.org/~cabal/cabal-install-${mycabalver}/cabal-install-${mycabalver}-${myarch}-unknown-linux.tar.gz" edo tar -xzf "cabal-install-${mycabalver}-${myarch}-unknown-linux.tar.gz" edo mv cabal "${inst_location}"/cabal ) || die "Failed to install cabal-install" @@ -792,6 +832,83 @@ install_cabal() { unset mycabalver myarch inst_location } +# @FUNCTION: compile_ghc +# @USAGE: +# @DESCRIPTION: +# Compile and installs the given GHC version with the +# specified GHC bootstrap version. +compile_ghc() { + { [ -z "$1" ] || [ -z "$2" ] ;} && die "Internal error: not enough arguments given to compile_ghc" + + myghcver=$1 + bootstrap_ghc=$2 + inst_location=$(get_ghc_location "$1") + download_url="https://downloads.haskell.org/~ghc/${myghcver}/ghc-${myghcver}-src.tar.xz" + download_tarball_name=$(basename "${download_url}") + + if ghc_already_installed "${myghcver}" ; then + if ${FORCE} ; then + echo "GHC already installed in ${inst_location}, overwriting!" + else + die "GHC already installed in ${inst_location}, use --force to overwrite" + fi + fi + + status_message "Compiling GHC for version ${myghcver} from source" + tmp_dir=$(mktemp -d) + [ -z "${tmp_dir}" ] && die "Failed to create temporary directory" + ( + edo cd "${tmp_dir}" + + edo download "${download_url}" + + edo tar -xf ghc-*-src.tar.xz + edo cd "ghc-${myghcver}" + + cat <<-EOF > mk/build.mk || die + BuildFlavour = quick + V=0 + BUILD_MAN = NO + BUILD_SPHINX_HTML = NO + BUILD_SPHINX_PDF = NO + HADDOCK_DOCS = YES + GhcWithLlvmCodeGen = YES + EOF + + edo ./boot + edo ./configure --prefix="${inst_location}" --with-ghc="${bootstrap_ghc}" + edo make -j${JOBS} + edo make install + + # clean up + edo cd .. + [ -e "${tmp_dir}/${download_tarball_name}" ] && rm "${tmp_dir}/${download_tarball_name}" + [ -e "${tmp_dir}/ghc-${myghcver}" ] && rm -r "${tmp_dir}/ghc-${myghcver}" + ) || { + [ -e "${tmp_dir}/${download_tarball_name}" ] && rm "${tmp_dir}/${download_tarball_name}" + [ -e "${tmp_dir}/ghc-${myghcver}" ] && rm -r "${tmp_dir}/ghc-${myghcver}" + die "Failed to install, consider updating this script via: + ${SCRIPT} self-update +Also check https://ghc.haskell.org/trac/ghc/wiki/Building/Preparation/Linux for build requirements and follow the instructions." + } + + [ -e "${BIN_LOCATION}" ] || mkdir "${BIN_LOCATION}" + + for f in "${inst_location}"/bin/*-"${myghcver}" ; do + [ -e "${f}" ] || die "Something went wrong, ${f} does not exist!" + fn=$(basename "${f}") + # shellcheck disable=SC2046 + edo ln $(optionv "-v") -sf ../ghc/"${myghcver}/bin/${fn}" "${BIN_LOCATION}/${fn}" + unset fn + done + # shellcheck disable=SC2046 + edo ln $(optionv "-v") -sf ../ghc/"${myghcver}"/bin/runhaskell "${BIN_LOCATION}/runhaskell-${myghcver}" + + status_message "Done installing, run \"ghci-${myghcver}\" or set up your current GHC via: ${SCRIPT} set ${myghcver}" + + unset myghcver bootstrap_ghc inst_location f download_url download_tarball_name +} + @@ -835,6 +952,8 @@ while [ $# -gt 0 ] ; do -h|--help) install_usage;; -f|--force) FORCE=true shift 1;; + -j|--jobs) JOBS=$1 + shift 2;; *) GHC_VER=$1 break;; esac @@ -915,6 +1034,24 @@ while [ $# -gt 0 ] ; do install_cabal "${KNOWN_GOOD_CABAL}" fi break;; + compile) + shift 1 + while [ $# -gt 0 ] ; do + case $1 in + -h|--help) compile_usage;; + -f|--force) FORCE=true + shift 1;; + -j|--jobs) JOBS=$2 + shift 2;; + *) GHC_VER=$1 + BOOTSTRAP_GHC=$2 + break;; + esac + done + [ "${GHC_VER}" ] || compile_usage + [ "${BOOTSTRAP_GHC}" ] || compile_usage + compile_ghc "${GHC_VER}" "${BOOTSTRAP_GHC}" + break;; *) usage;; esac break;;