Merge pull request #13608 from lukaso/debug-symbols

Support for `--debug-symbols` for macos
This commit is contained in:
Mike McQuaid 2022-08-12 10:05:32 +01:00 committed by GitHub
commit a73a1a665e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 182 additions and 63 deletions

View File

@ -21,6 +21,7 @@ Metrics/BlockLength:
# TODO: extract more of the bottling logic
- "dev-cmd/bottle.rb"
- "test/**/*"
- "cmd/install.rb"
Metrics/BlockNesting:
Max: 5
Metrics/ClassLength:

View File

@ -83,6 +83,7 @@ class Build
cc: args.cc,
build_bottle: args.build_bottle?,
bottle_arch: args.bottle_arch,
debug_symbols: args.debug_symbols?,
)
reqs.each do |req|
req.modify_build_environment(
@ -96,6 +97,7 @@ class Build
cc: args.cc,
build_bottle: args.build_bottle?,
bottle_arch: args.bottle_arch,
debug_symbols: args.debug_symbols?,
)
reqs.each do |req|
req.modify_build_environment(
@ -129,6 +131,7 @@ class Build
formula.brew(
fetch: false,
keep_tmp: args.keep_tmp?,
debug_symbols: args.debug_symbols?,
interactive: args.interactive?,
) do
with_env(

View File

@ -87,6 +87,9 @@ module Homebrew
sig { returns(T::Boolean) }
def keep_tmp?; end
sig { returns(T::Boolean) }
def debug_symbols?; end
sig { returns(T::Boolean) }
def overwrite?; end

View File

@ -91,6 +91,10 @@ module Homebrew
[:switch, "--keep-tmp", {
description: "Retain the temporary files created during installation.",
}],
[:switch, "--debug-symbols", {
depends_on: "--build-from-source",
description: "Generate debug symbols on build. Source will be retained in a cache directory. ",
}],
[:switch, "--build-bottle", {
description: "Prepare the formula for eventual bottling during installation, skipping any " \
"post-install steps.",
@ -232,6 +236,7 @@ module Homebrew
git: args.git?,
interactive: args.interactive?,
keep_tmp: args.keep_tmp?,
debug_symbols: args.debug_symbols?,
force: args.force?,
overwrite: args.overwrite?,
debug: args.debug?,
@ -247,6 +252,7 @@ module Homebrew
build_from_source_formulae: args.build_from_source_formulae,
interactive: args.interactive?,
keep_tmp: args.keep_tmp?,
debug_symbols: args.debug_symbols?,
force: args.force?,
debug: args.debug?,
quiet: args.quiet?,

View File

@ -57,6 +57,10 @@ module Homebrew
[:switch, "--keep-tmp", {
description: "Retain the temporary files created during installation.",
}],
[:switch, "--debug-symbols", {
depends_on: "--build-from-source",
description: "Generate debug symbols on build. Source will be retained in a cache directory. ",
}],
[:switch, "--display-times", {
env: :display_install_times,
description: "Print install times for each formula at the end of the run.",
@ -115,6 +119,7 @@ module Homebrew
build_from_source_formulae: args.build_from_source_formulae,
interactive: args.interactive?,
keep_tmp: args.keep_tmp?,
debug_symbols: args.debug_symbols?,
force: args.force?,
debug: args.debug?,
quiet: args.quiet?,
@ -132,6 +137,7 @@ module Homebrew
build_from_source_formulae: args.build_from_source_formulae,
interactive: args.interactive?,
keep_tmp: args.keep_tmp?,
debug_symbols: args.debug_symbols?,
force: args.force?,
debug: args.debug?,
quiet: args.quiet?,

View File

@ -68,6 +68,10 @@ module Homebrew
[:switch, "--keep-tmp", {
description: "Retain the temporary files created during installation.",
}],
[:switch, "--debug-symbols", {
depends_on: "--build-from-source",
description: "Generate debug symbols on build. Source will be retained in a cache directory. ",
}],
[:switch, "--display-times", {
env: :display_install_times,
description: "Print install times for each package at the end of the run.",
@ -187,6 +191,7 @@ module Homebrew
build_from_source_formulae: args.build_from_source_formulae,
interactive: args.interactive?,
keep_tmp: args.keep_tmp?,
debug_symbols: args.debug_symbols?,
force: args.force?,
debug: args.debug?,
quiet: args.quiet?,
@ -202,6 +207,7 @@ module Homebrew
build_from_source_formulae: args.build_from_source_formulae,
interactive: args.interactive?,
keep_tmp: args.keep_tmp?,
debug_symbols: args.debug_symbols?,
force: args.force?,
debug: args.debug?,
quiet: args.quiet?,

View File

@ -37,15 +37,17 @@ module EnvActivation
cc: T.nilable(String),
build_bottle: T::Boolean,
bottle_arch: T.nilable(String),
debug_symbols: T.nilable(T::Boolean),
_block: T.proc.returns(T.untyped),
).returns(T.untyped)
}
def with_build_environment(env: nil, cc: nil, build_bottle: false, bottle_arch: nil, &_block)
def with_build_environment(env: nil, cc: nil, build_bottle: false, bottle_arch: nil, debug_symbols: false, &_block)
old_env = to_hash.dup
tmp_env = to_hash.dup.extend(EnvActivation)
T.cast(tmp_env, EnvActivation).activate_extensions!(env: env)
T.cast(tmp_env, T.any(Superenv, Stdenv))
.setup_build_environment(cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch)
.setup_build_environment(cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch,
debug_symbols: debug_symbols)
replace(tmp_env)
begin

View File

@ -40,13 +40,16 @@ module SharedEnvExtension
build_bottle: T.nilable(T::Boolean),
bottle_arch: T.nilable(String),
testing_formula: T::Boolean,
debug_symbols: T.nilable(T::Boolean),
).void
}
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
@formula = formula
@cc = cc
@build_bottle = build_bottle
@bottle_arch = bottle_arch
@debug_symbols = debug_symbols
reset
end
private :setup_build_environment

View File

@ -21,9 +21,11 @@ module Stdenv
build_bottle: T.nilable(T::Boolean),
bottle_arch: T.nilable(String),
testing_formula: T::Boolean,
debug_symbols: T.nilable(T::Boolean),
).void
}
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
super
self["HOMEBREW_ENV"] = "std"

View File

@ -55,9 +55,11 @@ module Superenv
build_bottle: T.nilable(T::Boolean),
bottle_arch: T.nilable(String),
testing_formula: T::Boolean,
debug_symbols: T.nilable(T::Boolean),
).void
}
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
super
send(compiler)
@ -87,6 +89,8 @@ module Superenv
self["HOMEBREW_DEPENDENCIES"] = determine_dependencies
self["HOMEBREW_FORMULA_PREFIX"] = @formula.prefix unless @formula.nil?
set_debug_symbols if debug_symbols
# The HOMEBREW_CCCFG ENV variable is used by the ENV/cc tool to control
# compiler flag stripping. It consists of a string of characters which act
# as flags. Some of these flags are mutually exclusive.
@ -100,6 +104,7 @@ module Superenv
# d - Don't strip -march=<target>. Use only in formulae that
# have runtime detection of CPU features.
# w - Pass -no_weak_imports to the linker
# D - Generate debugging information
#
# These flags will also be present:
# a - apply fix for apr-1-config path
@ -331,6 +336,11 @@ module Superenv
append_to_cccfg "g" if compiler == :clang
end
sig { void }
def set_debug_symbols
append_to_cccfg "D"
end
# @private
sig { void }
def refurbish_args

