Last active
January 12, 2020 22:28
-
-
Save chewi/1601684ad8f3cf8de0b786c00fa09b3c to your computer and use it in GitHub Desktop.
Migrates a Gentoo ARM system from the old style tuple (CHOST) to the new style tuple ending in hf.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Abort if things go wrong. Very important! | |
set -ex | |
# Fetch the old CHOST from make.conf or profile. | |
OLD_CHOST=$(portageq envvar CHOST) | |
# The new CHOST needs to end in hf. The vendor part doesn't really | |
# matter as long as it's not softfloat or softfp but the convention is | |
# to replace hardfloat with unknown. | |
CHOST=${OLD_CHOST/-hardfloat-/-unknown-}hf | |
case ${OLD_CHOST} in | |
"") | |
echo "Unable to determine the old CHOST value. Is make.conf sane? Do you have a valid profile selected?" | |
exit 1 ;; | |
*-softfloat-*) | |
echo "This appears to be a softfloat system so you should not be running this script." | |
exit 1 ;; | |
*-softfp-*) | |
echo "This appears to be a softfp system. Your hardware may be hardfloat-capable but you cannot migrate using this script." | |
exit 1 ;; | |
*hf) | |
echo "You already have the new *hf CHOST? Either you've already successful run this or you're doing something crazy." | |
exit 1 ;; | |
esac | |
# This function is used to skip parts of this script if it is being | |
# retried following a failure. It checks whether the given atom has | |
# been built against the new CHOST. | |
atom_new_chost() { | |
local path=${VDB}/${1}/CHOST | |
[[ ! -f ${path} ]] && return 1 | |
[[ $(cat "${path}") == ${CHOST} ]] | |
} | |
# This script supports prefixed systems. | |
EPREFIX=$(portageq envvar EPREFIX) | |
# The VDB path is needed for atom_new_chost above. | |
VDB=$(portageq vdb_path) | |
# Fetch the old profile and convert to the new profile. The new | |
# profile may already be selected if this script is being retried so | |
# convert both ways just in case. Note that some profiles like | |
# hardened are not versioned so these will not change. That is okay. | |
OLD_PROFILE=$(eselect --brief profile show) | |
OLD_PROFILE=${OLD_PROFILE/17.0/13.0} | |
NEW_PROFILE=${OLD_PROFILE/13.0/17.0} | |
# What are the latest binutils and gcc versions we can install? | |
BINUTILS_PF=$(portageq best_visible "${EPREFIX}"/ sys-devel/binutils) | |
GCC_PF=$(portageq best_visible "${EPREFIX}"/ sys-devel/gcc) | |
# We need the new binutils PV and gcc SLOT for some operations below. | |
BINUTILS_PV=${BINUTILS_PF#sys-devel/binutils-} | |
BINUTILS_PV=${BINUTILS_PV%-r*} | |
GCC_SLOT=$(portageq metadata "${EPREFIX}"/ ebuild "${GCC_PF}" SLOT) | |
# What libc does this profile use, what is the latest we can install? | |
LIBC=$(portageq expand_virtual "${EPREFIX}"/ virtual/libc) | |
LIBC_PF=$(portageq best_visible "${EPREFIX}"/ "${LIBC}") | |
# What are the latest libtool and perl versions we can install? | |
LIBTOOL_PF=$(portageq best_visible "${EPREFIX}"/ sys-devel/libtool) | |
PERL_PF=$(portageq best_visible "${EPREFIX}"/ dev-lang/perl) | |
# Ensure portage, sandbox, and portage-utils are up to date. Older | |
# sandbox can block newer libtool. portage-utils is needed for qfile. | |
emerge -v1u sys-apps/portage sys-apps/sandbox app-portage/portage-utils | |
# Backup the old toolchain, just in case. | |
atom_new_chost "${BINUTILS_PF}" || | |
quickpkg sys-devel/binutils sys-devel/gcc "${LIBC}" | |
# Select the new profile. | |
eselect profile set --force ${NEW_PROFILE} | |
# If we modify make.conf with the new CHOST now then we won't be able | |
# to reliably determine the old CHOST when retrying this script. Just | |
# override with this variable and modify make.conf at the end. | |
export CHOST | |
# Build binutils with the new CHOST. | |
atom_new_chost "${BINUTILS_PF}" || | |
emerge -v1 "=${BINUTILS_PF}" | |
# Remove old binutils versions to avoid a mix-up. | |
! emerge -C "<${BINUTILS_PF}" | |
# Explicitly select the newly built binutils. | |
binutils-config "${CHOST}-${BINUTILS_PV}" | |
# Build gcc with the new CHOST. | |
atom_new_chost "${GCC_PF}" || | |
emerge -v1 "=${GCC_PF}" | |
# Remove old gcc versions to avoid a mix-up. | |
! emerge -C "<${GCC_PF}" | |
# Explicitly select the newly built gcc. | |
gcc-config -f "${CHOST}-${GCC_SLOT}" | |
# Delete old CHOST files from env.d. | |
find "${EPREFIX}"/etc/env.d/ -regex ".*\\b${OLD_CHOST}\\b.*" -exec rm -v {} + | |
# Delete old CHOST files from ld.so.conf.d, which may not exist. | |
[[ -d "${EPREFIX}"/etc/ld.so.conf.d ]] && | |
find "${EPREFIX}"/etc/ld.so.conf.d/ -regex ".*\\b${OLD_CHOST}\\b.*" -exec rm -v {} + | |
# Refresh the environment. | |
env-update | |
source "${EPREFIX}"/etc/profile | |
ldconfig | |
# Build libc with the new CHOST. | |
atom_new_chost "${LIBC_PF}" || | |
emerge -v1 "=${LIBC_PF}" | |
# Rebuild libtool and binutils as required for a PIE migration. | |
if ! atom_new_chost "${LIBTOOL_PF}"; then | |
emerge -v1 "=${BINUTILS_PF}" | |
emerge -v1 "=${LIBTOOL_PF}" | |
fi | |
# fix_libtool_files.sh is sometimes needed after changing CHOST. | |
"${EPREFIX}"/usr/share/gcc-data/"${CHOST}/${GCC_SLOT}"/fix_libtool_files.sh "${GCC_SLOT}" --oldarch "${OLD_CHOST}" | |
# Delete any orphaned files under /usr/bin that are prefixed with the | |
# old CHOST. This is mainly to clean up files created by gcc-config. | |
qfile -o "${EPREFIX}"/usr/bin/"${OLD_CHOST}"-* | xargs rm -vf | |
# Rename any remaining files under /usr/bin that are prefixed with the | |
# old CHOST so that they now have the new CHOST instead. | |
find "${EPREFIX}"/usr/bin -name "${OLD_CHOST}-*" -execdir bash -c "X='{}'; mv -v \"\${X}\" \"\${X/${OLD_CHOST}/${CHOST}}\"" \; | |
# The previous operation will have broken symlinks such as xml2-config | |
# so replace the old CHOST with the new CHOST in such symlinks. | |
find "${EPREFIX}"/usr/bin -lname "${OLD_CHOST}-*" -execdir bash -c "X='{}'; ln -snfv \"${CHOST}-\${X##*/}\" \"\${X}\"" \; | |
# Safely delete broken symlinks and empty directories from the old | |
# toolchain including the main top-level directory, if possible. | |
! find "${EPREFIX}/usr/${OLD_CHOST}"/ -xtype l -delete | |
! find "${EPREFIX}/usr/${OLD_CHOST}"/ -type d -empty -delete | |
# Python is sensitive to a CHOST change but a sed fix is sufficient. | |
sed -i "s/${OLD_CHOST}/${CHOST}/g" "${EPREFIX}"/usr/lib/python*/{_sysconfigdata*.py,config*/Makefile} | |
# Update make.conf with the new CHOST. We do this before rebuilding | |
# Perl below because Perl is a prime candidate for package blockers, | |
# which you are free to resolve manually at this point. | |
sed -i "/CHOST=/s/${OLD_CHOST}/${CHOST}/" "${EPREFIX}"/etc/portage/make.conf | |
# Perl is sensitive to a CHOST change so rebuild. | |
if portageq has_version "${EPREFIX}"/ dev-lang/perl && ! atom_new_chost "${PERL_PF}"; then | |
emerge -v1 "=${PERL_PF}" | |
fi | |
echo "All done! :)" | |
[[ -d "${EPREFIX}/usr/${OLD_CHOST}" ]] && | |
echo "Tried to delete ${EPREFIX}/usr/${OLD_CHOST} but it wasn't empty. Please check and delete it manually." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment