homebrew-core icon indicating copy to clipboard operation
homebrew-core copied to clipboard

glibc 2.35

Open sjackman opened this issue 1 year ago • 29 comments

  • [email protected] 5.15.57 (new formula)
  • glibc 2.35
  • Add --disable-crypt to prevent the conflict with libxcrypt

  • [x] Have you followed the guidelines for contributing?
  • [x] Have you ensured that your commits follow the commit style guide?
  • [x] Have you checked that there aren't other open pull requests for the same formula update/change?
  • [x] Have you built your formula locally with brew install --build-from-source <formula>, where <formula> is the name of the formula you're submitting?
  • [x] Is your test running fine brew test <formula>, where <formula> is the name of the formula you're submitting?
  • [ ] Does your build pass brew audit --strict <formula> (after doing brew install --build-from-source <formula>)? If this is a new formula, does it pass brew audit --new <formula>?

sjackman avatar Jul 29 '22 06:07 sjackman

A few things to note about this on CentOS 7:

  1. The host GCC is too old and I've got code I'd like to push that will vendor GCC if this is the case. We wouldn't want to use the fails_with syntax for this anymore in that case but instead of fall back to the vendored GCC if the host is too old. The GCC bootstrap process also requires bzip2, which I would like to build against [email protected] (bzip2 is relocatable).
  2. glibc now requires bison to build as well. This is bottle is also relocatable, though its dependency m4 is not. Nonetheless I'd like to build both of these against [email protected].
  3. glibc also requires Python 3.4 to build. This is extremely annoying but I am looking at how difficult it is to vendor this as well. I suspect it won't be that bad as most of the dependencies we have in our formulae are technically optional and since this is a temporary resource anyway, we only care about building what is absolutely necessary to build glibc and nothing more.
  4. The version of make is too old on CentOS 7. make is not relocatable but we can still build with [email protected].

I know this looks like a lot but it's all within the realm of things we already know how to do. I'd like to have a few days to test all this out and see if I can push an update that "just works" on a fresh CentOS 7 installation without requiring any manual intervention or preparation by the user. This would resolve all of my concerns about migrating to Ubuntu 22.04 and would make the upgrade process smooth (albeit a bit tedious) for existing users with glibc installations.

Lastly I will say here that my hope once the migration is done is to still get glibc to have an :any cellar. If we can achieve this we can massively simplify this formula as we'd always just ship a bottle to users and not have to care about them being able to build it. So hopefully these changes are temporary at best!

danielnachun avatar Jul 29 '22 13:07 danielnachun

This would resolve all of my concerns about migrating to Ubuntu 22.04

@danielnachun this is maybe unfair but it sounds like literally all your concerns centre around the CentOS 7 experience. Is that the case? If so, why are we optimising so much for a single distribution?

Lastly I will say here that my hope once the migration is done is to still get glibc to have an :any cellar.

To be honest, I'm not sure it's worth blocking the migration on the issues you've mentioned but not this. I don't have the data to back this up but it does seem most Homebrew on Linux users aren't using the default cellar.

MikeMcQuaid avatar Jul 29 '22 14:07 MikeMcQuaid

  • Add --disable-crypt to prevent the conflict with libxcrypt

100% agree in doing this. It's a bit messy if we were to do so later.

We should make sure we're actually libcrypt.so.1 free though. libxcrypt ships libcrypt.so.2. We might be close so we could enable HOMEBREW_DISALLOW_LIBCRYPT1 in CI for a little bit to make sure and hopefully not need to delay this PR too much. The question might be whether third party taps are ready. We still only omit a warning, but we were only planning to make it become a hard error in Homebrew 3.6.0 which is probably too late if we're going to stop shipping it before that - though I reckon we could depart from the usual deprecated & disabled timings for this scenario, which we already did for the initial deprecation anyway by deprecating in 3.4.10.

Bo98 avatar Jul 29 '22 20:07 Bo98