View File

@ -2,11 +2,10 @@
# frozen_string_literal: true
module Stdenv
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
generic_setup_build_environment(
formula: formula, cc: cc, build_bottle: build_bottle,
bottle_arch: bottle_arch, testing_formula: testing_formula
)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
generic_setup_build_environment(formula: formula, cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch,
testing_formula: testing_formula, debug_symbols: debug_symbols)
prepend_path "CPATH", HOMEBREW_PREFIX/"include"
prepend_path "LIBRARY_PATH", HOMEBREW_PREFIX/"lib"

View File

@ -15,11 +15,10 @@ module Superenv
end
# @private
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
generic_setup_build_environment(
formula: formula, cc: cc, build_bottle: build_bottle,
bottle_arch: bottle_arch, testing_formula: testing_formula
)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
generic_setup_build_environment(formula: formula, cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch,
testing_formula: testing_formula, debug_symbols: debug_symbols)
self["HOMEBREW_OPTIMIZATION_LEVEL"] = "O2"
self["HOMEBREW_DYNAMIC_LINKER"] = determine_dynamic_linker_path
self["HOMEBREW_RPATH_PATHS"] = determine_rpath_paths(@formula)

View File

@ -4,11 +4,11 @@
module SharedEnvExtension
extend T::Sig
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
generic_shared_setup_build_environment(
formula: formula, cc: cc, build_bottle: build_bottle,
bottle_arch: bottle_arch, testing_formula: testing_formula
)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
generic_shared_setup_build_environment(formula: formula, cc: cc, build_bottle: build_bottle,
bottle_arch: bottle_arch, testing_formula: testing_formula,
debug_symbols: debug_symbols)
# Normalise the system Perl version used, where multiple may be available
self["VERSIONER_PERL_VERSION"] = MacOS.preferred_perl_version

