Skip to content

Instantly share code, notes, and snippets.

@hamsham
Last active January 6, 2022 07:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hamsham/47702917cfe35a1ee70051143675c8bb to your computer and use it in GitHub Desktop.
Save hamsham/47702917cfe35a1ee70051143675c8bb to your computer and use it in GitHub Desktop.
Build script to check-out and compile LLVM/Clang
#!/usr/bin/env bash
set -euo pipefail
# This script follows the instructions for building Clang, from the LLVM
# documentation here: https://llvm.org/docs/GettingStarted.html#requirements
CLANG_RELEASE_LATEST=13.0.0
CLANG_GIT_REPO=https://github.com/llvm/llvm-project.git
function verify_prerequisites()
{
# Required executables listed from step 2 of the online manual
echo "Checking for prerequisite build tools..."
function _check_exe()
{
local exeName=$(which "$1" 2> /dev/null)
if [[ -z "$exeName" ]]; then
echo -e "Error: Unable to find $1."
exit 1
fi
echo -e "\tFound $1: $exeName"
}
_check_exe make
_check_exe python3
_check_exe cmake
_check_exe bzip2
_check_exe bunzip2
_check_exe gzip
_check_exe gunzip
_check_exe tar
_check_exe zip
_check_exe unzip
# Required libraries
echo "Checking for prerequisite libraries..."
function _check_lib()
{
local libName=$(ldconfig -p | grep "lib$1\.so[[:space:]]")
if [[ -z "$libName" ]]; then
echo -e "Error: Unable to find lib$1."
exit 1
fi
echo -e "\tFound $1: $(echo "$libName" | awk '{print $4}')"
}
_check_lib z
echo ""
}
function verify_release_num()
{
# Git branches use only a single digit in their name. Tagged releases use
# the MAJOR.MINOR.PATCH naming convention. Here, we validate only the
# MAJOR.MINOR.PATCH to avoid checking-out non-release branches. We'll need
# to rely on Git to error on invalid tag names later on.
local versionNum=$(echo "$1" | grep -E '^([1-9]+)\.([0-9]+)\.([0-9]+)$')
if [[ -z "$versionNum" ]]; then
echo "Error: Invalid version string for LLVM tagged branch. The version number must use the 'MAJOR.MINOR.PATCH' naming scheme."
exit 1
fi
echo "LLVM version to clone: $versionNum"
echo ""
}
function get_source_dir_name()
{
local llvmVersion="$1"
realpath "$workingDir/clang-$llvmVersion"-src
}
function get_build_dir_name()
{
local llvmVersion="$1"
realpath "$workingDir/clang-$llvmVersion"
}
function clone_llvm()
{
local llvmVersion="$1"
local llvmBranch="llvmorg-$llvmVersion"
local workingDir="$2"
local sourceDir=$(get_source_dir_name "$llvmVersion")
mkdir -p "$workingDir"
echo "Cloning LLVM $llvmVersion"
if [[ -d "$sourceDir" ]]; then
pushd "$sourceDir"
set +e
git status 2>&1 > /dev/null
local exit_status=$?
set -e
popd
if [[ exit_status -ne 0 ]]; then
echo "A non-source-controlled directory is located at $sourceDir. Please remove this directory and try again."
exit 1
fi
else
git clone --depth 1 --branch "$llvmBranch" "$CLANG_GIT_REPO" "$sourceDir"
fi
echo "Updating local LLVM branch for $llvmVersion"
pushd "$sourceDir"
git checkout -- .
git pull --rebase
popd
echo ""
}
function configure_llvm()
{
local llvmVersion="$1"
local sourceDir=$(get_source_dir_name "$llvmVersion")
local buildDir=$(get_build_dir_name "$llvmVersion")
local workingDir="$2"
local installPrefix="$3"
# Search for all top-level projects to build
local subProjects=$(find "$sourceDir" -mindepth 1 -maxdepth 2 -type f -name CMakeLists.txt -exec dirname {} \; | grep -v test | sed -E 's/.+\///' | tr '\n' ';')
mkdir -p "$buildDir"
echo "Building sub-projects: $subProjects"
set +e
cmake \
-S "$sourceDir/llvm" \
-B "$buildDir" \
-DCMAKE_INSTALL_PREFIX="$installPrefix" \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_TARGETS_TO_BUILD="X86;AArch64;ARM;Mips;WebAssembly;NVPTX;AMDGPU;PowerPC;SystemZ" \
-DLLVM_ENABLE_DOXYGEN=FALSE \
-DLLVM_ENABLE_SPHINX=FALSE \
-DLLVM_OPTIMIZED_TABLEGEN=TRUE \
-DLLVM_ENABLE_PROJECTS="$subProjects"
local status=$?
set -e
if [[ $status -ne 0 ]]; then
echo "An error occurred while compiling LLVM."
exit 1
fi
echo ""
}
function make_llvm()
{
local llvmVersion="$1"
local buildDir=$(get_build_dir_name "$llvmVersion")
set +e
cmake --build "$buildDir" --config Release
local status=$?
set -e
if [[ $status -ne 0 ]]; then
echo "An error occurred while compiling LLVM."
exit 1
fi
echo ""
}
function print_usage()
{
echo "USAGE:"
echo -e "\t-h,--help Prints this message then exits."
echo -e "\t-r,--release Sets the release branch of Clang to clone from git."
echo -e "\t-d,--directory Path of the top-level directory where Clang will be checked-out and built (defaults to the current working directory)."
echo -e "\t-p,--prefix Specifies the installation prefix (note: 'make install' must be run manually outside of this script)."
echo ""
}
function main()
{
local releaseVer="$CLANG_RELEASE_LATEST"
local workingDir=$(pwd)
local prefix="/opt"
set +u
while [ -n "$1" ]; do
case "$1" in
-h | --help)
print_usage
exit
;;
-r | --release)
shift
releaseVer="$1"
;;
-d | --directory)
shift
workingDir="$1"
;;
-p | --prefix)
shift
prefix="$1"
;;
*)
echo "Unknown parameter '$1'"
print_usage
exit 1
;;
esac
shift
done
set -u
verify_prerequisites
verify_release_num "$releaseVer"
clone_llvm "$releaseVer" "$workingDir"
configure_llvm "$releaseVer" "$workingDir" "$prefix"
make_llvm "$releaseVer"
}
main $@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment