summaryrefslogtreecommitdiff
path: root/site_scons
diff options
context:
space:
mode:
authorDaniel Moody <daniel.moody@mongodb.com>2023-01-17 17:38:37 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-01-17 18:33:16 +0000
commit15e9bc63835c7c0c441607e10034841b3a157e3c (patch)
treeacadfa97af8215da03e45ed0133e8730ffe3a579 /site_scons
parente7cf956c8b9aa7af50acbc88b7f4f4ba6b93120f (diff)
downloadmongo-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.py134
-rw-r--r--site_scons/site_tools/ninja.py91
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",