From 3c46bb9931ecea71167342322e09121ee48cde8e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 5 Aug 2016 13:23:22 +0200 Subject: [PATCH] tools: add compile_commands.json gyp generator Add a compile_commands.json generator for use with clang-based tooling. Pass the (undocumented) -C switch to configure to make it generate the files in out/Debug and out/Release. PR-URL: https://github.com/nodejs/node/pull/7986 Reviewed-By: James M Snell --- configure | 9 ++ .../gyp/generator/compile_commands_json.py | 115 ++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 tools/gyp/pylib/gyp/generator/compile_commands_json.py diff --git a/configure b/configure index 9cadfffbd0..d0b50f80f9 100755 --- a/configure +++ b/configure @@ -474,6 +474,12 @@ parser.add_option('--without-bundled-v8', help='do not use V8 includes from the bundled deps folder. ' + '(This mode is not officially supported for regular applications)') +# Create compile_commands.json in out/Debug and out/Release. +parser.add_option('-C', + action='store_true', + dest='compile_commands_json', + help=optparse.SUPPRESS_HELP) + (options, args) = parser.parse_args() # Expand ~ in the install prefix now, it gets written to multiple files. @@ -1360,6 +1366,9 @@ elif flavor == 'win' and sys.platform != 'msys': else: gyp_args += ['-f', 'make-' + flavor] +if options.compile_commands_json: + gyp_args += ['-f', 'compile_commands_json'] + gyp_args += args if warn.warned: diff --git a/tools/gyp/pylib/gyp/generator/compile_commands_json.py b/tools/gyp/pylib/gyp/generator/compile_commands_json.py new file mode 100644 index 0000000000..575db63c4e --- /dev/null +++ b/tools/gyp/pylib/gyp/generator/compile_commands_json.py @@ -0,0 +1,115 @@ +# Copyright (c) 2016 Ben Noordhuis . All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import gyp.common +import gyp.xcode_emulation +import json +import os + +generator_additional_non_configuration_keys = [] +generator_additional_path_sections = [] +generator_extra_sources_for_rules = [] +generator_filelist_paths = None +generator_supports_multiple_toolsets = True +generator_wants_sorted_dependencies = False + +# Lifted from make.py. The actual values don't matter much. +generator_default_variables = { + 'CONFIGURATION_NAME': '$(BUILDTYPE)', + 'EXECUTABLE_PREFIX': '', + 'EXECUTABLE_SUFFIX': '', + 'INTERMEDIATE_DIR': '$(obj).$(TOOLSET)/$(TARGET)/geni', + 'PRODUCT_DIR': '$(builddir)', + 'RULE_INPUT_DIRNAME': '%(INPUT_DIRNAME)s', + 'RULE_INPUT_EXT': '$(suffix $<)', + 'RULE_INPUT_NAME': '$(notdir $<)', + 'RULE_INPUT_PATH': '$(abspath $<)', + 'RULE_INPUT_ROOT': '%(INPUT_ROOT)s', + 'SHARED_INTERMEDIATE_DIR': '$(obj)/gen', + 'SHARED_LIB_PREFIX': 'lib', + 'STATIC_LIB_PREFIX': 'lib', + 'STATIC_LIB_SUFFIX': '.a', +} + + +def IsMac(params): + return 'mac' == gyp.common.GetFlavor(params) + + +def CalculateVariables(default_variables, params): + default_variables.setdefault('OS', gyp.common.GetFlavor(params)) + + +def AddCommandsForTarget(cwd, target, params, per_config_commands): + output_dir = params['generator_flags']['output_dir'] + for configuration_name, configuration in target['configurations'].iteritems(): + builddir_name = os.path.join(output_dir, configuration_name) + + if IsMac(params): + xcode_settings = gyp.xcode_emulation.XcodeSettings(target) + cflags = xcode_settings.GetCflags(configuration_name) + cflags_c = xcode_settings.GetCflagsC(configuration_name) + cflags_cc = xcode_settings.GetCflagsCC(configuration_name) + else: + cflags = configuration.get('cflags', []) + cflags_c = configuration.get('cflags_c', []) + cflags_cc = configuration.get('cflags_cc', []) + + cflags_c = cflags + cflags_c + cflags_cc = cflags + cflags_cc + + defines = configuration.get('defines', []) + defines = ['-D' + s for s in defines] + + # TODO(bnoordhuis) Handle generated source files. + sources = target.get('sources', []) + sources = [s for s in sources if s.endswith('.c') or s.endswith('.cc')] + + def resolve(filename): + return os.path.abspath(os.path.join(cwd, filename)) + + # TODO(bnoordhuis) Handle generated header files. + include_dirs = configuration.get('include_dirs', []) + include_dirs = [s for s in include_dirs if not s.startswith('$(obj)')] + includes = ['-I' + resolve(s) for s in include_dirs] + + defines = gyp.common.EncodePOSIXShellList(defines) + includes = gyp.common.EncodePOSIXShellList(includes) + cflags_c = gyp.common.EncodePOSIXShellList(cflags_c) + cflags_cc = gyp.common.EncodePOSIXShellList(cflags_cc) + + commands = per_config_commands.setdefault(configuration_name, []) + for source in sources: + file = resolve(source) + isc = source.endswith('.c') + cc = 'cc' if isc else 'c++' + cflags = cflags_c if isc else cflags_cc + command = ' '.join((cc, defines, includes, cflags, + '-c', gyp.common.EncodePOSIXShellArgument(file))) + commands.append(dict(command=command, directory=output_dir, file=file)) + + +def GenerateOutput(target_list, target_dicts, data, params): + per_config_commands = {} + for qualified_target, target in target_dicts.iteritems(): + build_file, target_name, toolset = ( + gyp.common.ParseQualifiedTarget(qualified_target)) + if IsMac(params): + settings = data[build_file] + gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(settings, target) + cwd = os.path.dirname(build_file) + AddCommandsForTarget(cwd, target, params, per_config_commands) + + output_dir = params['generator_flags']['output_dir'] + for configuration_name, commands in per_config_commands.iteritems(): + filename = os.path.join(output_dir, + configuration_name, + 'compile_commands.json') + gyp.common.EnsureDirExists(filename) + fp = open(filename, 'w') + json.dump(commands, fp=fp, indent=0, check_circular=False) + + +def PerformBuild(data, configurations, params): + pass