From 656a28ebc064b7eeba7b1eee4a36a00714a84434 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 19 Mar 2018 23:26:08 +0000 Subject: [PATCH] Support for ycmd. --- compile_commands.json | 1 + waf-tools/clang_compilation_database.py | 85 +++++++++++++++++++++++++ wscript | 3 +- 3 files changed, 88 insertions(+), 1 deletion(-) create mode 120000 compile_commands.json create mode 100644 waf-tools/clang_compilation_database.py diff --git a/compile_commands.json b/compile_commands.json new file mode 120000 index 000000000..25eb4b2b4 --- /dev/null +++ b/compile_commands.json @@ -0,0 +1 @@ +build/compile_commands.json \ No newline at end of file diff --git a/waf-tools/clang_compilation_database.py b/waf-tools/clang_compilation_database.py new file mode 100644 index 000000000..4d9b5e275 --- /dev/null +++ b/waf-tools/clang_compilation_database.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Christoph Koke, 2013 + +""" +Writes the c and cpp compile commands into build/compile_commands.json +see http://clang.llvm.org/docs/JSONCompilationDatabase.html + +Usage: + + def configure(conf): + conf.load('compiler_cxx') + ... + conf.load('clang_compilation_database') +""" + +import sys, os, json, shlex, pipes +from waflib import Logs, TaskGen, Task + +Task.Task.keep_last_cmd = True + +@TaskGen.feature('c', 'cxx') +@TaskGen.after_method('process_use') +def collect_compilation_db_tasks(self): + "Add a compilation database entry for compiled tasks" + try: + clang_db = self.bld.clang_compilation_database_tasks + except AttributeError: + clang_db = self.bld.clang_compilation_database_tasks = [] + self.bld.add_post_fun(write_compilation_database) + + tup = tuple(y for y in [Task.classes.get(x) for x in ('c', 'cxx')] if y) + for task in getattr(self, 'compiled_tasks', []): + if isinstance(task, tup): + clang_db.append(task) + +def write_compilation_database(ctx): + "Write the clang compilation database as JSON" + database_file = ctx.bldnode.make_node('compile_commands.json') + Logs.info('Build commands will be stored in %s', database_file.path_from(ctx.path)) + try: + root = json.load(database_file) + except IOError: + root = [] + clang_db = dict((x['file'], x) for x in root) + for task in getattr(ctx, 'clang_compilation_database_tasks', []): + try: + cmd = task.last_cmd + except AttributeError: + continue + directory = getattr(task, 'cwd', ctx.variant_dir) + f_node = task.inputs[0] + filename = os.path.relpath(f_node.abspath(), directory) + entry = { + "directory": directory, + "arguments": cmd, + "file": filename, + } + clang_db[filename] = entry + root = list(clang_db.values()) + database_file.write(json.dumps(root, indent=2)) + +# Override the runnable_status function to do a dummy/dry run when the file doesn't need to be compiled. +# This will make sure compile_commands.json is always fully up to date. +# Previously you could end up with a partial compile_commands.json if the build failed. +for x in ('c', 'cxx'): + if x not in Task.classes: + continue + + t = Task.classes[x] + + def runnable_status(self): + def exec_command(cmd, **kw): + pass + + run_status = self.old_runnable_status() + if run_status == Task.SKIP_ME: + setattr(self, 'old_exec_command', getattr(self, 'exec_command', None)) + setattr(self, 'exec_command', exec_command) + self.run() + setattr(self, 'exec_command', getattr(self, 'old_exec_command', None)) + return run_status + + setattr(t, 'old_runnable_status', getattr(t, 'runnable_status', None)) + setattr(t, 'runnable_status', runnable_status) diff --git a/wscript b/wscript index 6a4854052..2583d400a 100644 --- a/wscript +++ b/wscript @@ -41,7 +41,7 @@ print 'Version: %s' % VERSION def options(opt): opt.load('compiler_cxx') opt.load('winres') - + opt.add_option('--enable-debug', action='store_true', default=False, help='build with debugging information and without optimisation') opt.add_option('--disable-gui', action='store_true', default=False, help='disable building of GUI tools') opt.add_option('--disable-tests', action='store_true', default=False, help='disable building of tests') @@ -63,6 +63,7 @@ def options(opt): def configure(conf): conf.load('compiler_cxx') + conf.load('clang_compilation_database', tooldir=['waf-tools']) if conf.options.target_windows: conf.load('winres') -- 2.30.2