bison: m4 subprocess failed
[739](https://github.com/Homebrew/homebrew-core/runs/7588330781?check_suite_focus=true#step:7:740)
  Makefile:45: recipe for target '/tmp/glibc-20220730-19395-1t9wthi/glibc-2.35/build/intl/plural.c' failed
[740](https://github.com/Homebrew/homebrew-core/runs/7588330781?check_suite_focus=true#step:7:741)

https://github.com/Homebrew/homebrew-core/runs/7588330781?check_suite_focus=true#step:7:739

Looks like it requires m4 to build.

sjackman avatar Jul 30 '22 19:07 sjackman

I have really great news about the vendoring approach - I've gotten it to work flawlessly on a barebones CentOS 7 system with very minimal fuss. @sjackman I'd like to push a commit here so I can test it in completely clean CentOS 7 Docker image.

The only minor things I'd like help with are:

  1. Intelligently checking the versions of make and gcc so that we only fall back to vendoring them if they are missing or if they are too old. The other build dependencies either have no minimum version requirement or the requirement is so ancient there is no point in checking, even on CentOS 7 or other older LInux. For those cases I'm just checking for the presence of the tool and falling back to vendoring if it they are not detected.
  2. Deciding if we want to allow brewed or user-supplied GCC. My inclination here is to try to use /usr/bin/gcc, and if this is too old to just vendor GCC. We can improve on making this more flexible later, but I don't want to hold this up trying to tweak this too much.

Once these issues are resolved we'll just have to settle on a glibc version we want to use based on the CI image we want and we should be all set for the migration!

danielnachun avatar Jul 30 '22 20:07 danielnachun

I've addressed all the feedback and TODOs except for the issue with brew audit not allowing the hardcoding of ENV["CC"] = "/usr/bin/gcc/". The version detection for gcc and make works but I'm open to suggestions for improving it.

danielnachun avatar Jul 31 '22 22:07 danielnachun

I opened https://github.com/Homebrew/brew/pull/13626 so that we can just hardcode ENV["CC"] and ENV["CXX"] to the host compiler. Once that is merged I'll update this one last time and then we should be ready to go.

danielnachun avatar Aug 01 '22 01:08 danielnachun

Aside from addressing the above feedback, I tested this on a completely clean CentOS 7 Docker image and realized it made no sense to try check if make is present when deciding if we should vendor it because we can't build a newer make if the host doesn't already have one installed. For this reason I've added back the MakeRequirement. For what I hope are rather self-evident reasons, it's not possible to compile anything without gcc and make, so it make sense that these are requirements.

That realization about make helped me figure out how to add the proper conditionals so that only the resources which are actually needed are downloaded, which makes things cleaner.

I've also disabled dependent testing because glibc has no real dependents and it doesn't make sense to test them like this.

Aside from possible syntax improvements (thanks to @carlocab for so many helpful ones already), I think this is otherwise ready to go so long as we have agreed on Ubuntu 22.04 as the target distribution.

danielnachun avatar Aug 01 '22 04:08 danielnachun

Based on the feedback I've gotten here now, I am heavily leaning towards keeping things very simple here by just unconditionally vendoring these dependencies to make sure all parts of the build are tested in CI. If we want to make this more sophisticated later we can iterate on this after the migration, but now that we have to start debottling formulae on Linux we should aim to get something merged that we know works, even if it makes the source build a bit slower. As I mentioned above users will only have to install or upgrade this once and then it won't be touched for 2 years.

danielnachun avatar Aug 01 '22 16:08 danielnachun

After thinking about this more I think have a compromise that should balance formula complexity with flexibility pretty evenly. I think we should unconditionally vendor the build dependencies other than GCC, because they are small and have a negligible impact on the build time.

As for GCC, I think we need two checks:

  1. A GccNoRpathRequirement as a dependency that will informatively fail if DevelopmentTools.locate("gcc") or HOMEBREW_GCC_PATH points to a GCC that has one or more rpath entries in its spec. The user will be told to use a different GCC or temporarily remove the rpath entries in the spec. This check needs to happen before trying to vendor any build dependencies because they will break part way through the build if an RPATH is set that picks up brewed glibc that is being built.
  2. A method for checking if the GCC version that was used to build the other build dependents is new enough to also build glibc, and vendor the newer GCC if it is too old or if we are building in CI. GCC is the only the build dependency of glibc that has a substantial build time so I suppose it would be nice for users to be able to skip it if that happen to have access to a new enough GCC.

This approach guarantees that all of our code is tested in CI while giving users the option to skip vendoring the one dependency that actually impacts build time in any meaningful way. I have a pretty good idea of how to implement these steps and will push a commit that implements this to see what we think.

danielnachun avatar Aug 02 '22 03:08 danielnachun

A method for checking if the GCC version that was used to build the other build dependents is new enough to also build glibc, and vendor the newer GCC if it is too old or if we are building in CI.

Doesn't this mean that the code that does not vendor GCC is never tested in CI?

carlocab avatar Aug 02 '22 03:08 carlocab

but now that we have to start debottling formulae on Linux we should aim to get something merged that we know works, even if it makes the source build a bit slower

This is a reasonable concern.

Doesn't this mean that the code that does not vendor GCC is never tested in CI?

This is a major concern for me. We should not be introducing code paths here that will not be tested in CI. They will get broken.

MikeMcQuaid avatar Aug 02 '22 09:08 MikeMcQuaid

There isn’t supposed to be any code that’s run only when GCC isn’t vendored (if there is please let me know). Vendoring all the dependencies means all the code I’m adding gets tested. The only thing I was potentially considering was having the option to skip the GCC vendoring outside of CI if the host GCC is new enough.

danielnachun avatar Aug 02 '22 14:08 danielnachun

but now that we have to start debottling formulae on Linux we should aim to get something merged that we know works

I've bought you some time to get this right. https://github.com/Homebrew/homebrew-core/pull/107148, https://github.com/Homebrew/brew/pull/13631.

option to skip the GCC vendoring outside of CI if the host GCC is new enough

This is a code path that isn't tested in CI.

carlocab avatar Aug 02 '22 14:08 carlocab

we should aim to get something merged that we know works

libcrypt.so.1 migration is still a concern that needs to be answered first or we risk breaking binary compatibility.

We could be ready to just hard disallow libcrypt.so.1 in all taps from now but we need to actually make that change first and ship that rather than wait until after.

Bo98 avatar Aug 02 '22 14:08 Bo98

We could be ready to just hard disallow libcrypt.so.1 in all taps from now but we need to actually make that change first and ship that rather than wait until after.

Let's do this now. Where should we set HOMEBREW_DISALLOW_LIBCRYPT1? test-bot? brew?

carlocab avatar Aug 02 '22 16:08 carlocab

We could be ready to just hard disallow libcrypt.so.1 in all taps from now but we need to actually make that change first and ship that rather than wait until after.

Let's do this now. Where should we set HOMEBREW_DISALLOW_LIBCRYPT1? test-bot? brew?

In general the plan was to initially set in homebrew-core only to ensure we're actually ready on our side and then when we're sure make it the default (removing the env) in brew for all taps.

When we change brew, we also need to make sure it doesn't affect the broken-linkage rebuild code since it's a formula issue rather than an installation issue.

Bo98 avatar Aug 02 '22 18:08 Bo98

I've pushed a commit now that greatly simplifies things. I think we've gotten a bit lost in the weeds so I'll summarize very succinctly the two goals of the commit I'm trying to add:

  1. Unconditionally vendor the necessary build dependencies so that glibc will build on older Linux systems with no user intervention required (whether as new install or an upgrade). To me this is not fundamentally different from how we vendor build dependencies for other formulae and doesn't complicate maintenance much. It may seem a little intimidating to vendor GCC, but it has a very minimal dependency tree and it is intended to be used in this manner to bootstrap building glibc: https://www.linuxfromscratch.org/~thomas/multilib/chapter05/gcc-pass1.html.

  2. Make sure that brewed GCC is not used during any part of the build process because it will fail or break the build. The primary problem is the inclusion of RPATHs which will break both the build dependencies and glibc itself. From testing I've found that other failures actually happen because brewed GCC can't find some headers/libraries in standard locations like /usr/include etc. It would be nice to fix this eventually, but I don't think we should block the merging of the PR on this issues, especially since it only requires 2 lines of code to implement the fix right now. I have added a comment explaining this above the relevant lines.

There is certainly room here for eventual improvement, but in the current state this is to me a relatively straight forward set of changes that I know from testing extensively now will work for both upgrading and new installs on all Linux environments which are not EOL. Once the dust has settled from the transition, we can revisit this for possible improvements.

We have a more serious issue with libcrypt.so removal that needs to be addressed that may require cleanup/changes outside of this formula so I think we should try to focus on that if the bootstrapping is acceptable for now.

danielnachun avatar Aug 03 '22 04:08 danielnachun

Definitely looking better but I'd really love if there's a way we can avoid the vendoring entirely in favour of requiring all this stuff to be installed from the system package manager and provide a cellar :any bottle so no-one except us should ever really need to build it from source.

@danielnachun Thoughts on this? @sjackman has 👍🏻d.

MikeMcQuaid avatar Aug 08 '22 13:08 MikeMcQuaid

Definitely looking better but I'd really love if there's a way we can avoid the vendoring entirely in favour of requiring all this stuff to be installed from the system package manager and provide a cellar :any bottle so no-one except us should ever really need to build it from source.

@danielnachun Thoughts on this? @sjackman has 👍🏻d.

If it were easy to get an :any, I would have pursued that for sure, and it's still my long term goal. But I can't really estimate how long that will take and I would rather use something I know works.

Using the system package manager isn't an option if the user isn't root, and lack of root access is also why many users use non-default prefixes.

I am still having a really hard time understanding why the vendoring we're doing here is so much worse than what we do for Perl and Python formulae, which often vendor multiple modules that build native code. We've done a great job maintaining those formulae and this case is to me even simpler, because these are build time only dependencies and we are building pure C programs that don't involve potentially brittle interfaces between scripting languages and native code.

I'd really like to know what kind of documentation/testing I could provide to make this approach seem more reasonable. There are many other non-relocatable formulae we have that seem a lot more complicated to me than this and I wonder if some of the hesitation is just because there's less familiarity with glibc than with some other packages.

danielnachun avatar Aug 08 '22 15:08 danielnachun

I am still having a really hard time understanding why the vendoring we're doing here is so much worse than what we do for Perl and Python formulae, which often vendor multiple modules that build native code.

We're not vendoring gcc and pretty much an entire build-essentials-like toolchain.

I'm still pretty unconvinced why we can't use 1) system dependencies or 2) formulae dependencies to handle this.

