* 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
285 lines
9.4 KiB
Bash
Executable File
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 "${@}"
|