Build a softfp world of the toolchain - #178
Merged
Merged
Conversation
softfp died as a maintained buildscripts branch in 2022 (a synced fork is expensive to keep up), but the workload didn't: github.com/vitasdk-softfp keeps shipping it for Android-to-Vita ports. Coming back as a branch risks the same drift, so VITASDK_FLOAT_ABI makes it a --with-float switch instead, inherited by gcc-base/gcc-final/newlib/pthread-embedded without touching any of their recipes. The world's identity is stamped into version_info.txt, pacman's Architecture and makepkg's CARCH so a softfp core can never be mistaken for the default one. The Sony modules are hard-float (confirmed against vitaGL's existing naked wrapper for sceGxmSetViewport). A softfp caller and a hard-float stub disagree on where 23 functions' float/double arguments and returns live. softfp-shim/ derives the AAPCS-base-to-AAPCS-VFP register move for each straight from vita-headers' real signatures, and patch-softfp-stub-archives.sh splices the generated wrapper into the already-installed stub archives: the real object gets renamed (objcopy --redefine-sym) and the wrapper takes its place under the original name. That's a library placed in front of the stubs in LIB_SPEC in an earlier version of this — it doesn't work, because GCC expands a caller's own -l flags before LIB_SPEC, and every one of these five modules is always linked explicitly by whatever package needs it. An archive splice has no such ordering to lose. Verified against a real linux/aarch64 container build: the toolchain contract passes in both directions (hard and softfp), and a link test reads the linker map to confirm all 23 shimmed symbols resolve against the wrapper, not the raw stub.
Regeneration is a handful of regex passes over a few vita-headers files, cheap enough that trusting a checked-in copy to still match vita-headers was the wrong trade: a stale .S from before a signature change is a wrong ABI shim that still assembles and links without complaint, and nothing would have caught it. build-softfp-shim.sh now runs generate.py against the vita-headers this same build just installed, into a scratch directory, before assembling anything -- functions.tsv stays checked in (it records module ownership vita-headers itself does not expose), only the derived wrappers do not.
Regressed by an earlier git checkout -- in this same session that reverted this file to HEAD and got only partially undone: vita-makepkg went back to a plain copy of makepkg.conf.sample, which always says CARCH="vita", instead of running it through WriteMakepkgConf.cmake. Caught by CI, not locally: validate-core-package.sh's own world-coherence check failed a real vita-softfp build with "version_info.txt says vita-softfp, bin/makepkg.conf CARCH says vita" on every host.
The staged executor takes the profile from the lock, requires it, and then dropped it -- the comment where it landed said as much: "profile is required but not yet consumed: no profile -> VITASDK_FLOAT_ABI mapping exists in CMakeLists.txt yet". So `describe --profile vita-softfp` produced a lock that said softfp and a toolchain that was hard-float, and nothing anywhere said the two disagreed. Profiles.cmake already names the worlds this tree publishes, so it is where the ABI each of them bakes in belongs, next to the name. CMakeLists takes VITASDK_PROFILE, refuses one the tree does not publish, and derives the float ABI and the world's arch from it; build-host.sh passes it in both cmake invocations, since stage 1 builds the sysroot the later stages import. A profile wins over VITASDK_FLOAT_ABI, and silently. CMake cannot tell a cache entry left at its default from one somebody passed, so a check that the two agree would either miss -DVITASDK_FLOAT_ABI=hard or refuse every re-configure of an existing build directory. Passing both is passing the same thing twice. The test runs stage 1 against a cmake that records its arguments, which is what the flag being parsed and dropped would have failed.
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Softfp is a build parameter and a world of the channel, never a branch. The 2021 branch was one line —
--with-float=hard→softfp— plus hand publishing, and what killed it was the cost of keeping a fork in step. This is that one line, in the same tree, reached through the profile the lock already carries.What it adds
VITASDK_FLOAT_ABI, selecting--with-float=in the common GCC configure args, so all three GCC stages and everything built with them inherit it.version_info.txt, the pacmanArchitecture, and the installedmakepkg.conf'sCARCH.validate-core-package.shrefuses a core whose three answers disagree.--profilefrom the lock, required it, and then dropped it — the comment where it landed said so.describe --profile vita-softfpproduced a lock saying softfp and a toolchain that was hard-float, with nothing anywhere noticing.Profiles.cmakealready names the worlds this tree publishes, so the ABI each bakes in lives next to the name.softfp-shim/generate.pyderives the AAPCS-base→AAPCS-VFP move sequence for each of the 23 crossings from the real signatures invita-headers, andpatch-softfp-stub-archives.shsplices the wrappers into the stub archivesvita-headersinstalled. A.aresolves through its member index, not member order, so there is no link-order race to win and no recipe changes: packages keep linking-lSceGxm_stubas before.Verified
Built for real in a container with
-DVITASDK_FLOAT_ABI=softfp, twice — once before the shims existed and once after. The ABI contract test checks both directions (__ARM_PCS_VFPandTag_ABI_VFP_argspresent in hard, absent in softfp), the 73 public headers each compile on their own, and the shim test links the 23 against their real stubs and reads the map file to prove each resolved against the wrapper rather than the renamed trampoline.Known gap
A caller carrying its own hard→softfp wrapper — the
vitasdk-softfporg's vitaGL withSOFTFP_ABI=1— would translate twice against this. That is a line in the migration guide, not a mechanism here: a new world has no binary legacy to be compatible with, so the fix is to stop wrapping.🤖 Generated with Claude Code