I'd really like to know what kind of documentation/testing I could provide to make this approach seem more reasonable. There are many other non-relocatable formulae we have that seem a lot more complicated to me than this and I wonder if some of the hesitation is just because there's less familiarity with glibc than with some other packages.

My outstanding questions:

  • why can we not rely on system dependencies here?
  • if we had to use formula dependencies here: what would we have to do?
  • why can we not use formula dependencies for things that e.g. aren't linked against or messing with RPATHs?
  • how long does the build take before and after these changes?
  • what still needs to be done after landing this PR before we can move to 22.04?

MikeMcQuaid avatar Aug 08 '22 15:08 MikeMcQuaid

We're not vendoring gcc and pretty much an entire build-essentials-like toolchain.

This is true but I guess from what I've seen now from working on this, that toolchain is actually quite simple to install, largely because everything else needs it. This is a pretty standard practice for what happens with Gentoo Prefix, for example. Importantly, it's also something that has to be done only once during either the initial setup of Homebrew, or when the CI image is upgraded to require a newer glibc, so it's not a formula that users will be installing regularly.

I'm still pretty unconvinced why we can't use 1) system dependencies or 2) formulae dependencies to handle this.

My outstanding questions:

  • why can we not rely on system dependencies here?

They can be too old or missing, and if the user has no root access, they are just stuck having to figure out how to get them installed on their own. We've previously been able to support this situation very well and I'm trying to avoid a regression in functionality. Part of the reason I'm pushing so hard to make this work is that with the implementation we already have of binary patching, a user in a non-default prefix without root access only has to grit their teeth though bootstrapping glibc (or upgrading for existing installs), and after that they can almost exclusively use bottles for everything.

  • if we had to use formula dependencies here: what would we have to do?
  • why can we not use formula dependencies for things that e.g. aren't linked against or messing with RPATHs?

