Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cctools: 973.0.1 -> 1010.6 #307880

Merged
merged 24 commits into from
Jul 17, 2024
Merged

cctools: 973.0.1 -> 1010.6 #307880

merged 24 commits into from
Jul 17, 2024

Conversation

reckenrode
Copy link
Contributor

@reckenrode reckenrode commented Apr 30, 2024

Description of changes

This PR updates cctools and ld64. It also fixes related breakage. It is currently set to draft until 24.05 is released. I will be rebasing weekly against staging, resolving any merge conflicts then. Before updating the ld64 branch, I build my configs and the Darwin channel blockers to confirm no regressions.

The following notes are copied from https://discourse.nixos.org/t/darwin-updates-news/42249/10.

Packaging Changes

  • cctools, ld64, and libtapi are now built from Apple’s OSS distributions repo instead of the cctools-port and apple-libtapi repos.
  • These versions (cctools 1010.6, ld64 951.9, libtapi 1500.0.12.3) correspond to the versions shipped with Xcode 15. cctools and ld64 are current as of Xcode 15.3. Packages should no longer have to patch around missing flags or feature support.
  • Restoring Linux support is a WIP. I have made some changes to use non-private and non-portable APIs, but I am currently focused on getting Darwin updates first.
  • The packages have been moved to the by-name hierarchy. Aliases are provided to the old names, but there are some breaking changes (see below).
  • cctools is now only cctools. This is technically a breaking change (see below). ld64 has been moved to its own, separate package.
  • darwin.binutils is now the package that defines the mix of cctools and LLVM tools. It has been update with additional tools. See below for the breakdown of what it contains.
  • The build system has been replaced with Meson. I did this because dealing with xcbuild stinks, and these packages eventually need to support Linux for cross-compilation.
  • corecrypto and CommonCrypto hashing APIs are reimplemented using OpenSSL on both Darwin (and eventually) Linux. cctools-port only does this on non-Darwin platforms.
  • libtapi has been split into separate out and lib outputs. Most packages only need libtapi.dylib, which is ~500 KiB compared to ~30 MiB for the tapi binary.
  • libtapi is linked against zlib. I don’t know what it uses zlib to do, but the upstream libtapi is also linked against zlib, and I want to match what upstream is doing.

Note: ld-prime is will not be packaged because it is not currently included in the source releases. While I think it’s unlikely, ld-prime will be added separately as a new package should the source be released.

