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

Add support for bottling Portable Ruby for ARM64 Linux #19111

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Library/Homebrew/extend/ENV/super.rb
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ def determine_optflags
odebug "Building a bottle for custom architecture (#{effective_arch})..."
Hardware::CPU.arch_flag(effective_arch)
end
alias generic_determine_optflags determine_optflags

sig { returns(String) }
def determine_cccfg
Expand Down
19 changes: 17 additions & 2 deletions Library/Homebrew/extend/os/linux/extend/ENV/super.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,30 @@ def homebrew_extra_paths

def homebrew_extra_isystem_paths
paths = []
# Add paths for GCC headers when building against [email protected] because we have to use -nostdinc.
if deps.any? { |d| d.name == "[email protected]" }
# Add paths for GCC headers when building against [email protected] or [email protected]
Copy link
Member

Choose a reason for hiding this comment

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

Maybe this should be all versioned glibcs (glibc@.+) rather than hardcoding a list here?

# because we have to use -nostdinc.
versioned_glibcs = ["[email protected]", "[email protected]"]
if deps.any? { |d| versioned_glibcs.include?(d.name) }
gcc_include_dir = Utils.safe_popen_read(cc, "--print-file-name=include").chomp
gcc_include_fixed_dir = Utils.safe_popen_read(cc, "--print-file-name=include-fixed").chomp
paths << gcc_include_dir << gcc_include_fixed_dir
end
paths
end

sig { returns(String) }
def determine_optflags
if effective_arch == :armv8 &&
compiler.match?(GNU_GCC_REGEXP) &&
DevelopmentTools.gcc_version(compiler.to_s) >= "9.3.1"
# Out-of-line atomics are not supported out-of-the-box on all systems.
# https://learn.arm.com/learning-paths/servers-and-cloud-computing/lse/intro/
"#{generic_determine_optflags} -mno-outline-atomics"
Copy link
Member

Choose a reason for hiding this comment

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

Given we already use -march=armv8-a, is this for scenarios with a shared libgcc is used?
Is this also relevant for anything outside of Portable Ruby?

Copy link
Member Author

@ZhongRuoyu ZhongRuoyu Jan 17, 2025

Choose a reason for hiding this comment

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

This is not related to shared libgcc AFAIK; it's relevant for building all bottles with GCC >= 9.3.1 (where out-of-line atomics are enabled by default and not controlled by -march=armv8-a). I recall not being able to run binaries from a bottle built in standard CI environment (GCC 11) out-of-the-box on Ubuntu 18.04 (requires an extra package libc6-lse to be installed).

Copy link
Member

@Bo98 Bo98 Jan 17, 2025

Choose a reason for hiding this comment

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

That's interesting given https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/making-the-most-of-the-arm-architecture-in-gcc-10 implies it can determine it at runtime using a libgcc call of __aarch64_cas4_relax.

Is it elsewhere on 18.04 and not being linked? Missing from our GCC 11 build like https://bugs.gentoo.org/868018?

Copy link
Member Author

@ZhongRuoyu ZhongRuoyu Jan 17, 2025

Choose a reason for hiding this comment

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

Mmm, will need to check this. Away from keyboard at the moment but will do tonight in the weekend (sorry things got in the way).

Copy link
Member

Choose a reason for hiding this comment

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

Unless we need this to build Portable Ruby on the GitHub runner: I'd prefer if we didn't have this. Feels like something that should be formula specific.

else
generic_determine_optflags
end
end

def determine_rpath_paths(formula)
PATH.new(
*formula&.lib,
Expand Down
14 changes: 8 additions & 6 deletions Library/Homebrew/shims/super/cc
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,9 @@ class Cmd
def cppflags
args = []
args += path_flags("-isystem", isystem_paths) + path_flags("-I", include_paths)
# Add -nostdinc when building against [email protected] to avoid mixing system and brewed glibc headers.
args << "-nostdinc" if @deps.include?("[email protected]")
# Add -nostdinc when building against [email protected] or [email protected] to avoid
# mixing system and brewed glibc headers.
args << "-nostdinc" if (@deps & ["[email protected]", "[email protected]"]).any?
ZhongRuoyu marked this conversation as resolved.
Show resolved Hide resolved
# Ideally this would be -ffile-prefix-map, but that requires a minimum of GCC 8, LLVM Clang 10 or Apple Clang 12
# and detecting the version dynamically based on what `HOMEBREW_CC` may have been rewritten to point to is awkward
args << "-fdebug-prefix-map=#{formula_buildpath}=." if formula_buildpath && !debug_symbols?
Expand All @@ -353,19 +354,20 @@ class Cmd
end

def ldflags_linux(args)
versioned_glibc_dep = (@deps & ["[email protected]", "[email protected]"]).first
Copy link
Member

Choose a reason for hiding this comment

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

And even more: same as above. Given how many times we're hardcoding these versions definitely feel like we should be using e.g. a consistent constant and a regex.

unless mode == :ld
wl = "-Wl,"
if @deps.include?("[email protected]")
args << "-B#{@opt}/[email protected]/lib"
if versioned_glibc_dep
args << "-B#{@opt}/#{versioned_glibc_dep}/lib"
else
args << "-B#{@opt}/glibc/lib"
end
end
args += rpath_flags("#{wl}-rpath=", rpath_paths)
args += ["#{wl}--dynamic-linker=#{dynamic_linker_path}"] if dynamic_linker_path
# Use -rpath-link to make sure linker uses [email protected] rather than the system glibc for indirect
# Use -rpath-link to make sure linker uses [email protected] or [email protected] rather than the system glibc for indirect
# dependencies because -L will only handle direct dependencies.
args << "#{wl}-rpath-link=#{@opt}/[email protected]/lib" if @deps.include?("[email protected]")
args << "#{wl}-rpath-link=#{@opt}/#{versioned_glibc_dep}/lib" if versioned_glibc_dep
args
end

Expand Down
Loading