I'll answer these together. It depends on the dependency:

  1. make (4.0 or newer), m4 (any version) - These are not relocatable so using a formula doesn't save from building from source. If we can guarantee that we will only use the system GCC, then a formula would work. They build very quickly and have no dependencies.
  2. bison (any version) - This is relocatable and could easily be built against [email protected], but it has to bake in the path to m4 at build time so the formula could only be used if the m4 formula was also being used. It has no dependencies other than m4 and builds extremely quickly.
  3. [email protected] (any version of Python 3 from 3.4 or newer would work) - It's not relocatable so a formula does not avoid building from source. Our existing Python 3 formulae bring in a whole slew of optional dependencies which are not needed for Python 3 to help build glibc, so we'd want some sort of minimal-python that doesn't pull in these unneeded dependencies (only zlib is needed, and is already brought in by binutils). Like the above dependencies, it builds very quickly, only adding a few minutes at most to the build.
  4. bzip2 (any version) - We could just build bzip2 with [email protected] because it is relocatable. I would be totally fine with doing this but objections were raised earlier to doing so, and like the other formulae so far it has no dependencies and has a negligible build time.
  5. gcc (6.2 or newer) - This is the more annoying one. Similar to Python 3, our existing GCC formulae are much more complex than what is needed to build glibc, so we'd want a minimal-gcc that only builds what is needed. While this could be make relocatable, I haven't figured out how to get it to work with [email protected], so we would want to force it to build from source.