New Features

  • LTO support. With this update, LTO works. I had to patch ld64 to look for libLTO.dylib in the store and clang to pass the correct path (see llvmPackages_{12,13,14,15,16,17,18,git}.clang: fix libLTO.dylib path #304350). I bootstrap ld64 and link it with itself with LTO enabled to make sure that LTO actually works.
  • Code directory support. cctools is built with libcodedirectory support, which allows strip and install_name_tool to identify linker-created signatures and update them automatically. This removes the need for postLinkSignHook and actually makes it harmful to continue using it by default (because it prevents automatic signature updates by replacing them with a non-linker-created signature).

Breaking Changes

  • ld64 and cctools use GCD (libdispatch) for parallelism. This should improve performance, but it technically ups the required macOS version to 10.14. The APIs it uses are present under different names in 10.12, so I have attempted to patch around them. It builds with the 10.12 SDK, but it will need testing to confirm the tools actually work. This was the driver of updating the default SDK on x86_64-darwin for 24.11.
  • Apple removed support for nested static archives from ld64. This happened with the release of Xcode 14, so it has been out in the ecosystem for a few years. Hopefully packages have adapted by now. For example, Kyua adds libutils.a to libcli.a using libcli_a_LIBADD in automake. This will fail to link with ld64 951.9.
  • ld64 is more picking about command-line arguments. Passing -rpath when merging Mach-O object files fails.
  • GNU as has been moved to the cctools^gas output. -q and -Q flags are supported to control whether it calls GNU as or the clang assembler (matching the upstream behavior of as).
  • cctools only provides binaries from cctools. ld64 is a separate package now.
  • darwin.cctools-apple, darwin.cctools-port, and darwin.cctools-llvm are replaced by just cctools. cctools-llvm is an alias to darwin.bintools.
  • The old names can’t be used in nixpkgs because aliases are disabled when ofborg eval is run. The PR updating the tools will include changes for all packages using the old names. (Updates for LTO will be done in a separate PR or PRs.)
  • Use of postLinkSignHook has been removed from bintools-wrapper. Because it removes linker-created signatures, it breaks the automatic updating of signatures by strip and install_name_tool. Unless you’re manually invoking codesign, you shouldn’t be affected. install_name_tool will do the right thing by default.
  • strip and install_name_tool are no longer wrapped with sigtool. If you are modifying linker-signed binaries, which should be the typical case, they will update the signatures automatically. If you are manually invoking codesign, you will need to update the signatures manually after running strip or install_name_tool.

stdenv updates

  • Stage 2 has been collapsed from two parts into one stage. The source-based CF is not coming back. It adds a lot of complexity to the bootstrap.
  • As noted in breaking changes, the Darwin stdenv no longer provides bintools using postLinkSignHook. Once the bootstrap tools are updated with these releases, it may be possible to drop sigtool completely from the bootstrap. Until that happens, early stages manually implement postLinkSignHook because the bootstrap tools ld64 does not appear capable of signing binaries on its own.
  • As part of this update, I have to update the stdenv to use the new paths.
  • The overall stdenv size is down by ~20 MiB due to dropping tapi from the closure. It also drops signtool and signingUtils, but those binaries are small.
  • curl and GNU binutils throw when used during the bootstrap. curl should never be used during the bootstrap (to allow it to be updated without triggering a whole rebuild of Darwin). GNU binutils generally shouldn’t be used on Darwin (e.g., Rust 1.77 will clash harder with GNU binutils on Darwin Nix #299606), so the bootstrap shouldn’t need to use it.

darwin.bintools changes

darwin.bintools changes

  • c++filter is no longer linked from GNU binutils. It is linked from LLVM. A handful of packages are linked from cctools because LLVM does not provided drop-in replacements for them. The lists of tools are exported as attributes on darwin.bintools (llvm_cmds and cctools_cmds respectively). All binaries are symlinked to their traditional names (e.g., llvm-strip is symlinked to strip).
    • LLVM tools: addr2line, ar, c++filt, dwarfdump, dsymutil, lipo, install-name-tool, nm, objcopy, objdump, otool, size, strings, strip
    • cctools tools: codesign_allocate, gprof, ranlib (and ld from ld64)
  • Darwin is still isCCTools and not isLLVM because it does not use lld by default. Maybe that could change with lld 18, but I’m doubtful.

Resolved Issues

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.05 Release Notes (or backporting 23.05 and 23.11 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/darwin-updates-news/42249/12

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/need-help-from-darwin-users-syntax-errors-in-library-frameworks-foundation-framework-headers/30467/17

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/darwin-ld-symbol-s-not-found-for-architecture-arm64/46177/1

@reckenrode
Copy link
Contributor Author

Latest push is up until right before the Darwin cross work.

@reckenrode
Copy link
Contributor Author

I’m paring down this PR to reduce the chance of conflicts and to make it easier to review in aggregate. Cherry-picking commits is going to take too much time, and sometimes they depend on other commits.

@reckenrode
Copy link
Contributor Author

The following will be done in separate PRs:

  • libunwind upgrade;
  • adding cctools to darwin-aliases.nix; and
  • enable LTO in packages that have it disabled on Darwin.

@reckenrode
Copy link
Contributor Author

The only thing I have left to do before marking this ready is fix the AvailabilityVersions package to patch out newer macros on SDKs 10.12, 10.13, 10.14, and 10.15. Some packages (like Git and SDL2) check for the presence of certain macros regardless of their value to check SDK version. That feels like a misuse of the macros, but I don’t want to break anything with the switch.

When the linker signs a Mach-O binary, it sets a flag in the signature’s code directory indicating that the signature was generated by a linker. Tools such as `strip` and `install_name_tool` read this flag and will
update ad hoc signatures after they perform their modifications.

The updated l64 supports signing binaries automatically. Both the updated cctools and LLVM will check for the linker-signed flag and resign binaries they modify automatically when it’s present. Given that, use of postLinkSignHook is unnecessary and potentially harmful.

In particular, if the hook is used and an unwrapped `strip` or `install_name_tool` is on the user’s path, they will not automatically update an ad hoc signature. Instead, they will issue a warning and create a binary with a broken signature.

It is more robust to let the tools handled this since the only time a signature would not be linker-signed is when the user is manually invoking `codesign` (or another tool such as `sigtool` or `rcodesign`), which by nature of the invocation updates the signature to a valid  one.

Since `strip` no longer needs to be wrapped for code-signing, binutils-wrapper now uses the GNU strip wrapper on Darwin.

Fixes NixOS#208951.
# GHC needs install_name_tool on all darwin platforms. On aarch64-darwin it is
# part of the bintools wrapper (due to codesigning requirements), but not on
# x86_64-darwin. We decide based on target platform to have consistent tools
# across all GHC stages.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment needs to be rephrased and replace the one for strip below. (In all touched files.) Having the information in a comment is better than piecing it together from a deleted comment and the commit message :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What’s the context of the comment for strip? Darwin now uses the default wrapper, which just passes --enable-deterministic-archives. Should it not do that with GHC, or should it use the wrapper unconditionally?

# TODO(@sternenseemann): also use wrapper if linker == "bfd" or "gold"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the comments.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to use the wrapper if possible, but unfortunately it is kind of difficult to know when we can use it. I think the TODO is about the fact that you can sort of bodge detect GNU binutils using linker == "gold" || linker == "bfd" which means there's a wrapper (like on aarch64-darwin and now x86_64-darwin). IIRC there's no wrapper if bintools come from LLVM, so that's a case you'd need to guard against.

I think I never really attempted to improve it since the wrapper is inconsequential for GHC itself and I was dissatisfied with the detectability. I think this mess ought to be cleaned up in a different way, i.e. just symlinking from the wrapper to the unwrapped derivation if an unwrapped bintool is available.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I take it using bintools.isGNU is unreliable? If not, I can update the GHC files to check cc.bintools.isGNU || stdenv.targetPlatform.isDarwin. Otherwise, I’d like to keep the changes just to Darwin to avoid increasing the scope of this PR more.

(Also, please let me know if any more revisions are needed to the comments I added to GHC regarding install_name_tool and strip.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know whether it is reliable or not. I think it wasn't a thing back then (would need to check). But agreed w.r.t. scope.

- Unconditionally get `install_name_tool` from cc.bintools.bintools since it is no longer wrapped; and
- Use the `strip` wrapper on both Darwin architectures. It’s the default one, and it’s the same between both.
@toonn
Copy link
Contributor

toonn commented Jul 14, 2024

I've kicked off a build on 10.13 hardware to see if the changes to keep <10.14 working are alright, not sure if we want to wait for that to complete though.

@reckenrode
Copy link
Contributor Author

I've kicked off a build on 10.13 hardware to see if the changes to keep <10.14 working are alright, not sure if we want to wait for that to complete though.

It should work, so I’d be surprised if it didn’t. Anyway, I’m currently waiting on approvals from you and @sternenseemann (or at least confirmation/feedback re: the revised comments).

@sternenseemann
Copy link
Member

(or at least confirmation/feedback re: the revised comments).

Looks good.

Copy link
Contributor

@toonn toonn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, like I said no need to block on the build.
Had a couple failures related to the LLVM manpages but I haven't been able to check whether it's not just running out of disk space or such. So let's just go ahead with the merge already.

@toonn toonn merged commit c3c5870 into NixOS:staging Jul 17, 2024
22 checks passed
@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/darwin-updates-news/42249/15

@reckenrode reckenrode mentioned this pull request Jul 18, 2024
13 tasks
reckenrode added a commit to reckenrode/node2nix that referenced this pull request Jul 18, 2024
cctools was updated and migrated to the `by-name` hierarchy in nixpkgs,
which moves it to the top-level. It is also being added to
`darwin-aliases.nix`, which will make the old name unavailable for use
in nixpkgs. This change preferentially uses the new name while falling
back to the old one for out-of-tree users.

Relevant nixpkgs PRs:
- NixOS/nixpkgs#307880
- NixOS/nixpkgs#328077
@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/breaking-changes-announcement-for-unstable/17574/57

@reckenrode reckenrode deleted the ld64 branch July 20, 2024 16:26
al3xtjames pushed a commit to al3xtjames/nixpkgs that referenced this pull request Jul 22, 2024
reckenrode added a commit to reckenrode/nixpkgs that referenced this pull request Jul 28, 2024
After NixOS#307880 was merged, ld64 is 951.9, which is the version shipped with Xcode 15.4. It is new enough to support all of the linker flags used by the upstream bindist.

The only remaining blockers to bootstrapping with the bindist on Darwin is the GHC issue that tries to use `ar -L`, which creates archives that cannot be linked by ld64. Overriding the setting in the bindist suppresses that behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants