Gentoo already allows option 1 by specifying a directory to ultimately install the finished image to (normally it is set to /) [1]. One can do a complete rebuild of everything in @system and @world, install it to the specified subdirectory, and then sync it all over in one shot. Preferably you would do this from a live session, although in theory you could also bind-mount / onto a subdirectory of the place you reinstalled everything to, chroot into it, and then sync it (what is now /) into the bind-mounted real upper /.
It's true that Gentoo has some pieces of what they need to build an implementation of option 1 (build packages that depend on other packages before completeing an install), but it's currently the case that that is not what happens when one runs `emerge` (the gentoo packaging build/installing tool), as you've noted one would need to write scripts that wrap emerge (or do the same work manually) to attempt to accomplish this today.
I suspect that using bind mounts and overlays (to allow the "building packages" chroot a view of the "installed" root) could be used to accomplish this, or alternately some filesystem snapshotting features if we're thinking about this from the "external to emerge" angle. (It's my understanding that for Gentoo to do this ABI change, though, they need some solution integrated into emerge).
To some extent, this kind of potential model also reminds me of systems that integrate their package updating with filesystem snapshotting to allow rollbacks and actually-atomic upgrades of many files. I think one or more of the solaris distributions did this?
> but it's currently the case that that is not what happens when one runs `emerge` (the gentoo packaging build/installing tool)
This would be a simple matter of changing /etc/portage/make.profile to point to a profile that uses the new ABI and setting (and exporting) the ROOT variable in the shell you type "emerge" into (or add this ROOT=/whatever/ line to /etc/portage/make.conf), is what I was getting at. There's no need to write any wrappers.
Simply changing `ROOT` doesn't magically enable us to have `emerge` update our normal `ROOT=/`. There's extra steps here (the syncing, the bind mounting, etc) for the `emerge` with a custom `ROOT` to do an update to `/` itself.
And that's if we have a `ROOT` that allows us to source dependencies (libraries to link against, includes, etc). Currently it's unclear to me how exactly `ROOT` works, probably meaning there needs to be a bit more documentation there and potentially indicating that it might not be used much right now.
> There's extra steps here (the syncing, the bind mounting, etc) for the `emerge` with a custom `ROOT` to do an update to `/` itself.
Those extra steps are handled by telling people what to do, in news items. This happened for example in the 17.1 -> 23.0 profile migration [1]; emerge wasn't updated to help people do this in any way whatsoever, users are expected to do everything themselves. This is the Gentoo way.
> And that's if we had a `ROOT` that allowed us to source dependencies (libraries to link against, includes, etc).
You don't need to source anything in ROOT because everything you're rebuilding is already in /.
If you intended to build a program that depended upon a library you did not already have (in /), you're right, this wouldn't work. That isn't the case here. The dynamic linker (ld-linux.so or whatever you fancy, the ELF interpreter, the thing that runs before main(), the thing that will look at the list of dependent libraries, try to load them, and balk at any mismatches) isn't executed until the program is, and setting ROOT merely tells portage where to put them; it doesn't execute them. This I alluded to in the other comment thread about building a userland that your CPU can't even execute.
Huh. If it's OK to have instructions like those for users to run through, then I guess I don't understand what's holding up switching to 64-bit time_t for gentoo. Seems like they could make a new profile and tell folks to deal with it. Perhaps I don't understand what the requirements are here, which might indicate that the requirements aren't clear for others too.
The third paragraph says following, which means it's not suitable solution to build whole system:
When building a package, ROOT should not be used to satisfy the required dependencies on libraries, headers files etc. Instead, the files on the build system should be specified using /.
Yes, that means it will look in the host system (/) for those dependencies. But when you're also recompiling and installing those dependencies to /whatever/ as well anyway, and /whatever/ is eventually going to end up being /, this is fine. The original / doesn't get touched until everything is done, and /whatever/ is all built to the new ABI, which it can be precisely because nothing in /whatever/ is getting consulted or used during the rebuild process.
No, what rini17 pointed out is a problem here, and I think my previous comments that setting ROOT might be "part of a solution" are less accurate (as it seems `ROOT` is even less of a complete solution here).
Lets consider this hypothetical representation of the 64-bit time issue:
In `ROOT=/`, we have a `libA.so` with 32-bit time_t, and a `libB.so` with 32-bit time_t that depends on `libA` (ie: `libB.so` -> `libA.so`).
We rebuild package `A` with a special root (`ROOT=/tmp/new`) which has 64-bit time_t. We now have a `/tmp/new` with `libA.so` built for 64-bit time_t. We now want to build `B` for `ROOT=/tmp/new` with 64-bit time_t and have it link against the new `/tmp/new/lib/libA.so`.
But setting `ROOT=/tmp/new` doesn't cause us to use the `/tmp/new` to as our source to link against things. So (as it currently stands) we'll end up trying to link `libB.so` (64-bit time_t) against `/lib/libA.so` (32-bit time_t), and things just won't work.
If gentoo changes/extends ROOT (or adds something else like ROOT but used to locate dependencies for linking), then it could be a piece of a solution. But it sounds like it's pretty far from that in intention/practice right now.
> But setting `ROOT=/tmp/new` doesn't cause us to use the `/tmp/new` to as our source to link against things
That's a good thing, because it won't be /tmp/new/ when we're finished.
> So (as it currently stands) we'll end up trying to link `libB.so` (64-bit time_t) against `/lib/libA.so` (32-bit time_t), and things just won't work.
It won't work until /tmp/new/ becomes /, which it doesn't have to until you're done.
Remember that this is just for building and installing the software. It doesn't get executed which is precisely what you want because it wouldn't work properly otherwise, as you point out.
You can even use this method to build a complete userland for an instruction set architecture that your CPU doesn't even support. All you need do is also set CHOST to the tuple identifying the target architecture in addition to setting ROOT for where it should be installed [1]. You just wouldn't be able to chroot into it obviously.
Before getting into the details here about why we need to read `libA.so` at build time: Perhaps the documentation gentoo provides about `ROOT` that was noted by rini17 is incorrect/misleading and `ROOT` is used as the source of build time dependencies automatically and the documentation was intended for ebuild writers and not emerge users? (in which case, Gentoo should fix/clarify it).
"link" has 2 meanings:
1. As you've pointed at, at runtime we have linking occur that reads files.
2. Additionally, building software with `gcc`/etc, we tell it what libraries it needs to link against (`-lA`). When we do that, `gcc` as part of the build process searches for `libA.so` (in various locations dependent on its configuration and arguments), reads the `libA.so` file, and uses that info to determine what to emit in the object file that `gcc` is building. So we need to read a shared library. The same is true for headers used at build time. How much this actually ends up mattering varies depending on architectural details, and whether libraries have different symbols exposed (or generate different header files) depending on what the bit-width of time_t is. It may well be that for most packages we could have the build-time linking occur against a 32-bit time_t object as long as runtime linking is done to the 64-bit time_t object (assuming one is using identical package versions or at least versions with a compatible ABI).
> and whether libraries have different symbols exposed (or generate different header files) depending on what the bit-width of time_t is
Hmm. You have a good point there; I hadn't thought about that...
Perhaps they can take an existing stage3 with 32-bit time_t, build a new stage1 through 3 with a 64-bit time_t, and compare the symbols and header files between them to identify any potential trouble spots. This would help them regardless of what migration course of action they decide upon.
Any software people have installed that isn't included in the stage3 (e.g. desktop window managers and everything else on top) wouldn't be included here and so is a potential pain point, but everything in @system would be, so at that point you can just rebuild @world again to fix everything.
[1] https://devmanual.gentoo.org/ebuild-writing/variables/#root