Sorry for this huge wall of text but I did spend a lot of time thinking about this already! My general hesitancy in diving too much into formulae here is that there doesn't seem to be much benefit. All of these have few/no dependencies, most are not relocatable, and all but GCC have negligible build times. We also don't have to worry about updating these build dependencies either. The versions we ship in homebrew-core are far, far newer than what is needed to build glibc so that's why I just picked the version we currently have.

  • how long does the build take before and after these changes?

This is the one downside. The build time both before and after will vary a lot based on the number of cores and what else the CPU is doing but in my testing so far it's roughly 2 to 3 times longer. While this is not great, I can almost guarantee you that if you took a straw poll of users stuck in non-default prefixes without root access, they would overwhelmingly prefer that glibc just take care of the GCC dependency even if it's slower rather than throwing an error telling them to seek out their own newer copy of GCC that they have to build themselves. There is of course no impact on users in default prefixes since everything is build time only. So overall I think this will lead to a much better user experience!

  • what still needs to be done after landing this PR before we can move to 22.04?

We have to fix the issue with making sure glibc is automatically installed if the host copy is too old, being handled here: https://github.com/Homebrew/brew/pull/13577. We probably also want to finish the GCC-related changes, for which have several PRs. Nothing too crazy but I don't think this is the main blocker right now.

danielnachun avatar Aug 09 '22 02:08 danielnachun

They can be too old or missing, and if the user has no root access, they are just stuck having to figure out how to get them installed on their own. We've previously been able to support this situation very well and I'm trying to avoid a regression in functionality. Part of the reason I'm pushing so hard to make this work is that with the implementation we already have of binary patching, a user in a non-default prefix without root access only has to grit their teeth though bootstrapping glibc (or upgrading for existing installs), and after that they can almost exclusively use bottles for everything.

I guess this is what I'm struggling with. This case is solving for cases where the user has:

  • too old or missing build tools on their system
  • no root access
  • too old system glibc
  • isn't using our default prefix

these are not relocatable so using a formula doesn't save from building from source It's not relocatable so a formula does not avoid building from source. so we would want to force it to build from source.

I feel like I'm being stupid here but: glibc is also not relocatable to will need to be built from source. Why is it a problem if dependencies are also built from source?

There was something said earlier about the GCC formula being problematic because of RPATH/specs files. What I don't understand is:

  • are the RPATH/specs issues not fixable?
  • could we e.g. copy the installed GCC formula somewhere into the build path, fix the specs and use that?
  • why is this a problem for any dependency other than GCC?

We also don't have to worry about updating these build dependencies either.

This is not responsible package management. This is why we don't like upstreams vendoring dependencies, either.