View File

@ -10,11 +10,10 @@ module Stdenv
["#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}"]
end
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
generic_setup_build_environment(
formula: formula, cc: cc, build_bottle: build_bottle,
bottle_arch: bottle_arch, testing_formula: testing_formula
)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
generic_setup_build_environment(formula: formula, cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch,
testing_formula: testing_formula, debug_symbols: debug_symbols)
append "LDFLAGS", "-Wl,-headerpad_max_install_names"

View File

@ -85,7 +85,8 @@ module Superenv
end
# @private
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false)
def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil, testing_formula: false,
debug_symbols: false)
sdk = formula ? MacOS.sdk_for_formula(formula) : MacOS.sdk
is_xcode_sdk = sdk&.source == :xcode
@ -100,10 +101,8 @@ module Superenv
MacOS::CLT::PKG_PATH
end
generic_setup_build_environment(
formula: formula, cc: cc, build_bottle: build_bottle,
bottle_arch: bottle_arch, testing_formula: testing_formula
)
generic_setup_build_environment(formula: formula, cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch,
testing_formula: testing_formula, debug_symbols: debug_symbols)
# Filter out symbols known not to be defined since GNU Autotools can't
# reliably figure this out with Xcode 8 and above.

View File

@ -62,4 +62,19 @@ class Keg
#{result.stderr}
EOS
end
def prepare_debug_symbols
binary_executable_or_library_files.each do |file|
odebug "Extracting symbols #{file}"
result = system_command("dsymutil", args: [file], print_stderr: false)
next if result.success?
# If it fails again, error out
ofail <<~EOS
Failed to extract symbols from #{file}:
#{result.stderr}
EOS
end
end
end

View File

@ -1270,11 +1270,11 @@ class Formula
# Yields |self,staging| with current working directory set to the uncompressed tarball
# where staging is a {Mktemp} staging context.
# @private
def brew(fetch: true, keep_tmp: false, interactive: false)
def brew(fetch: true, keep_tmp: false, debug_symbols: false, interactive: false)
@prefix_returns_versioned_prefix = true
active_spec.fetch if fetch
stage(interactive: interactive) do |staging|
staging.retain! if keep_tmp
stage(interactive: interactive, debug_symbols: debug_symbols) do |staging|
staging.retain! if keep_tmp || debug_symbols
prepare_patches
fetch_patches if fetch
@ -2529,8 +2529,8 @@ class Formula
}
end
def stage(interactive: false)
active_spec.stage do |staging|
def stage(interactive: false, debug_symbols: false)
active_spec.stage(debug_symbols: debug_symbols) do |staging|
@source_modified_time = active_spec.source_modified_time
@buildpath = Pathname.pwd
env_home = buildpath/".brew_home"

View File

