oss-build-scripts/projects/llvm/ossbuild-llvm.bash
Kai Tetzlaff (kai+qnas) 99a79e2218 Refactor lib/ossbuild-common.bash and adapt projects to changes
* Use common prefixes for project specific build step functions:
  - ossbuild-prepare-<prjname>
  - ossbuild-build-<prjname>
  - ossbuild-install-<prjname>
* New project specific build step function: ossbuild-configure-ok-p-<prjname>
* New environment variable OSSBUILD_SKIP. Allows users to skip listed
  (comma separated) build steps.
* Remove `-generic` from common function names.
* Improve ossbuild-pushd/popd functions.
* Improve doc comments.
* Adapt projects to renamed functions
2024-05-18 01:48:22 +02:00

285 lines
9.4 KiB
Bash
Executable File

#!/usr/bin/env bash
LIB_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")/../../lib"
source "${LIB_DIR}/ossbuild-common.bash"
ossbuild-prepare-llvm() {
echo "[INF] ${FUNCNAME[0]} ..."
local version="${1}"
local repository="https://github.com/llvm/llvm-project"
local archive="llvm-project-${version}.src.tar.xz"
pushd "${HOME}/work/oss" &> /dev/null
[ -e "${archive}" ] || {
wget "${repository}/releases/download/llvmorg-${version}/${archive}"
}
local src_dir
src_dir="${HOME}/work/oss/$(basename "${archive}" .tar.xz)"
[ -d "${src_dir}" ] || tar xvf "${archive}"
popd &> /dev/null
pushd "${src_dir}" &> /dev/null
}
ossbuild-generate-llvm() {
echo "[INF] ${FUNCNAME[0]} ..."
local build_type="${1:-Release}"
local projects="${2:-}"
local prefix="${3:-}"
local source_dir='llvm'
[ -d "${source_dir}" ] || {
echo "[ERR] could not find source dir: '${source_dir}'"
return 1
}
local -a cmake_extra_args
local build_dir="build-${build_type,,}"
if [ -n "${projects}" ]; then
build_dir="${build_dir}.${projects//;/.}"
else
# get runtime target from GCC
local gcc_runtime_target
gcc_runtime_target="$(gcc -xc /dev/null -v -E 2>&1 | grep '^Target:' | cut -d' ' -f2)"
#projects='clang;clang-tools-extra;lld;lldb;compiler-rt;libunwind;libcxx;libcxxabi'
projects='clang;clang-tools-extra;compiler-rt;lld;lldb'
cmake_extra_args+=(
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind"
# must match triple of GCC used for first build step (here:
# /opt/lib/gcc/x86_64-openwrt-linux-gnu/8.4.0)
-DLLVM_RUNTIME_TARGETS="${gcc_runtime_target}"
# required )in case of a non-standard triple) in order to allow the
# final clang to find the GCC resource dir which contains files
# required by the linker (like crti.o, libgcc, libc_nonshared.a in
# e.g. /opt/lib/gcc/x86_64-openwrt-linux-gnu/8.4.0)
#
# Note: This also sets LLVM_DEFAULT_TARGET_TRIPLE.
-DLLVM_HOST_TRIPLE="${gcc_runtime_target}"
# Avoid error during cmake toolchain generation:
#
# ERROR: Compiler doesn't support generation of unwind tables if
# exception support is disabled. Building libunwind DSO with runtime
# dependency on C++ ABI library is not supported.
-DRUNTIMES_${gcc_runtime_target}_LIBUNWIND_ENABLE_SHARED="Off"
)
fi
local log="${build_dir/build-/cmake-}.log"
if [ -z "${prefix}" ]; then
if is-qnap-qts; then
prefix="$(readlink /opt)/local"
else
prefix='/usr/local'
fi
fi
if [ -d "${build_dir}" ]; then
if [ -v FORCE_REGENERATE ]; then
if [ "${FORCE_REGENERATE}" != "no-rm" ]; then
rm -rf "${build_dir}"
fi
else
echo "[INF] keep existing build dir: '${build_dir}'"
return 0
fi
fi
local -a cmd=(
cmake
-S "${source_dir}"
-B "${build_dir}"
-G Ninja
-DCMAKE_BUILD_TYPE="${build_type}"
-DCMAKE_INSTALL_PREFIX="${prefix}"
-DLLVM_ENABLE_PROJECTS="${projects}"
#-DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,\$ORIGIN/../lib -L${prefix}/lib"
-DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,${prefix}/lib -L${prefix}/lib -L/opt/lib"
"${cmake_extra_args[@]}"
)
if command -v ccache &> /dev/null; then
cmd+=(
-DLLVM_CCACHE_BUILD="ON"
-DLLVM_CCACHE_PARAMS="CCACHE_CPP2=yes CCACHE_HASHDIR=yes CCACHE_BASEDIR='${PWD}/${build_dir}'"
)
fi
if is-qnap-qts; then
# get gcc_install_prefix
local gcc_install_prefix
gcc_install_prefix="$(gcc -x c -E /dev/null -v 2>&1 | rg 'Configured with' | sed -e 's/.* --prefix=\([^ ]\+\).*/\1/')"
cmd+=(
# enable clang to locate the GCC toolchain if it is in a
# non-standard location (like ~/opt~ on QNAP Entware)
-DGCC_INSTALL_PREFIX="${gcc_install_prefix}"
# CMAKE_EXE_LINKER_FLAGS and LLVM_PARALLEL_LINK_JOBS flags reduce linker
# memory usage (without them, llvm build fails on qnas)
-DCMAKE_EXE_LINKER_FLAGS="-Wl,--reduce-memory-overheads -Wl,--hash-size=1021"
-DLLVM_PARALLEL_LINK_JOBS=1
# avoid cmake warning: 'runtime library [libz.so.1] in /lib may be
# hidden by files in ...'
-DZLIB_ROOT="${prefix}"
)
# From https://lists.llvm.org/pipermail/cfe-users/2016-November/001076.html:
#
# ... gcc's configure file comes with handy flags like:
# - --with-local-prefix= which allows to override the default system
# header include /usr/local/include
# - --with-native-system-header-dir= to override the default system
# header include /include
# - --enable-linker-build-id to enable build ids by default (in clang
# the equivalent is -DENABLE_LINKER_BUILD_ID)
# - --with-linker-hash-style=gnu to force the gnu hash style when
# emitting the symbol table.
#
# However, LLVM/clang doesn't seem to provide an equivalent for
# --with-local-prefix, --with-native-system-header-dir and
# --with-linker-hash-style. So instead, some sources need to be
# patched.
echo
local clang_toolchain_src
clang_toolchain_src='clang/lib/Driver/ToolChains/Linux.cpp'
[ -e "${clang_toolchain_src}.orig" ] || {
echo "[INF] patching ${clang_toolchain_src} ..."
sed -i.orig \
-e 's,/usr/,/opt/,g' "${clang_toolchain_src}"
}
echo "[INF] using patch:"
diff -u "${clang_toolchain_src}"{.orig,} || true
echo "[INF] end of patch (${clang_toolchain_src})"
echo
clang_toolchain_src='clang/lib/Driver/ToolChains/Gnu.cpp'
[ -e "${clang_toolchain_src}.orig" ] || {
echo "[INF] patching ${clang_toolchain_src} ..."
sed -i.orig \
-e 's,\(basePath = "/\)usr\(/lib/gcc/"\),\1opt\2,g' \
"${clang_toolchain_src}"
}
echo "[INF] using patch:"
diff -u "${clang_toolchain_src}"{.orig,} || true
echo "[INF] end of patch (${clang_toolchain_src})"
fi
echo "[INF] generating build system for: ${projects}" | tee "${log}"
echo "${cmd[@]}" | tee -a "${log}"
"${cmd[@]}" 2>&1 | tee -a "${log}"
local -i retval=${?}
echo
local logprfx="INF"
if [ ${retval} -ne 0 ] || grep -q "Configuring incomplete" "${log}" ; then
logprfx="ERR"
echo "[${logprfx}] failed to generate build system for: ${projects}"
[ ${retval} -ne 0 ] || retval=10
else
echo "[${logprfx}] successfully generated build system for: ${projects}"
fi
echo "[${logprfx}] build dir: '${build_dir}'"
echo "[${logprfx}] cmake log: '${log}'"
return ${retval}
}
# shellcheck disable=SC2120
ossbuild-build-llvm() {
echo "[INF] ${FUNCNAME[0]} ..."
local build_type="${1:-Release}"
local build_args="${2:-}"
local build_dir="${3:-build-${build_type,,}}"
local cmd=(
cmake --build "${build_dir}"
--
)
if [ -n "${build_args}" ]; then
read -a extra_args <<< "${build_args}"
cmd+=(
"${extra_args[@]}"
)
elif is-qnap-qts; then
cmd+=(
# compiling on QTS sometimes fails (probably due to memory
# limitations), so limit the parallel jobs to 2
-j2
# don't stop at failures
-k0
)
fi
# enable verbose logging when V is non-empty
[ -z "${V:-}" ] || cmd+=(-v)
echo "${cmd[@]}"
"${cmd[@]}"
}
ossbuild-install-llvm() {
echo "[INF] ${FUNCNAME[0]} ..."
local build_type="${1:-Release}"
local build_dir="${2:-build-${build_type,,}}"
local cmd=(
sudo cmake --build "${build_dir}"
--
install
)
echo "${cmd[@]}"
"${cmd[@]}"
}
ossbuild-generate-llvm-fallback() {
echo "[INF] ${FUNCNAME[0]} ..."
local build_type="${1:-Release}"
local build_dir="${2:-build-${build_type,,}}"
# Fallback 1: Build a smaller subset of LLVM projects
local llvm_projects=(
clang
clang-tools-extra
lld
)
local IFS=';'
ossbuild-generate-llvm "${build_type}" "${llvm_projects[*]}"
# Fallback 2: Generate build systems for individual projects
IFS=';' read -a LLVM_PROJECTS \
<<< $(grep 'set(LLVM_ALL_PROJECTS ' llvm/CMakeLists.txt | cut -d\" -f2)
local project
for project in "${llvm_projects[@]}"; do
ossbuild-generate-llvm "${build_type}" "${project}"
done
}
ossbuild-llvm() {
local version="${1:-15.0.5}"
local build_type="${2:-Release}" # or 'RelWithDebInfo', but beware of the huge binaries
ossbuild-prepare-llvm "${version}"
ossbuild-generate-llvm "${build_type}"
# Ideally, llcm-cmake-build should build the most LLVM projects. However, if
# it doesn't, it might make sense to build projects individually (see
# `ossbuild-generate-llvm-fallback` above).
ossbuild-build-llvm "${build_type}"
# Install the toolchain
ossbuild-install-llvm "${build_type}"
return $?
}
# stop here when sourced
return 0 2>/dev/null || true
set -euo pipefail
[ "${DEBUG:-0}" -le 0 ] || set -x
ossbuild-llvm "${@}"