The versions we ship in homebrew-core are far, far newer than what is needed to build glibc so that's why I just picked the version we currently have.

They are too new to build it or just newer than needed? Why is newer than needed a problem?

This is the one downside. The build time both before and after will vary a lot based on the number of cores and what else the CPU is doing but in my testing so far it's roughly 2 to 3 times longer.

This seems bad given that we're not building e.g. formula that are reusable in the dependency tree and if any of them have critical security vulnerabilities (see "responsible package management" above) we'll need to rebuild everything.

While this is not great, I can almost guarantee you that if you took a straw poll of users stuck in non-default prefixes without root access, they would overwhelmingly prefer that glibc

Users in this situation are running in an unsupported configuration. It feels like we're optimising for those users over maintainer experience with responsible package management practises.

MikeMcQuaid avatar Aug 09 '22 09:08 MikeMcQuaid

I figured out how to build everything from formulae!!! @MikeMcQuaid you were totally right and I should have tried this a lot sooner, as it's actually much cleaner and simpler. I was mistaken in thinking that brew would try to install brewed GCC before letting the glibc dependencies get built if the host GCC is too old, so this actually works great across all the different configurations I've tried.

In making the bootstrap-gcc formula, I also realized I made a mistake in transcribing the formula from Docker to my Mac and forgot to disable some unneeded things in GCC, and now the build time has been massively reduced to only about 5-6 minutes in my system. Although things will obviously be slower in CI due to fewer cores etc., this now means that all of the build dependencies will only add a neglible amount of build time to glibc that users will hardly notice.

Assuming everything goes well in CI and there aren't too many syntax issues with the new formulae, I think this gets us to where we wanted to be in terms of proper package maintenance.

danielnachun avatar Aug 10 '22 05:08 danielnachun

I guess this is what I'm struggling with. This case is solving for cases where the user has:

  • too old or missing build tools on their system

  • no root access

  • too old system glibc

  • isn't using our default prefix

There was something said earlier about the GCC formula being problematic because of RPATH/specs files. What I don't understand is:

  • are the RPATH/specs issues not fixable?

  • could we e.g. copy the installed GCC formula somewhere into the build path, fix the specs and use that?

  • why is this a problem for any dependency other than GCC?

This is not responsible package management. This is why we don't like upstreams vendoring dependencies, either.

Users in this situation are running in an unsupported configuration. It feels like we're optimising for those users over maintainer experience with responsible package management practises.

I agree with all of this. In particular, I am concerned about the security implications of:

  1. packaging old versions of the bootstrap dependencies
  2. forcing these old versions onto all users who will use Homebrew glibc

I really think we should start pushing the provisioning of the bootstrap dependencies toward the user when the system version is too old.

Since we already have nearly all the steps they need to follow written down in various formulae, turning these formulae into documentation that relevant users can follow if they need to bootstrap for themselves should be doable.

carlocab avatar Aug 10 '22 08:08 carlocab

I really think we should start pushing the provisioning of the bootstrap dependencies toward the user when the system version is too old.

This is what I proposed in my nightly builds PR opened in Homebrew/brew some time ago (for git, tar and curl); and @MikeMcQuaid thought this was too complex for our users and we should try to automagically bootstrap things. Also, if we ask the users to do everything: why do we maintain portable ruby?

I personnaly think the approach here is sane as the user does not have to think much about the details: it makes it easy to install brew, and we are in full control of what/how we install things.

iMichka avatar Aug 10 '22 08:08 iMichka

I feel like I'm being stupid here but: glibc is also not relocatable to will need to be built from source. Why is it a problem if dependencies are also built from source?

There was something said earlier about the GCC formula being problematic because of RPATH/specs files. What I don't understand is:

  • are the RPATH/specs issues not fixable?
  • could we e.g. copy the installed GCC formula somewhere into the build path, fix the specs and use that?
  • why is this a problem for any dependency other than GCC?

@danielnachun please answer the questions above too, thanks.

I figured out how to build everything from formulae!!

@danielnachun Sorry, to be clear, my intention was we use the existing e.g. binutils etc. formulae, not create new ones for each.

