diff options
author | Daniel Moody <daniel.moody@mongodb.com> | 2023-01-17 17:38:37 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-01-17 18:33:16 +0000 |
commit | 15e9bc63835c7c0c441607e10034841b3a157e3c (patch) | |
tree | acadfa97af8215da03e45ed0133e8730ffe3a579 /site_scons | |
parent | e7cf956c8b9aa7af50acbc88b7f4f4ba6b93120f (diff) | |
download | mongo-15e9bc63835c7c0c441607e10034841b3a157e3c.tar.gz |
SERVER-50476 created gdb_index scons tool to generate gdb_index
Diffstat (limited to 'site_scons')
-rw-r--r-- | site_scons/site_tools/gdb_index.py | 134 | ||||
-rw-r--r-- | site_scons/site_tools/ninja.py | 91 |
2 files changed, 200 insertions, 25 deletions
diff --git a/site_scons/site_tools/gdb_index.py b/site_scons/site_tools/gdb_index.py new file mode 100644 index 00000000000..5850b8560d3 --- /dev/null +++ b/site_scons/site_tools/gdb_index.py @@ -0,0 +1,134 @@ +# 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): + + verbose = '' if env.Verbose() else None + + base_action = builder.action + if not isinstance(base_action, SCons.Action.ListAction): + base_action = SCons.Action.ListAction([base_action]) + + # There are cases were a gdb-index file is NOT generated from gdb 'save gdb-index' command, + # mostly shim libraries where there is no code in the library, and the following Actions would + # then fail. The files are created make sure there is always a file to operate on, if its an + # empty file then the following actions are basically NOOP, and its cleaner then writing + # conditions into each action. + + # Because this is all taking under one task, the list action will always run all actions if + # the target is out of date. So the gdb-index files would always be regenerated, and there is + # no value in keeping them around, it will just waste disk space. Therefore they should be + # removed as if they never existed from the task. The build system doesn't need to know about + # them. + if env.get('DWARF_VERSION') <= 4: + base_action.list.extend([ + SCons.Action.Action( + 'touch ${TARGET}.gdb-index', + verbose, + ), + SCons.Action.Action( + '$GDB --batch-silent --quiet --nx --eval-command "save gdb-index ${TARGET.dir}" $TARGET', + "$GDB_INDEX_GEN_INDEX_STR", + ), + SCons.Action.Action( + '$OBJCOPY --add-section .gdb_index=${TARGET}.gdb-index --set-section-flags .gdb_index=readonly ${TARGET} ${TARGET}', + "$GDB_INDEX_ADD_SECTION_STR", + ), + SCons.Action.Action( + 'rm -f ${TARGET}.gdb-index', + verbose, + ), + ]) + else: + base_action.list.extend([ + SCons.Action.Action( + 'touch ${TARGET}.debug_names ${TARGET}.debug_str', + verbose, + ), + SCons.Action.Action( + '$GDB --batch-silent --quiet --nx --eval-command "save gdb-index -dwarf-5 ${TARGET.dir}" $TARGET', + "$GDB_INDEX_GEN_INDEX_STR", + ), + SCons.Action.Action( + '$OBJCOPY --dump-section .debug_str=${TARGET}.debug_str.new $TARGET', + verbose, + ), + SCons.Action.Action( + 'cat ${TARGET}.debug_str >>${TARGET}.debug_str.new', + verbose, + ), + SCons.Action.Action( + '$OBJCOPY --add-section .debug_names=${TARGET}.debug_names --set-section-flags .debug_names=readonly --update-section .debug_str=${TARGET}.debug_str.new ${TARGET} ${TARGET}', + "$GDB_INDEX_ADD_SECTION_STR", + ), + SCons.Action.Action( + 'rm -f ${TARGET}.debug_names ${TARGET}.debug_str.new ${TARGET}.debug_str', + verbose, + ), + ]) + + builder.action = base_action + + +def generate(env): + if env.get("OBJCOPY", None) is None: + env["OBJCOPY"] = env.WhereIs("objcopy") + if env.get("GDB", None) is None: + env["GDB"] = env.WhereIs("gdb") + + if not env.Verbose(): + env.Append( + GDB_INDEX_GEN_INDEX_STR="Using $GDB to generate index for $TARGET", + GDB_INDEX_ADD_SECTION_STR="Adding index sections into $TARGET", + ) + + for builder in ["Program", "SharedLibrary", "LoadableModule"]: + _update_builder(env, env["BUILDERS"][builder]) + + +def exists(env): + result = False + if env.TargetOSIs("posix"): + objcopy = env.get("OBJCOPY", None) or env.WhereIs("objcopy") + gdb = env.get("GDB", None) or env.WhereIs("gdb") + try: + dwarf_version = int(env.get('DWARF_VERSION')) + except ValueError: + dwarf_version = None + + unset_vars = [] + if not objcopy: + unset_vars += ['OBJCOPY'] + if not gdb: + unset_vars += ['GDB'] + if not dwarf_version: + unset_vars += ['DWARF_VERSION'] + + if not unset_vars: + print("Enabled generation of gdb index into binaries.") + result = True + else: + print(f"Disabled generation gdb index because {', '.join(unset_vars)} were not set.") + return result diff --git a/site_scons/site_tools/ninja.py b/site_scons/site_tools/ninja.py index a55205fc612..78c9e87e66a 100644 --- a/site_scons/site_tools/ninja.py +++ b/site_scons/site_tools/ninja.py @@ -267,6 +267,35 @@ def generate_depfile(env, node, dependencies): f.write(depfile_contents) +def _extract_cmdstr_for_list_action(ninja_build_list): + cmdline = "" + for cmd in ninja_build_list: + + # Occasionally a command line will expand to a + # whitespace only string (i.e. ' '). Which is not a + # valid command but does not trigger the empty command + # condition if not cmdstr. So here we trim the whitespace + # to make strings like the above become empty strings and + # so they will be skipped. + cmdstr = cmd["variables"]["cmd"].strip() + if not cmdstr: + continue + + # Skip duplicate commands + if cmdstr in cmdline: + continue + + if cmdline: + cmdline += " && " + + cmdline += cmdstr + + # Remove all preceding and proceeding whitespace + cmdline = cmdline.strip() + + return cmdline + + class SConsToNinjaTranslator: """Translates SCons Actions into Ninja build objects.""" @@ -384,31 +413,8 @@ class SConsToNinjaTranslator: all_outputs = list({output for build in results for output in build["outputs"]}) dependencies = list({dep for build in results for dep in build["implicit"]}) - if results[0]["rule"] == "CMD": - cmdline = "" - for cmd in results: - - # Occasionally a command line will expand to a - # whitespace only string (i.e. ' '). Which is not a - # valid command but does not trigger the empty command - # condition if not cmdstr. So here we strip preceding - # and proceeding whitespace to make strings like the - # above become empty strings and so will be skipped. - cmdstr = cmd["variables"]["cmd"].strip() - if not cmdstr: - continue - - # Skip duplicate commands - if cmdstr in cmdline: - continue - - if cmdline: - cmdline += " && " - - cmdline += cmdstr - - # Remove all preceding and proceeding whitespace - cmdline = cmdline.strip() + if all([result['rule'] == 'CMD' for result in results]): + cmdline = _extract_cmdstr_for_list_action(results) # Make sure we didn't generate an empty cmdline if cmdline: @@ -431,6 +437,34 @@ class SConsToNinjaTranslator: return ninja_build + elif results[0]["rule"] == "LINK" and all( + [result['rule'] == 'CMD' for result in results[1:]]): + cmdline = _extract_cmdstr_for_list_action(results[1:]) + + # Make sure we didn't generate an empty cmdline + if cmdline: + + env = node.env if node.env else self.env + sources = [get_path(src_file(s)) for s in node.sources] + + ninja_build = results[0] + + ninja_build.update({ + "outputs": all_outputs, + "rule": "LINK_CHAINED_CMD", + "implicit": dependencies, + }) + + ninja_build['variables'].update({ + "cmd": cmdline, + "env": get_command_env(env, all_outputs, sources), + }) + + if node.env and node.env.get("NINJA_POOL", None) is not None: + ninja_build["pool"] = node.env["pool"] + + return ninja_build + elif results[0]["rule"] == "phony": return { "outputs": all_outputs, @@ -535,6 +569,13 @@ class NinjaState: "rspfile_content": "$rspc", "pool": "local_pool", }, + "LINK_CHAINED_CMD": { + "command": "$env$LINK @$out.rsp && $cmd", + "description": "Linked $out", + "rspfile": "$out.rsp", + "rspfile_content": "$rspc", + "pool": "local_pool", + }, "AR": { "command": "$env$AR @$out.rsp", "description": "Archived $out", |