summaryrefslogtreecommitdiff
path: root/eclass/sysroot.eclass
blob: f17d6bcec2b4b1094fd30075feceb6a247914710 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# Copyright 2025 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

# @ECLASS: sysroot.eclass
# @MAINTAINER:
# cross@gentoo.org
# @AUTHOR:
# James Le Cuirot <chewi@gentoo.org>
# @SUPPORTED_EAPIS: 7 8
# @BLURB: Common functions for using a different (sys)root
# @DESCRIPTION:
# This eclass provides common functions to run executables within a different
# root or sysroot, with or without emulation by QEMU. Despite the name, these
# functions can be used in src_* or pkg_* phase functions.

case ${EAPI} in
	7|8) ;;
	*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
esac

# @FUNCTION: qemu_arch
# @DESCRIPTION:
# Return the QEMU architecture name for the given target or CHOST. This name is
# used in qemu-user binary filenames, e.g. qemu-ppc64le.
qemu_arch() {
	local target=${1:-${CHOST}}
	case ${target} in
		armeb*) echo armeb ;;
		arm*) echo arm ;;
		hppa*) echo hppa ;;
		i?86*) echo i386 ;;
		m68*) echo m68k ;;
		mips64el*-gnuabi64) echo mips64el ;;
		mips64el*-gnuabin32) echo mipsn32el ;;
		mips64*-gnuabi64) echo mips64 ;;
		mips64*-gnuabin32) echo mipsn32 ;;
		powerpc64le*) echo ppc64le ;;
		powerpc64*) echo ppc64 ;;
		powerpc*) echo ppc ;;
		*) echo "${target%%-*}" ;;
	esac
}

# @FUNCTION: sysroot_make_run_prefixed
# @DESCRIPTION:
# Create a wrapper script for directly running executables within a (sys)root
# without changing the root directory. The path to that script is returned. If
# no sysroot has been set, then this function returns unsuccessfully.
#
# The script explicitly uses QEMU if this is necessary and it is available in
# this environment. It may otherwise implicitly use a QEMU outside this
# environment if binfmt_misc has been used with the F flag. It is not feasible
# to add a conditional dependency on QEMU.
sysroot_make_run_prefixed() {
	local QEMU_ARCH=$(qemu_arch) SCRIPT MYROOT MYEROOT LIBGCC

	if [[ ${EBUILD_PHASE_FUNC} == src_* ]]; then
		[[ -z ${SYSROOT} ]] && return 1
		SCRIPT="${T}"/sysroot-run-prefixed
		MYROOT=${SYSROOT}
		MYEROOT=${ESYSROOT}

		# Both methods below might need help to find GCC's libs. GCC might not
		# be installed in the SYSROOT. Note that Clang supports this flag too.
		LIBGCC=$($(tc-getCC) ${CPPFLAGS} ${CFLAGS} ${LDFLAGS} -print-libgcc-file-name)
		LIBGCC=${LIBGCC%/*}
	else
		[[ -z ${ROOT} ]] && return 1
		SCRIPT="${T}"/root-run-prefixed
		MYROOT=${ROOT}
		MYEROOT=${EROOT}

		# Both methods below might need help to find GCC's libs. libc++ systems
		# won't have this file, but it's not needed in that case.
		if [[ -f ${EROOT}/etc/ld.so.conf.d/05gcc-${CHOST}.conf ]]; then
			local LIBGCC_A
			mapfile -t LIBGCC_A < "${EROOT}/etc/ld.so.conf.d/05gcc-${CHOST}.conf"
			LIBGCC=$(printf "%s:" "${LIBGCC_A[@]/#/${ROOT}}")
			LIBGCC=${LIBGCC%:}
		fi
	fi

	if [[ ${QEMU_ARCH} == $(qemu_arch "${CBUILD}") ]]; then
		# glibc: ld.so is a symlink, ldd is a binary.
		# musl: ld.so doesn't exist, ldd is a symlink.
		local DLINKER=$(find "${MYEROOT}"/usr/bin/{ld.so,ldd} -type l -print -quit 2>/dev/null || die "failed to find dynamic linker")

		# musl symlinks ldd to ld-musl.so to libc.so. We want the ld-musl.so
		# path, not the libc.so path, so don't resolve the symlinks entirely.
		DLINKER=$(readlink -ev "${DLINKER}" || die "failed to find dynamic linker")

		# Using LD_LIBRARY_PATH to set the prefix is not perfect, as it doesn't
		# adjust RUNPATHs, but it is probably good enough.
		install -m0755 /dev/stdin "${SCRIPT}" <<-EOF || die
			#!/bin/sh
			LD_LIBRARY_PATH="\${LD_LIBRARY_PATH}\${LD_LIBRARY_PATH+:}${LIBGCC}:${MYEROOT}/$(get_libdir):${MYEROOT}/usr/$(get_libdir)" exec "${DLINKER}" "\${@}"
		EOF
	else
		# Use QEMU's environment variables rather than its command line
		# arguments to cover both explicit and implicit QEMU usage.
		install -m0755 /dev/stdin "${SCRIPT}" <<-EOF || die
			#!/bin/sh
			QEMU_SET_ENV="\${QEMU_SET_ENV}\${QEMU_SET_ENV+,}LD_LIBRARY_PATH=\${LD_LIBRARY_PATH}\${LD_LIBRARY_PATH+:}${LIBGCC}" QEMU_LD_PREFIX="${MYROOT}" exec $(type -P "qemu-${QEMU_ARCH}") "\${@}"
		EOF
	fi

	echo "${SCRIPT}"
}

# @FUNCTION: sysroot_run_prefixed
# @DESCRIPTION:
# Create a wrapper script with sysroot_make_run_prefixed if necessary, and use
# it to execute the given command, otherwise just execute the command directly.
sysroot_run_prefixed() {
	local script
	if script=$(sysroot_make_run_prefixed); then
		"${script}" "${@}"
	else
		"${@}"
	fi
}