# Copyright 2022-2025 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 EAPI=8 inherit edo ninja-utils flag-o-matic toolchain-funcs MINGW_PV=$(ver_cut 1-3) LLVM_PV=20.1.6 LLVM_MAJOR=$(ver_cut 1 ${LLVM_PV}) DESCRIPTION="Clang/LLVM based mingw64 toolchain" HOMEPAGE=" https://www.mingw-w64.org/ " SRC_URI=" https://downloads.sourceforge.net/mingw-w64/mingw-w64/mingw-w64-release/mingw-w64-v${MINGW_PV}.tar.bz2 https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_PV}/llvm-project-${LLVM_PV}.src.tar.xz " S="${WORKDIR}" LICENSE=" Apache-2.0-with-LLVM-exceptions || ( UoI-NCSA MIT ) ZPL BSD BSD-2 ISC LGPL-2+ LGPL-2.1+ MIT public-domain " SLOT="0" KEYWORDS="~arm64" IUSE="custom-cflags +strip" BDEPEND=" dev-build/cmake " RDEPEND=" llvm-core/clang:${LLVM_MAJOR} llvm-core/llvm:${LLVM_MAJOR} llvm-core/lld:${LLVM_MAJOR} " DEPEND="${RDEPEND}" HOSTS=( aarch64-w64-mingw32 # i686-w64-mingw32 ) pkg_pretend() { [[ ${MERGE_TYPE} == binary ]] && return tc-is-cross-compiler && die "cross-compilation of the toolchain itself is unsupported" } src_prepare() { # rename directories to simplify both patching and the ebuild mv mingw-w64-v${MINGW_PV} mingw64 || die mv llvm-project-${LLVM_PV}.src llvm-project || die default } src_compile() { # not great but do everything in src_compile given bootstrapping # process needs to be done in steps of configure+compile+install # (done modular to have most package-specific things in one place) MWT_D=${T}/root # moved to ${D} in src_install mwtdir=/usr/lib/${PN} prefix=${EPREFIX}${mwtdir} sysroot=${MWT_D}${prefix} PATH=${sysroot}/bin:${PATH} unset AR CC CPP CXX DLLTOOL LD NM OBJCOPY OBJDUMP RANLIB RC STRIP export AR=llvm-ar export CC=clang export CXX=clang++ export NM=llvm-nm export RANLIB=llvm-ranlib export STRIP=llvm-strip filter-flags '-fuse-ld=*' filter-flags '-mfunction-return=thunk*' #878849 filter-flags '-mbranch-protection=*' #957683 use custom-cflags || filter-flags '-fstack-protector*' #931512 filter-flags '-Wl,-z,*' append-flags -mno-avx filter-lto # requires setting up, and may be messy with mingw static libs use custom-cflags || strip-flags # fancy flags are not realistic here local -A lib_hosts=( aarch64-w64-mingw32 "--disable-lib32 --disable-lib64 --enable-libarm64" i686-w64-mingw32 "--enable-lib32 --disable-lib64 --disable-libarm64" ) for CHOST in ${HOSTS[@]}; do ( per_host_compile ${lib_hosts[${CHOST}]} ) # portage doesn't know the right strip executable to use for CTARGET # and it can lead to .a mangling, notably with 32bit (breaks toolchain) dostrip -x ${mwtdir}/${CHOST}/lib{,32} dostrip -x /usr/lib/llvm/${LLVM_MAJOR}/${CHOST}/lib/lib{c++,unwind}.dll.a done } per_host_compile() { CC="${CC} -target ${CHOST}" \ CXX="${CXX} -target ${CHOST}" \ LD="${LD} -target ${CHOST}" \ strip-unsupported-flags local conf_mingw64=( --build=${CBUILD} --prefix="${prefix}"/${CHOST} --host=${CHOST} --with-sysroot=no --without-{crt,headers} # mingw .dll aren't used by wine and packages wouldn't find them # at runtime, use crossdev if need dll and proper search paths --disable-shared ) local conf_mingw64_headers=( --enable-idl --with-headers ) local conf_mingw64_runtime=( --with-crt $@ ) local conf_mingw64_libraries=( --with-libraries="winpthreads" ) mwt-build() { local id=${1##*/} local build_dir=${WORKDIR}/${1}${2+_${2}}-${CHOST}-build # econf is not allowed in src_compile and its defaults are # mostly unused here, so use configure directly local conf=( "${WORKDIR}/${1}"/configure ) local -n conf_id=conf_${id} conf_id2=conf_${id}_${2} [[ ${conf_id@a} == *a* ]] && conf+=( "${conf_id[@]}" ) [[ ${2} && ${conf_id2@a} == *a* ]] && conf+=( "${conf_id2[@]}" ) einfo "Building ${id}${2+ ${2}} in ${build_dir} ..." mkdir -p "${build_dir}" || die pushd "${build_dir}" >/dev/null || die edo "${conf[@]}" emake MAKEINFO=: V=1 # -j1 to match bug #906155, other packages may be fragile too emake -j1 MAKEINFO=: V=1 DESTDIR="${MWT_D}" install popd >/dev/null || die } cmake-build() { local id1=${1/-/_} local id2=${2/-/_} local -n conf_id=conf_${id1} conf_id2=conf_${id1}_${id2} local conf=( "${conf_id[@]}" ) [[ ${2} && ${conf_id2@a} == *a* ]] && conf+=( "${conf_id2[@]}" ) local build_dir=${WORKDIR}/${1}${2+_${2}}-${CHOST}-build mkdir "${build_dir}" || die pushd "${build_dir}" >/dev/null || die cmake -GNinja \ "${conf[@]}" "${WORKDIR}/$1/$2" || die eninja DESTDIR="${MWT_D}" eninja install popd >/dev/null || die } CPPFLAGS="$CPPFLAGS -target ${CHOST}" mwt-build mingw64 headers CPPFLAGS="$CPPFLAGS -isystem ${MWT_D}${prefix}/${CHOST}/include" export RCFLAGS="$RCFLAGS -I${MWT_D}${prefix}/${CHOST}/include" LDFLAGS="$LDFLAGS -fuse-ld=lld" mwt-build mingw64 runtime local resource_dir="${T}/resource-dir-${CHOST}" cp -a "${BROOT}/usr/lib/clang/${LLVM_MAJOR}" "${resource_dir}" || die LDFLAGS="$LDFLAGS -rtlib=compiler-rt -stdlib=libc++ -L${MWT_D}${prefix}/${CHOST}/lib" CPPFLAGS="$CPPFLAGS -resource-dir ${resource_dir}" local conf_llvm_project=( -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER_WORKS=1 -DCMAKE_C_COMPILER_TARGET="${CHOST}" -DCMAKE_ASM_COMPILER_TARGET="${CHOST}" -DCMAKE_CXX_COMPILER_TARGET="${CHOST}" -DCMAKE_C_FLAGS_INIT="${CPPFLAGS}" -DCMAKE_CXX_FLAGS_INIT="${CPPFLAGS}" ) local comp_rt_install="${EPREFIX}/usr/lib/clang/${LLVM_MAJOR}" local conf_llvm_project_compiler_rt=( -DCOMPILER_RT_INSTALL_PATH="${comp_rt_install}" -DCOMPILER_RT_BUILD_BUILTINS=TRUE -DCOMPILER_RT_DEFAULT_TARGET_ONLY=TRUE -DCOMPILER_RT_EXCLUDE_ATOMIC_BUILTIN=FALSE -DLLVM_CONFIG_PATH="" -DCMAKE_FIND_ROOT_PATH="${prefix}/${CHOST}" -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY -DCOMPILER_RT_BUILD_SANITIZERS=FALSE -DCOMPILER_RT_BUILD_CTX_PROFILE=FALSE -DCOMPILER_RT_BUILD_XRAY=FALSE -DCOMPILER_RT_BUILD_ORC=FALSE -DCOMPILER_RT_BUILD_PROFILE=FALSE -DCOMPILER_RT_BUILD_MEMPROF=FALSE -DCOMPILER_RT_BUILD_LIBFUZZER=FALSE ) local conf_llvm_project_runtimes=( -DLLVM_ENABLE_RUNTIMES="libunwind;libcxxabi;libcxx" -DCMAKE_INSTALL_PREFIX="${EPREFIX}/usr/lib/llvm/${LLVM_MAJOR}/${CHOST}" -DLIBUNWIND_USE_COMPILER_RT=TRUE -DLIBUNWIND_ENABLE_SHARED=TRUE -DLIBCXX_USE_COMPILER_RT=TRUE -DLIBCXX_ENABLE_SHARED=TRUE -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=TRUE -DLIBCXX_CXX_ABI=libcxxabi -DLIBCXX_LIBDIR_SUFFIX="" -DLIBCXX_INCLUDE_TESTS=FALSE -DLIBCXX_INSTALL_MODULES=TRUE -DLIBCXX_ENABLE_ABI_LINKER_SCRIPT=FALSE -DLIBCXXABI_USE_COMPILER_RT=TRUE -DLIBCXXABI_USE_LLVM_UNWINDER=TRUE -DLIBCXXABI_ENABLE_SHARED=OFF -DLIBCXXABI_LIBDIR_SUFFIX="" ) cmake-build llvm-project compiler-rt cp -a "${MWT_D}/${comp_rt_install}"/* "${resource_dir}/" || die cmake-build llvm-project runtimes mwt-build mingw64 libraries } src_install() { mv -- "${MWT_D}${EPREFIX}"/* "${ED}" || die find "${ED}" -type f -name '*.la' -delete || die bindir="${ED}/usr/lib/llvm-mingw64/bin" mkdir -p "${bindir}" || die mkdir -p "${ED}/etc/clang/${LLVM_MAJOR}" || die for CHOST in ${HOSTS[@]}; do ( per_host_install ) done } per_host_install() { local cchost="${CHOST/mingw32/windows-gnu}" for bin in clang clang++; do ln -s "${EPREFIX}/usr/lib/llvm/${LLVM_MAJOR}/bin/${bin}" "${bindir}/${CHOST}-${bin}" || die echo "@${cchost}-common.cfg" >"${ED}/etc/clang/${LLVM_MAJOR}/${cchost}-${bin}.cfg" || die done cat >"${ED}/etc/clang/${LLVM_MAJOR}/${cchost}-common.cfg" <<-EOF -Xclang=-internal-isystem -Xclang=${EPREFIX}/usr/lib/${PN}/${CHOST}/include -stdlib=libc++ -rtlib=compiler-rt -unwindlib=libunwind -L${EPREFIX}/usr/lib/${PN}/${CHOST}/lib/ EOF for bin in dlltool windres ar; do ln -s "${EPREFIX}/usr/lib/llvm/${LLVM_MAJOR}/bin/llvm-${bin}" "${bindir}/${CHOST}-${bin}" || die done } pkg_postinst() { if [[ ! ${REPLACING_VERSIONS} ]]; then elog "Note that this package is primarily intended for Wine and related" elog "packages to depend on without needing a manual crossdev setup." elog elog "Settings are oriented only for what these need and simplicity." elog "Use sys-devel/crossdev if need full toolchain/customization:" elog " https://wiki.gentoo.org/wiki/Mingw" elog " https://wiki.gentoo.org/wiki/Crossdev" fi }