0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 00:56:44 +01:00
mongodb/site_scons/site_tools/separate_debug.py
2020-09-02 03:02:47 +00:00

195 lines
7.6 KiB
Python

# Copyright 2020 MongoDB Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
import SCons
def _update_builder(env, builder):
old_scanner = builder.target_scanner
old_path_function = old_scanner.path_function
def new_scanner(node, env, path=()):
results = old_scanner.function(node, env, path)
origin = getattr(node.attributes, "debug_file_for", None)
if origin is not None:
origin_results = old_scanner(origin, env, path)
for origin_result in origin_results:
origin_result_debug_files = getattr(
origin_result.attributes, "separate_debug_files", None
)
if origin_result_debug_files is not None:
results.extend(origin_result_debug_files)
return results
builder.target_scanner = SCons.Scanner.Scanner(
function=new_scanner, path_function=old_path_function,
)
base_action = builder.action
if not isinstance(base_action, SCons.Action.ListAction):
base_action = SCons.Action.ListAction([base_action])
# TODO: Make variables for dsymutil and strip, and for the action
# strings. We should really be running these tools as found by
# xcrun by default. We should achieve that by upgrading the
# site_scons/site_tools/xcode.py tool to search for these for
# us. We could then also remove a lot of the compiler and sysroot
# setup from the etc/scons/xcode_*.vars files, which would be a
# win as well.
if env.TargetOSIs("darwin"):
base_action.list.extend(
[
SCons.Action.Action(
"$DSYMUTIL -num-threads 1 $TARGET -o ${TARGET}.dSYM",
"$DSYMUTILCOMSTR"
),
SCons.Action.Action(
"$STRIP -S ${TARGET}",
"$DEBUGSTRIPCOMSTR"
),
]
)
elif env.TargetOSIs("posix"):
base_action.list.extend(
[
SCons.Action.Action(
"$OBJCOPY --only-keep-debug $TARGET ${TARGET}.debug",
"$OBJCOPY_ONLY_KEEP_DEBUG_COMSTR"
),
SCons.Action.Action(
"$OBJCOPY --strip-debug --add-gnu-debuglink ${TARGET}.debug ${TARGET}",
"$DEBUGSTRIPCOMSTR"
),
]
)
else:
pass
builder.action = base_action
base_emitter = builder.emitter
def new_emitter(target, source, env):
debug_files = []
if env.TargetOSIs("darwin"):
# There isn't a lot of great documentation about the structure of dSYM bundles.
# For general bundles, see:
#
# https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html
#
# But we expect to find two files in the bundle. An
# Info.plist file under Contents, and a file with the same
# name as the target under Contents/Resources/DWARF.
target0 = env.File(target[0])
dsym_dir_name = str(target[0]) + ".dSYM"
dsym_dir = env.Dir(dsym_dir_name, directory=target0.get_dir())
plist_file = env.File("Contents/Info.plist", directory=dsym_dir)
setattr(plist_file.attributes, "aib_effective_suffix", ".dSYM")
setattr(plist_file.attributes, "aib_additional_directory", "{}/Contents".format(dsym_dir_name))
dwarf_dir = env.Dir("Contents/Resources/DWARF", directory=dsym_dir)
dwarf_file = env.File(target0.name, directory=dwarf_dir)
setattr(dwarf_file.attributes, "aib_effective_suffix", ".dSYM")
setattr(dwarf_file.attributes, "aib_additional_directory", "{}/Contents/Resources/DWARF".format(dsym_dir_name))
debug_files.extend([plist_file, dwarf_file])
elif env.TargetOSIs("posix"):
debug_file = env.File(str(target[0]) + ".debug")
debug_files.append(debug_file)
elif env.TargetOSIs("windows"):
debug_file = env.File(env.subst("${PDB}", target=target))
debug_files.append(debug_file)
else:
pass
# Establish bidirectional linkages between the target and each debug file by setting
# attributes on th nodes. We use these in the scanner above to ensure that transitive
# dependencies among libraries are projected into transitive dependencies between
# debug files.
for debug_file in debug_files:
setattr(debug_file.attributes, "debug_file_for", target[0])
setattr(target[0].attributes, "separate_debug_files", debug_files)
# On Windows, we don't want to emit the PDB. The mslink.py
# SCons tool is already doing so, so otherwise it would be
# emitted twice. This tool only needed to adorn the node with
# the various attributes as needed, so we just return the
# original target, source tuple.
if env.TargetOSIs("windows"):
return target, source
return (target + debug_files, source)
new_emitter = SCons.Builder.ListEmitter([base_emitter, new_emitter])
builder.emitter = new_emitter
def generate(env):
if not exists(env):
return
if env.TargetOSIs("darwin"):
if env.get("DSYMUTIL", None) is None:
env["DSYMUTIL"] = env.WhereIs("dsymutil")
if env.get("STRIP", None) is None:
env["STRIP"] = env.WhereIs("strip")
if not env.Verbose():
env.Append(
DSYMUTILCOMSTR="Generating debug info for $TARGET into ${TARGET}.dSYM",
DEBUGSTRIPCOMSTR="Stripping debug info from ${TARGET}",
)
elif env.TargetOSIs("posix"):
if env.get("OBJCOPY", None) is None:
env["OBJCOPY"] = env.Whereis("objcopy")
if not env.Verbose():
env.Append(
OBJCOPY_ONLY_KEEP_DEBUG_COMSTR="Generating debug info for $TARGET into ${TARGET}.dSYM",
DEBUGSTRIPCOMSTR="Stripping debug info from ${TARGET} and adding .gnu.debuglink to ${TARGET}.debug",
)
for builder in ["Program", "SharedLibrary", "LoadableModule"]:
_update_builder(env, env["BUILDERS"][builder])
def exists(env):
if env.TargetOSIs("darwin"):
if env.get("DSYMUTIL", None) is None and env.WhereIs("dsymutil") is None:
return False
if env.get("STRIP", None) is None and env.WhereIs("strip") is None:
return False
elif env.TargetOSIs("posix"):
if env.get("OBJCOPY", None) is None and env.WhereIs("objcopy") is None:
return False
return True