It's not clear to me why we need e.g. gmp 6.1 rather than gmp 6.2 to build glibc, can you explain?

If this is a hard, unavoidable requirement: let's call these formulae [email protected] etc. and then we can make them useful by themselves and track e.g. gmp 6.1.0, 6.1.1, etc. like normal versioned formulae.

Are any of these cellar :any?

I was mistaken in thinking that brew would try to install brewed GCC before letting the glibc dependencies get built if the host GCC is too old, so this actually works great across all the different configurations I've tried.

If this ever happens: this feels like another thing that should be handled in https://github.com/Homebrew/brew/pull/13577 for both glibc and gcc and make sure it's working as expected after that.

Assuming everything goes well in CI and there aren't too many syntax issues with the new formulae, I think this gets us to where we wanted to be in terms of proper package maintenance.

Unfortunately: not yet, no. To save you wasting your and CI time: I'd suggest that we get you, me @carlocab at least on the same page with what's an acceptable solution for all of us before pushing more changes.

MikeMcQuaid avatar Aug 10 '22 13:08 MikeMcQuaid

This is what I proposed in my nightly builds PR opened in Homebrew/brew some time ago (for git, tar and curl); and @MikeMcQuaid thought this was too complex for our users and we should try to automagically bootstrap things.

@iMichka My blocking objections were more:

  • who will fix this job when it fails?
  • why all these OS versions?
  • we need to not build all these dependencies from source every time (e.g. using Anaconda if necessary) and, if we can figure out a solution for our CI, it might be nice for our users, too
  • why are we spending so much time and effort supporting very old distros

Also, if we ask the users to do everything: why do we maintain portable ruby?

  1. because it's needed on macOS and macOS is a very different beast to Linux terms of how much we can consider provided by the system
  2. we're pouring enormous amounts of time and effort to support small numbers of users on incredibly old Linux distros in unsupported configurations and we don't do this on macOS
  3. because we know macOS Ruby is going away at some point in the future
  4. because macOS has no system package manager, unlike Linux
  5. because there's more macOS Homebrew users
  6. because macOS Homebrew users are, in my opinion, less technical on average

MikeMcQuaid avatar Aug 10 '22 13:08 MikeMcQuaid

If the concern about reusing existing formulae is that they are built against a glibc that is too new, use pour_bottle? to restrict bottle usage to systems where the bottles will work.

This would allow us to easily reuse the bzip2 formula, for example.

carlocab avatar Aug 10 '22 17:08 carlocab

  • are the RPATH/specs issues not fixable?

The are two RPATH/specs issues. In the build dependencies, the problem is that both our superenv and brewed GCC spec add RPATHs that point to brewed glibc, and as glibc is getting built it starts to populate the glibc cellar with files that will get used instead of the host glibc. This eventually results in the build dependency binaries dynamically linking to a mix of libraries from the host and brewed glibc which breaks them.

When building glibc itself, it will break if any RPATH is set by the superenv or the brewed GCC spec.

The simplest solution is to force the build dependencies to be built with the host compiler, bypassing both the compiler shims and (if upgrading) any existing brewed GCC installations.

We may be able to fix most of this by setting something up in brew where, if building glibc or its build dependencies, we check if #{ENV.cc} --print-file-name=specs.orig exists and if it does use -specs=#{ENV.cc} --print-file-name=specs.orig as an additional argument. We’d also need to add something in the compiler shim that skips adding any RPATHs or other ldflags if building glibc or its build dependencies. I haven’t tested this yet was but was planning to do so very soon.

Regardless we still need to build a copy of GCC because the host GCC may be too old, but that’s unrelated to the RPATH issue.

  • could we e.g. copy the installed GCC formula somewhere into the build path, fix the specs and use that?

We can’t install GCC from a bottle because it needs brewed glibc to work, and we can’t build it with [email protected] because while compiling it builds binaries that will link to the host libstdc++, which links to the host glibc and breaks the binary. The only remaining option would be to force building GCC from source, but as I mentioned above our GCC formula is much more complicated and slow to build than what is needed.

  • why is this a problem for any dependency other than GCC?

I explained this in the answer to the first question.

danielnachun avatar Aug 12 '22 06:08 danielnachun