|
| 1 | +# Copyright 2019-2023 Gentoo Authors |
| 2 | +# Distributed under the terms of the GNU General Public License v2 |
| 3 | + |
| 4 | +# @ECLASS: usr-ldscript.eclass |
| 5 | +# @MAINTAINER: |
| 6 | +# Toolchain Ninjas <[email protected]> |
| 7 | +# @SUPPORTED_EAPIS: 7 8 |
| 8 | +# @BLURB: Defines the gen_usr_ldscript function. |
| 9 | + |
| 10 | +case ${EAPI} in |
| 11 | + 7|8) ;; |
| 12 | + *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;; |
| 13 | +esac |
| 14 | + |
| 15 | +if [[ -z ${_USR_LDSCRIPT_ECLASS} ]]; then |
| 16 | +_USR_LDSCRIPT_ECLASS=1 |
| 17 | + |
| 18 | +inherit multilib toolchain-funcs |
| 19 | + |
| 20 | +IUSE="split-usr" |
| 21 | + |
| 22 | +# @FUNCTION: gen_usr_ldscript |
| 23 | +# @USAGE: [-a] <list of libs to create linker scripts for> |
| 24 | +# @DESCRIPTION: |
| 25 | +# This function generate linker scripts in /usr/lib for dynamic |
| 26 | +# libs in /lib. This is to fix linking problems when you have |
| 27 | +# the .so in /lib, and the .a in /usr/lib. What happens is that |
| 28 | +# in some cases when linking dynamic, the .a in /usr/lib is used |
| 29 | +# instead of the .so in /lib due to gcc/libtool tweaking ld's |
| 30 | +# library search path. This causes many builds to fail. |
| 31 | +# See bug #4411 for more info. |
| 32 | +# |
| 33 | +# Note that you should in general use the unversioned name of |
| 34 | +# the library (libfoo.so), as ldconfig should usually update it |
| 35 | +# correctly to point to the latest version of the library present. |
| 36 | +gen_usr_ldscript() { |
| 37 | + local lib libdir=$(get_libdir) output_format="" auto=false suffix=$(get_libname) |
| 38 | + |
| 39 | + tc-is-static-only && return |
| 40 | + use prefix && return |
| 41 | + |
| 42 | + # The toolchain's sysroot is automatically prepended to paths in this |
| 43 | + # script. We therefore need to omit EPREFIX on standalone prefix (RAP) |
| 44 | + # systems. prefix-guest (non-RAP) systems don't apply a sysroot so EPREFIX |
| 45 | + # is still needed in that case. This is moot because the above line makes |
| 46 | + # the function a noop on prefix, but we keep this in case that changes. |
| 47 | + local prefix=$(usex prefix-guest "${EPREFIX}" "") |
| 48 | + |
| 49 | + # We only care about stuffing / for the native ABI. #479448 |
| 50 | + if [[ $(type -t multilib_is_native_abi) == "function" ]] ; then |
| 51 | + multilib_is_native_abi || return 0 |
| 52 | + fi |
| 53 | + |
| 54 | + # Eventually we'd like to get rid of this func completely #417451 |
| 55 | + case ${CTARGET:-${CHOST}} in |
| 56 | + *-darwin*) ;; |
| 57 | + *-android*) return 0 ;; |
| 58 | + *linux*) |
| 59 | + use split-usr || return 0 |
| 60 | + ;; |
| 61 | + *) return 0 ;; |
| 62 | + esac |
| 63 | + |
| 64 | + # Just make sure it exists |
| 65 | + dodir /usr/${libdir} |
| 66 | + |
| 67 | + if [[ $1 == "-a" ]] ; then |
| 68 | + auto=true |
| 69 | + shift |
| 70 | + dodir /${libdir} |
| 71 | + fi |
| 72 | + |
| 73 | + # OUTPUT_FORMAT gives hints to the linker as to what binary format |
| 74 | + # is referenced ... makes multilib saner |
| 75 | + local flags=( ${CFLAGS} ${LDFLAGS} -Wl,--verbose ) |
| 76 | + if $(tc-getLD) --version | grep -q 'GNU gold' ; then |
| 77 | + # If they're using gold, manually invoke the old bfd. #487696 |
| 78 | + local d="${T}/bfd-linker" |
| 79 | + mkdir -p "${d}" |
| 80 | + ln -sf $(type -P ${CHOST}-ld.bfd) "${d}"/ld |
| 81 | + flags+=( -B"${d}" ) |
| 82 | + fi |
| 83 | + output_format=$($(tc-getCC) "${flags[@]}" 2>&1 | sed -n 's/^OUTPUT_FORMAT("\([^"]*\)",.*/\1/p') |
| 84 | + [[ -n ${output_format} ]] && output_format="OUTPUT_FORMAT ( ${output_format} )" |
| 85 | + |
| 86 | + for lib in "$@" ; do |
| 87 | + local tlib |
| 88 | + if ${auto} ; then |
| 89 | + lib="lib${lib}${suffix}" |
| 90 | + else |
| 91 | + # Ensure /lib/${lib} exists to avoid dangling scripts/symlinks. |
| 92 | + # This especially is for AIX where $(get_libname) can return ".a", |
| 93 | + # so /lib/${lib} might be moved to /usr/lib/${lib} (by accident). |
| 94 | + [[ -r ${ED}/${libdir}/${lib} ]] || continue |
| 95 | + #TODO: better die here? |
| 96 | + fi |
| 97 | + |
| 98 | + case ${CTARGET:-${CHOST}} in |
| 99 | + *-darwin*) |
| 100 | + if ${auto} ; then |
| 101 | + tlib=$(scanmacho -qF'%S#F' "${ED}"/usr/${libdir}/${lib}) |
| 102 | + else |
| 103 | + tlib=$(scanmacho -qF'%S#F' "${ED}"/${libdir}/${lib}) |
| 104 | + fi |
| 105 | + [[ -z ${tlib} ]] && die "unable to read install_name from ${lib}" |
| 106 | + tlib=${tlib##*/} |
| 107 | + |
| 108 | + if ${auto} ; then |
| 109 | + mv "${ED}"/usr/${libdir}/${lib%${suffix}}.*${suffix#.} "${ED}"/${libdir}/ || die |
| 110 | + # some install_names are funky: they encode a version |
| 111 | + if [[ ${tlib} != ${lib%${suffix}}.*${suffix#.} ]] ; then |
| 112 | + mv "${ED}"/usr/${libdir}/${tlib%${suffix}}.*${suffix#.} "${ED}"/${libdir}/ || die |
| 113 | + fi |
| 114 | + rm -f "${ED}"/${libdir}/${lib} |
| 115 | + fi |
| 116 | + |
| 117 | + # Mach-O files have an id, which is like a soname, it tells how |
| 118 | + # another object linking against this lib should reference it. |
| 119 | + # Since we moved the lib from usr/lib into lib this reference is |
| 120 | + # wrong. Hence, we update it here. We don't configure with |
| 121 | + # libdir=/lib because that messes up libtool files. |
| 122 | + # Make sure we don't lose the specific version, so just modify the |
| 123 | + # existing install_name |
| 124 | + if [[ ! -w "${ED}/${libdir}/${tlib}" ]] ; then |
| 125 | + chmod u+w "${ED}/${libdir}/${tlib}" || die # needed to write to it |
| 126 | + local nowrite=yes |
| 127 | + fi |
| 128 | + install_name_tool \ |
| 129 | + -id "${EPREFIX}"/${libdir}/${tlib} \ |
| 130 | + "${ED}"/${libdir}/${tlib} || die "install_name_tool failed" |
| 131 | + if [[ -n ${nowrite} ]] ; then |
| 132 | + chmod u-w "${ED}/${libdir}/${tlib}" || die |
| 133 | + fi |
| 134 | + # Now as we don't use GNU binutils and our linker doesn't |
| 135 | + # understand linker scripts, just create a symlink. |
| 136 | + pushd "${ED}/usr/${libdir}" > /dev/null |
| 137 | + ln -snf "../../${libdir}/${tlib}" "${lib}" |
| 138 | + popd > /dev/null |
| 139 | + ;; |
| 140 | + *) |
| 141 | + if ${auto} ; then |
| 142 | + tlib=$(scanelf -qF'%S#F' "${ED}"/usr/${libdir}/${lib}) |
| 143 | + [[ -z ${tlib} ]] && die "unable to read SONAME from ${lib}" |
| 144 | + mv "${ED}"/usr/${libdir}/${lib}* "${ED}"/${libdir}/ || die |
| 145 | + # some SONAMEs are funky: they encode a version before the .so |
| 146 | + if [[ ${tlib} != ${lib}* ]] ; then |
| 147 | + mv "${ED}"/usr/${libdir}/${tlib}* "${ED}"/${libdir}/ || die |
| 148 | + fi |
| 149 | + rm -f "${ED}"/${libdir}/${lib} |
| 150 | + else |
| 151 | + tlib=${lib} |
| 152 | + fi |
| 153 | + cat > "${ED}/usr/${libdir}/${lib}" <<-END_LDSCRIPT |
| 154 | + /* GNU ld script |
| 155 | + Since Gentoo has critical dynamic libraries in /lib, and the static versions |
| 156 | + in /usr/lib, we need to have a "fake" dynamic lib in /usr/lib, otherwise we |
| 157 | + run into linking problems. This "fake" dynamic lib is a linker script that |
| 158 | + redirects the linker to the real lib. And yes, this works in the cross- |
| 159 | + compiling scenario as the sysroot-ed linker will prepend the real path. |
| 160 | +
|
| 161 | + See bug https://bugs.gentoo.org/4411 for more info. |
| 162 | + */ |
| 163 | + ${output_format} |
| 164 | + GROUP ( ${prefix}/${libdir}/${tlib} ) |
| 165 | + END_LDSCRIPT |
| 166 | + ;; |
| 167 | + esac |
| 168 | + fperms a+x "/usr/${libdir}/${lib}" || die "could not change perms on ${lib}" |
| 169 | + done |
| 170 | +} |
| 171 | + |
| 172 | +fi # _USR_LDSCRIPT_ECLASS |
0 commit comments