diff --git a/Manual.md b/Manual.md index 6481bb4ee5..4f954b840b 100644 --- a/Manual.md +++ b/Manual.md @@ -961,6 +961,16 @@ via `make_install_target`. via `configure_args`, the meson command can be overridden by `meson_cmd` and the location of the out of source build by `meson_builddir` +- `void-cross` For cross-toolchain packages used to build Void systems. You will need to +specify `cross_triplet` (corresponds to the target triplet specified in the cross profile +for the target arch), `cross_linux_arch` (the architecture name in the Linux kernel source) +and when building Go support for musl targets, also `cross_libucontext_arch` (see `libucontext` +for available ones). Optionally, `cross_gcc_skip_go` can be specified. Individual subproject +configure arguments can be specified via `cross_*_configure_args` where `*` is `binutils`, +`gcc_bootstrap` (early gcc), `gcc` (final gcc), `glibc` (or `musl`), `configure_args` is +additionally passed to both early and final `gcc`. You can also specify custom `CFLAGS` +and `LDFLAGS` for the libc as `cross_(glibc|musl)_(cflags|ldflags)`. + For packages that use the Python module build method (`setup.py` or [PEP 517](https://www.python.org/dev/peps/pep-0517/)), you can choose one of the following: diff --git a/common/build-style/void-cross.sh b/common/build-style/void-cross.sh new file mode 100644 index 0000000000..0e5c233635 --- /dev/null +++ b/common/build-style/void-cross.sh @@ -0,0 +1,591 @@ +# +# This helper is for void system crosstoolchain templates. +# +# Mandatory variables: +# +# - cross_triplet - the target triplet (e.g. aarch64-linux-gnu) +# - cross_linux_arch - the source ARCH of the kernel (e.g. arm64) +# - cross_libucontext_arch - only on musl without cross_gcc_skip_go +# +# Optional variables: +# +# - cross_gcc_skip_go - do not build gccgo support +# - cross_binutils_configure_args +# - cross_gcc_bootstrap_configure_args +# - cross_gcc_configure_args +# - cross_glibc_cflags +# - cross_glibc_ldflags +# - cross_glibc_configure_args +# - cross_musl_cflags +# - cross_musl_ldflags +# - cross_musl_configure_args +# +# configure_args is passed to both bootstrap gcc and final gcc +# if you need to pass some to one and not the other, use the +# respective cross_ variables for final gcc and bootstrap gcc +# + +_void_cross_apply_patch() { + local args="$1" pname="$(basename $2)" + if [ ! -f ".${pname}_done" ]; then + patch -N $args -i $2 + touch .${pname}_done + fi +} + +_void_cross_build_binutils() { + [ -f ${wrksrc}/.binutils_done ] && return 0 + + local ver=$1 + + msg_normal "Building binutils for ${cross_triplet}\n" + + mkdir -p ${wrksrc}/binutils_build + cd ${wrksrc}/binutils_build + + ../binutils-${ver}/configure \ + --prefix=/usr \ + --sbindir=/usr/bin \ + --libdir=/usr/lib \ + --libexecdir=/usr/lib \ + --target=${cross_triplet} \ + --with-sysroot=/usr/${cross_triplet} \ + --disable-nls \ + --disable-shared \ + --disable-multilib \ + --disable-werror \ + --disable-gold \ + --with-system-zlib \ + --enable-deterministic-archives \ + --enable-default-hash-style=gnu \ + ${cross_binutils_configure_args} + + make configure-host + make ${makejobs} + + make install DESTDIR=${wrksrc}/build_root + + touch ${wrksrc}/.binutils_done +} + +_void_cross_build_bootstrap_gcc() { + [ -f ${wrksrc}/.gcc_bootstrap_done ] && return 0 + + local ver=$1 + + msg_normal "Patching GCC for ${cross_triplet}\n" + + cd ${wrksrc}/gcc-${ver} + for f in ${XBPS_SRCPKGDIR}/gcc/patches/*.patch; do + _void_cross_apply_patch -p0 "$f" + done + if [ -f ${wrksrc}/.musl_version ]; then + for f in ${XBPS_SRCPKGDIR}/gcc/files/*-musl.patch; do + _void_cross_apply_patch -p0 "$f" + done + fi + cd .. + + msg_normal "Building bootstrap GCC for ${cross_triplet}\n" + + mkdir -p gcc_bootstrap + cd gcc_bootstrap + + local extra_args + if [ -f ${wrksrc}/.musl_version ]; then + extra_args+=" --with-newlib" + extra_args+=" --disable-symvers" + extra_args+=" libat_cv_have_ifunc=no" + else + extra_args+=" --without-headers" + fi + + ../gcc-${ver}/configure \ + --prefix=/usr \ + --sbindir=/usr/bin \ + --libdir=/usr/lib \ + --libexecdir=/usr/lib \ + --target=${cross_triplet} \ + --disable-nls \ + --disable-multilib \ + --disable-shared \ + --disable-libquadmath \ + --disable-decimal-float \ + --disable-libgomp \ + --disable-libmpx \ + --disable-libmudflap \ + --disable-libssp \ + --disable-libitm \ + --disable-libatomic \ + --disable-threads \ + --disable-sjlj-exceptions \ + --enable-languages=c \ + --with-gnu-ld \ + --with-gnu-as \ + ${extra_args} \ + ${configure_args} \ + ${cross_gcc_bootstrap_configure_args} + + make ${makejobs} + make install DESTDIR=${wrksrc}/build_root + + local ptrs=$(${cross_triplet}-gcc -dM -E - < /dev/null | \ + grep __SIZEOF_POINTER__) + local ws=${ptrs##* } + + case ${ws} in + 8) echo 64 > ${wrksrc}/.gcc_wordsize ;; + 4) echo 32 > ${wrksrc}/.gcc_wordsize ;; + *) msg_error "Unknown word size: ${ws}\n" ;; + esac + + touch ${wrksrc}/.gcc_bootstrap_done +} + +_void_cross_build_kernel_headers() { + [ -f ${wrksrc}/.linux_headers_done ] && return 0 + + local ver=$1 + + msg_normal "Patching Linux headers for ${cross_triplet}\n" + + cd ${wrksrc}/linux-${ver} + for f in ${XBPS_SRCPKGDIR}/kernel-libc-headers/patches/*.patch; do + _void_cross_apply_patch -p0 $f + done + cd .. + + msg_normal "Building Linux headers for ${cross_triplet}\n" + + cd linux-${ver} + + make ARCH=$cross_linux_arch headers_check + make ARCH=$cross_linux_arch \ + INSTALL_HDR_PATH=${wrksrc}/build_root/usr/${cross_triplet}/usr \ + headers_install + + touch ${wrksrc}/.linux_headers_done +} + +_void_cross_build_glibc_headers() { + [ -f ${wrksrc}/.glibc_headers_done ] && return 0 + + local ver=$1 + local tgt=$cross_triplet + + msg_normal "Patching glibc for ${cross_triplet}\n" + + cd ${wrksrc}/glibc-${ver} + if [ -d "${XBPS_SRCPKGDIR}/glibc/patches" ]; then + for f in ${XBPS_SRCPKGDIR}/glibc/patches/*.patch; do + _void_cross_apply_patch -p1 "$f" + done + fi + cd .. + + msg_normal "Building glibc headers for ${cross_triplet}\n" + + mkdir -p glibc_headers + cd glibc_headers + + echo "libc_cv_forced_unwind=yes" > config.cache + echo "libc_cv_c_cleanup=yes" >> config.cache + + # we don't need any custom args here, it's just headers + CC="${tgt}-gcc" CXX="${tgt}-g++" CPP="${tgt}-cpp" LD="${tgt}-ld" \ + AS="${tgt}-as" NM="${tgt}-nm" CFLAGS="-pipe" CXXFLAGS="" CPPFLAGS="" \ + LDFLAGS="" \ + ../glibc-${ver}/configure \ + --prefix=/usr \ + --host=${tgt} \ + --with-headers=${wrksrc}/build_root/usr/${tgt}/usr/include \ + --config-cache \ + --enable-obsolete-rpc \ + --enable-obsolete-nsl \ + --enable-kernel=2.6.27 \ + ${cross_glibc_configure_args} + + make -k install-headers cross_compiling=yes \ + install_root=${wrksrc}/build_root/usr/${tgt} + + touch ${wrksrc}/.glibc_headers_done +} + +_void_cross_build_glibc() { + [ -f ${wrksrc}/.glibc_build_done ] && return 0 + + local ver=$1 + local tgt=$cross_triplet + + msg_normal "Building glibc for ${tgt}\n" + + mkdir -p ${wrksrc}/glibc_build + cd ${wrksrc}/glibc_build + + local ws=$(cat ${wrksrc}/.gcc_wordsize) + + echo "slibdir=/usr/lib${ws}" > configparms + + echo "libc_cv_forced_unwind=yes" > config.cache + echo "libc_cv_c_cleanup=yes" >> config.cache + + CC="${tgt}-gcc" CXX="${tgt}-g++" CPP="${tgt}-cpp" LD="${tgt}-ld" \ + AR="${tgt}-ar" AS="${tgt}-as" NM="${tgt}-nm" \ + CFLAGS="-pipe ${cross_glibc_cflags}" \ + CXXFLAGS="-pipe ${cross_glibc_cflags}" \ + CPPFLAGS="${cross_glibc_cflags}" \ + LDFLAGS="${cross_glibc_ldflags}" \ + ../glibc-${ver}/configure \ + --prefix=/usr \ + --libdir=/usr/lib${ws} \ + --libexecdir=/usr/libexec \ + --host=${tgt} \ + --with-headers=${wrksrc}/build_root/usr/${tgt}/usr/include \ + --config-cache \ + --enable-obsolete-rpc \ + --enable-obsolete-nsl \ + --disable-profile \ + --disable-werror \ + --enable-kernel=2.6.27 \ + ${cross_glibc_configure_args} + + make ${makejobs} + make install_root=${wrksrc}/build_root/usr/${tgt} install + + touch ${wrksrc}/.glibc_build_done +} + +_void_cross_build_musl() { + [ -f ${wrksrc}/.musl_build_done ] && return 0 + + local ver=$1 + local tgt=$cross_triplet + + msg_normal "Patching musl for ${tgt}\n" + + cd ${wrksrc}/musl-${ver} + if [ -d "${XBPS_SRCPKGDIR}/musl/patches" ]; then + for f in ${XBPS_SRCPKGDIR}/musl/patches/*.patch; do + _void_cross_apply_patch -p0 "$f" + done + fi + cd .. + + msg_normal "Building musl for ${tgt}\n" + + mkdir -p musl_build + cd musl_build + + CC="${tgt}-gcc" CXX="${tgt}-g++" CPP="${tgt}-cpp" LD="${tgt}-ld" \ + AR="${tgt}-ar" AS="${tgt}-as" NM="${tgt}-nm" \ + CFLAGS="-pipe -fPIC ${cross_musl_cflags}" \ + CPPFLAGS="${cross_musl_cflags}" LDFLAGS="${cross_musl_ldflags}" \ + ../musl-${ver}/configure \ + --prefix=/usr \ + --host=${tgt} \ + ${cross_musl_configure_args} + + make ${makejobs} + make DESTDIR=${wrksrc}/build_root/usr/${tgt} install + + touch ${wrksrc}/.musl_build_done +} + +_void_cross_build_libucontext() { + [ -n "$cross_gcc_skip_go" ] && return 0 + [ -f ${wrksrc}/.libucontext_build_done ] && return 0 + + local ver=$1 + + msg_normal "Building libucontext for ${cross_triplet}\n" + + cd ${wrksrc}/libucontext-${ver} + # a terrible hack but seems to work for now + CC="${cross_triplet}-gcc" AS="${cross_triplet}-as" AR="${cross_triplet}-ar" \ + CPPFLAGS="-pipe ${cross_musl_cflags} -g0 -Os -nostdinc -isystem ${wrksrc}/build_root/usr/${cross_triplet}/usr/include" \ + make ARCH=${cross_libucontext_arch} libucontext.a + + cp libucontext.a ${wrksrc}/build_root/usr/${cross_triplet}/usr/lib + + touch ${wrksrc}/.libucontext_build_done +} + +_void_cross_build_gcc() { + [ -f ${wrksrc}/.gcc_build_done ] && return 0 + + local ver=$1 + + msg_normal "Building gcc for ${cross_triplet}\n" + + mkdir -p ${wrksrc}/gcc_build + cd ${wrksrc}/gcc_build + + local langs="c,c++,fortran,objc,obj-c++,ada,lto" + if [ -z "$cross_gcc_skip_go" ]; then + langs+=",go" + fi + + local extra_args + if [ -f ${wrksrc}/.musl_version ]; then + extra_args+=" --enable-libssp" + # otherwise glibc hosts get confused and use the gnu impl + extra_args+=" --enable-clocale=generic" + extra_args+=" --disable-symvers" + extra_args+=" --disable-gnu-unique-object" + extra_args+=" libat_cv_have_ifunc=no" + else + extra_args+=" --disable-libssp" + extra_args+=" --enable-gnu-unique-object" + fi + + # note on --disable-libquadmath: + # on some platforms the library is actually necessary for the + # fortran frontend to build, but still disable it because it + # should not be in the resulting packages; it conflicts with + # the libquadmath you can install into the cross root + # + # platforms where this is a problem should explicitly force + # libquadmath to be on via cross_gcc_configure_args, the + # do_install in this build-style automatically removes it + # + ../gcc-${ver}/configure \ + --prefix=/usr \ + --sbindir=/usr/bin \ + --libdir=/usr/lib \ + --libexecdir=/usr/lib \ + --target=${cross_triplet} \ + --with-sysroot=/usr/${cross_triplet} \ + --with-build-sysroot=${wrksrc}/build_root/usr/${cross_triplet} \ + --enable-languages=${langs} \ + --disable-nls \ + --disable-multilib \ + --disable-sjlj-exceptions \ + --disable-libquadmath \ + --disable-libmudflap \ + --disable-libitm \ + --disable-libvtv \ + --disable-libsanitizer \ + --disable-libstdcxx-pch \ + --enable-shared \ + --enable-threads=posix \ + --enable-__cxa_atexit \ + --enable-linker-build-id \ + --enable-libada \ + --enable-lto \ + --enable-default-pie \ + --enable-default-ssp \ + --with-gnu-ld \ + --with-gnu-as \ + --with-linker-hash-style=gnu \ + ${extra_args} \ + ${configure_args} \ + ${cross_gcc_configure_args} + + make ${makejobs} + + touch ${wrksrc}/.gcc_build_done +} + +_void_cross_check_var() { + local var="cross_${1}" + if [ -z "${!var}" ]; then + msg_error "cross_${1} not defined in template" + fi +} + +_void_cross_test_ver() { + local proj=$1 + local noerr=$2 + local ver cver + for p in ${proj}-*; do + cver=${p#${proj}-} + if [ -z "$noerr" -a -n "$ver" ]; then + msg_error "multiple versions of ${proj} found: ${ver}, ${cver}" + fi + ver=${cver} + done + if [ -d "${proj}-${ver}" ]; then + echo ${ver} > ${wrksrc}/.${proj}_version + return + fi + if [ -z "$noerr" ]; then + msg_error "project ${proj} not available for build\n" + fi +} + +do_build() { + # Verify toolchain versions + cd ${wrksrc} + + local binutils_ver linux_ver gcc_ver libc_ver libucontext_ver + + _void_cross_test_ver binutils + _void_cross_test_ver linux + _void_cross_test_ver gcc + + binutils_ver=$(cat .binutils_version) + linux_ver=$(cat .linux_version) + gcc_ver=$(cat .gcc_version) + + _void_cross_test_ver musl noerr + if [ ! -f .musl_version ]; then + _void_cross_test_ver glibc + libc_ver=$(cat .glibc_version) + else + libc_ver=$(cat .musl_version) + if [ -z "$cross_gcc_skip_go" ]; then + _void_cross_test_ver libucontext + _void_cross_check_var libucontext_arch + libucontext_ver=$(cat .libucontext_version) + fi + fi + + # Verify triplet + _void_cross_check_var triplet + _void_cross_check_var linux_arch + + local sysroot="/usr/${cross_triplet}" + + # Prepare environment + cd ${wrksrc} + + # Core directories for the build root + mkdir -p build_root/usr/{bin,lib,include,share} + mkdir -p build_root/usr/${cross_triplet}/usr/{bin,lib,include,share} + + # Host root uses host wordsize + ln -sf usr/lib build_root/lib + ln -sf usr/lib build_root/lib${XBPS_TARGET_WORDSIZE} + ln -sf lib build_root/usr/lib${XBPS_TARGET_WORDSIZE} + + # Prepare target sysroot + ln -sf usr/lib build_root/${sysroot}/lib + ln -sf lib build_root/${sysroot}/usr/libexec + + _void_cross_build_binutils ${binutils_ver} + + # Prepare environment so we can use temporary prefix + local oldpath="$PATH" + local oldldlib="$LD_LIBRARY_PATH" + + export PATH="${wrksrc}/build_root/usr/bin:$PATH" + export LD_LIBRARY_PATH="${wrksrc}/build_root/usr/lib:$PATH" + + _void_cross_build_bootstrap_gcc ${gcc_ver} + _void_cross_build_kernel_headers ${linux_ver} + + local ws=$(cat ${wrksrc}/.gcc_wordsize) + + # Now that we know the target wordsize, prepare symlinks + ln -sf usr/lib ${wrksrc}/build_root/${sysroot}/lib${ws} + ln -sf lib ${wrksrc}/build_root/${sysroot}/usr/lib${ws} + + if [ -f ${wrksrc}/.musl_version ]; then + _void_cross_build_musl ${libc_ver} + _void_cross_build_libucontext ${libucontext_ver} + else + _void_cross_build_glibc_headers ${libc_ver} + _void_cross_build_glibc ${libc_ver} + fi + + _void_cross_build_gcc ${gcc_ver} + + # restore this stuff in case later hooks depend on it + export PATH="$oldpath" + export LD_LIBRARY_PATH="$oldldlib" +} + +do_install() { + # We need to be able to access binutils in the root + local oldpath="$PATH" + local oldldlib="$LD_LIBRARY_PATH" + export PATH="${wrksrc}/build_root/usr/bin:$PATH" + export LD_LIBRARY_PATH="${wrksrc}/build_root/usr/lib:$PATH" + + local sysroot="/usr/${cross_triplet}" + local ws=$(cat ${wrksrc}/.gcc_wordsize) + + # Core directories for the sysroot + # + # libexec is created for sysroot but not for dest, since in sysroot + # we configure glibc with separate libexec, elsewhere it's just lib + # and we want to delete the libexec from glibc afterwards to save space + mkdir -p ${DESTDIR}/${sysroot}/usr/{bin,lib,libexec,include,share} + # Sysroot base symlinks + ln -sf usr/lib ${DESTDIR}/${sysroot}/lib + ln -sf usr/lib ${DESTDIR}/${sysroot}/lib${ws} + ln -sf lib ${DESTDIR}/${sysroot}/usr/lib${ws} + + # Install Linux headers + cd ${wrksrc}/linux-$(cat ${wrksrc}/.linux_version) + make ARCH=${cross_linux_arch} \ + INSTALL_HDR_PATH=${DESTDIR}/${sysroot}/usr headers_install + rm -f $(find ${DESTDIR}/${sysroot}/usr/include \ + -name .install -or -name ..install.cmd) + rm -rf ${DESTDIR}/${sysroot}/usr/include/drm + + # Install binutils + cd ${wrksrc}/binutils_build + make install DESTDIR=${DESTDIR} + + # Install final gcc + cd ${wrksrc}/gcc_build + make install DESTDIR=${DESTDIR} + + # Move libcc1.so* to the sysroot + mv ${DESTDIR}/usr/lib/libcc1.so* ${DESTDIR}/${sysroot}/usr/lib + + if [ -f ${wrksrc}/.musl_version ]; then + # Install musl + cd ${wrksrc}/musl_build + make DESTDIR=${DESTDIR}/${sysroot} install + + # Remove useless headers + rm -rf ${DESTDIR}/usr/lib/gcc/${cross_triplet}/*/include-fixed + + # Make ld-musl.so symlinks relative + for f in ${DESTDIR}/${sysroot}/usr/lib/ld-musl-*.so.*; do + ln -sf libc.so ${f} + done + else + # Install glibc + cd ${wrksrc}/glibc_build + make install_root=${DESTDIR}/${sysroot} install install-headers + + # Remove bad header + rm -f ${DESTDIR}/usr/lib/gcc/${cross__triplet}/*/include-fixed/bits/statx.h + fi + + local gcc_ver=$(cat ${wrksrc}/.gcc_version) + + # Symlinks for gnarl and gnat shared libraries + local majorver=${gcc_ver%.*.*} + local adalib=usr/lib/gcc/${_triplet}/${gcc_ver}/adalib + mv ${DESTDIR}/${adalib}/libgnarl-${majorver}.so \ + ${DESTDIR}/${sysroot}/usr/lib + mv ${DESTDIR}/${adalib}/libgnat-${majorver}.so \ + ${DESTDIR}/${sysroot}/usr/lib + ln -sf libgnarl-${majorver}.so ${DESTDIR}/${sysroot}/usr/lib/libgnarl.so + ln -sf libgnat-${majorver}.so ${DESTDIR}/${sysroot}/usr/lib/libgnat.so + rm -vf ${DESTDIR}/${adalib}/libgna{rl,t}.so + + # Remove unnecessary libatomic which is only built for gccgo + rm -rf ${DESTDIR}/${sysroot}/usr/lib/libatomic.* + + # If libquadmath was forced (needed for gfortran on some platforms) + # then remove it because it conflicts with libquadmath package + rm -rf ${DESTDIR}/${sysroot}/usr/lib/libquadmath.* + + # Remove leftover symlinks + rm -f ${DESTDIR}/usr/lib${XBPS_TARGET_WORDSIZE} + rm -f ${DESTDIR}/lib* + rm -f ${DESTDIR}/*bin + # Remove unnecessary stuff + rm -rf ${DESTDIR}/${sysroot}/{sbin,etc,var,libexec} + rm -rf ${DESTDIR}/${sysroot}/usr/{sbin,share,libexec} + rm -rf ${DESTDIR}/usr/share + rm -f ${DESTDIR}/usr/lib*/libiberty.a + + export PATH="$oldpath" + export LD_LIBRARY_PATH="$oldldlib" +} diff --git a/common/environment/build-style/void-cross.sh b/common/environment/build-style/void-cross.sh new file mode 100644 index 0000000000..08d1585e95 --- /dev/null +++ b/common/environment/build-style/void-cross.sh @@ -0,0 +1,13 @@ +lib32disabled=yes +nopie=yes +create_wrksrc=yes + +nostrip_files+=" libcaf_single.a libgcc.a libgcov.a libgcc_eh.a + libgnarl_pic.a libgnarl.a libgnat_pic.a libgnat.a libgmem.a" + +# glibc crosstoolchains not available on musl hosts yet +if [ -z "$archs" -a "${cross_triplet/-musl}" = "${cross_triplet}" ]; then + if [ "$XBPS_TARGET_LIBC" != "glibc" ]; then + archs="~*-musl" + fi +fi