@ -39,6 +39,7 @@ class FormulaInstaller
attr_predicate :installed_as_dependency?, :installed_on_request?
attr_predicate :show_summary_heading?, :show_header?
attr_predicate :force_bottle?, :ignore_deps?, :only_deps?, :interactive?, :git?, :force?, :overwrite?, :keep_tmp?
attr_predicate :debug_symbols?
attr_predicate :verbose?, :debug?, :quiet?
def initialize(
@ -58,6 +59,7 @@ class FormulaInstaller
git: false,
interactive: false,
keep_tmp: false,
debug_symbols: false,
cc: nil,
options: Options.new,
force: false,
@ -71,6 +73,7 @@ class FormulaInstaller
@force = force
@overwrite = overwrite
@keep_tmp = keep_tmp
@debug_symbols = debug_symbols
@link_keg = !formula.keg_only? || link_keg
@show_header = show_header
@ignore_deps = ignore_deps
@ -688,6 +691,7 @@ class FormulaInstaller
include_test_formulae: @include_test_formulae,
build_from_source_formulae: @build_from_source_formulae,
keep_tmp: keep_tmp?,
debug_symbols: debug_symbols?,
force: force?,
debug: debug?,
quiet: quiet?,
@ -741,6 +745,7 @@ class FormulaInstaller
include_test_formulae: @include_test_formulae,
build_from_source_formulae: @build_from_source_formulae,
keep_tmp: keep_tmp?,
debug_symbols: debug_symbols?,
force: force?,
debug: debug?,
quiet: quiet?,
@ -802,6 +807,8 @@ class FormulaInstaller
post_install
end
keg.prepare_debug_symbols if debug_symbols?
# Updates the cache for a particular formula after doing an install
CacheStoreDatabase.use(:linkage) do |db|
break unless db.created?
@ -873,6 +880,11 @@ class FormulaInstaller
args << "--cc=#{@cc}" if @cc
args << "--keep-tmp" if keep_tmp?
if debug_symbols?
args << "--debug-symbols"
args << "--build-from-source"
end
if @env.present?
args << "--env=#{@env}"
elsif formula.env.std? || formula.deps.select(&:build?).any? { |d| d.name == "scons" }

View File

@ -269,6 +269,7 @@ module Homebrew
git: false,
interactive: false,
keep_tmp: false,
debug_symbols: false,
force: false,
overwrite: false,
debug: false,
@ -293,6 +294,7 @@ module Homebrew
git: git,
interactive: interactive,
keep_tmp: keep_tmp,
debug_symbols: debug_symbols,
force: force,
overwrite: overwrite,
debug: debug,

View File

@ -483,6 +483,8 @@ class Keg
ObserverPathnameExtension.n
end
def prepare_debug_symbols; end
def remove_oldname_opt_record
return unless oldname_opt_record
return if oldname_opt_record.resolved_path != path

View File

@ -13,7 +13,8 @@ class Mktemp
def initialize(prefix, opts = {})
@prefix = prefix
@retain = opts[:retain]
@retain_in_cache = opts[:retain_in_cache]
@retain = opts[:retain] || @retain_in_cache
@quiet = false
end
@ -28,6 +29,11 @@ class Mktemp
@retain
end
# True if the source files should be retained.
def retain_in_cache?
@retain_in_cache
end
# Instructs this Mktemp to not emit messages when retention is triggered.
sig { void }
def quiet!
@ -40,7 +46,15 @@ class Mktemp
end
def run
@tmpdir = Pathname.new(Dir.mktmpdir("#{@prefix.tr "@", "AT"}-", HOMEBREW_TEMP))
prefix_name = @prefix.tr "@", "AT"
@tmpdir = if retain_in_cache?
tmp_dir = HOMEBREW_CACHE/"Sources/#{prefix_name}"
chmod_rm_rf(tmpdir) # clear out previous staging directory
tmp_dir.mkpath
tmp_dir
else
Pathname.new(Dir.mktmpdir("#{prefix_name}-", HOMEBREW_TEMP))
end
# Make sure files inside the temporary directory have the same group as the
# brew instance.
@ -54,18 +68,21 @@ class Mktemp
Process.gid
end
begin
chown(nil, group_id, tmpdir)
chown(nil, group_id, @tmpdir)
rescue Errno::EPERM
opoo "Failed setting group \"#{Etc.getgrgid(group_id).name}\" on #{tmpdir}"
opoo "Failed setting group \"#{Etc.getgrgid(group_id).name}\" on #{@tmpdir}"
end
begin
Dir.chdir(tmpdir) { yield self }
ensure
ignore_interrupts { chmod_rm_rf(tmpdir) } unless retain?
ignore_interrupts { chmod_rm_rf(@tmpdir) } unless retain?
end
ensure
ohai "Temporary files retained at:", @tmpdir.to_s if retain? && !@tmpdir.nil? && !@quiet
if retain? && @tmpdir.present? && !@quiet
message = retain_in_cache? ? "Source files for debugging available at:" : "Temporary files retained at:"
ohai message, @tmpdir.to_s
end
end
private

View File

@ -16,6 +16,7 @@ module Homebrew
build_from_source_formulae: [],
interactive: false,
keep_tmp: false,
debug_symbols: false,
force: false,
debug: false,
quiet: false,
@ -48,6 +49,7 @@ module Homebrew
git: git,
interactive: interactive,
keep_tmp: keep_tmp,
debug_symbols: debug_symbols,
force: force,
debug: debug,
quiet: quiet,

View File

@ -89,14 +89,14 @@ class Resource
# dir using {Mktemp} so that works with all subtypes.
#
# @api public
def stage(target = nil, &block)
def stage(target = nil, debug_symbols: false, &block)
raise ArgumentError, "target directory or block is required" if !target && block.blank?
prepare_patches
fetch_patches(skip_downloaded: true)
fetch unless downloaded?
unpack(target, &block)
unpack(target, debug_symbols: debug_symbols, &block)
end
def prepare_patches
@ -120,9 +120,9 @@ class Resource
# If block is given, yield to that block with `|stage|`, where stage
# is a {ResourceStageContext}.
# A target or a block must be given, but not both.
def unpack(target = nil)
def unpack(target = nil, debug_symbols: false)
current_working_directory = Pathname.pwd
mktemp(download_name) do |staging|
stage_resource(download_name, debug_symbols: debug_symbols) do |staging|
downloader.stage do
@source_modified_time = downloader.source_modified_time
apply_patches
@ -235,8 +235,8 @@ class Resource
protected
def mktemp(prefix, &block)
Mktemp.new(prefix).run(&block)
def stage_resource(prefix, debug_symbols: false, &block)
Mktemp.new(prefix, retain_in_cache: debug_symbols).run(&block)
end
private

View File

@ -292,6 +292,7 @@ class Cmd
args.concat(optflags) unless runtime_cpu_detection?
args.concat(archflags)
args << "-std=#{@arg0}" if /c[89]9/.match?(@arg0)
args << "-g" if debug_symbols?
args
end
@ -410,6 +411,10 @@ class Cmd
config.include?("w")
end
def debug_symbols?
config.include?("D")
end
def canonical_path(path)
path = Pathname.new(path)
path = path.realpath if path.exist?

View File

@ -205,5 +205,12 @@ describe "ENV" do
expect(env["HOMEBREW_CCCFG"]).to include("g")
end
end
describe "#set_debug_symbols" do
it "sets the debug symbols flag" do
env.set_debug_symbols
expect(env["HOMEBREW_CCCFG"]).to include("D")
end
end
end
end

View File

@ -72,4 +72,16 @@ describe "brew install" do
.and be_a_success
expect(HOMEBREW_CELLAR/"testball1/HEAD-d5eb689/foo/test").not_to be_a_file
end
it "installs formulae with debug symbols", :integration_test do
setup_test_formula "testball1"
expect { brew "install", "testball1", "--debug-symbols", "--build-from-source" }
.to output(%r{#{HOMEBREW_CELLAR}/testball1/0\.1}o).to_stdout
.and not_to_output.to_stderr
.and be_a_success
expect(HOMEBREW_CELLAR/"testball1/0.1/bin/test").to be_a_file
expect(HOMEBREW_CELLAR/"testball1/0.1/bin/test.dSYM/Contents/Resources/DWARF/test").to be_a_file if OS.mac?
expect(HOMEBREW_CACHE/"Sources/testball1").to be_a_directory
end
end

View File

@ -24,6 +24,7 @@ module Homebrew
build_from_source_formulae: [],
interactive: false,
keep_tmp: false,
debug_symbols: false,
force: false,
debug: false,
quiet: false,
@ -61,6 +62,7 @@ module Homebrew
build_from_source_formulae: build_from_source_formulae,
interactive: interactive,
keep_tmp: keep_tmp,
debug_symbols: debug_symbols,
force: force,
debug: debug,
quiet: quiet,
@ -128,6 +130,7 @@ module Homebrew
build_from_source_formulae: [],
interactive: false,
keep_tmp: false,
debug_symbols: false,
force: false,
debug: false,
quiet: false,
@ -161,6 +164,7 @@ module Homebrew
build_from_source_formulae: build_from_source_formulae,
interactive: interactive,
keep_tmp: keep_tmp,
debug_symbols: debug_symbols,
force: force,
debug: debug,
quiet: quiet,
@ -254,6 +258,7 @@ module Homebrew
build_from_source_formulae: [],
interactive: false,
keep_tmp: false,
debug_symbols: false,
force: false,
debug: false,
quiet: false,
@ -339,6 +344,7 @@ module Homebrew
build_from_source_formulae: build_from_source_formulae,
interactive: interactive,
keep_tmp: keep_tmp,
debug_symbols: debug_symbols,
force: force,
debug: debug,
quiet: quiet,
@ -407,6 +413,7 @@ module Homebrew
build_from_source_formulae: build_from_source_formulae + [formula.full_name],
interactive: interactive,
keep_tmp: keep_tmp,
debug_symbols: debug_symbols,
force: force,
debug: debug,
quiet: quiet,