Bug 892973 - Add support for the YouCompleteMe vim plugin. r=gps, a=NPOTB
new file mode 100644
--- /dev/null
+++ b/.ycm_extra_conf.py
@@ -0,0 +1,27 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import imp
+import os
+from StringIO import StringIO
+import shlex
+
+path = os.path.join(os.path.dirname(__file__), 'mach')
+
+if not os.path.exists(path):
+ path = os.path.join(os.path.dirname(__file__), 'config.status')
+ config = imp.load_module('_buildconfig', open(path), path, ('', 'r', imp.PY_SOURCE))
+ path = os.path.join(config.topsrcdir, 'mach')
+mach_module = imp.load_module('_mach', open(path), path, ('', 'r', imp.PY_SOURCE))
+
+def FlagsForFile(filename):
+ mach = mach_module.get_mach()
+ out = StringIO()
+ out.encoding = None
+ mach.run(['compileflags', filename], stdout=out, stderr=out)
+
+ return {
+ 'flags': shlex.split(out.getvalue()),
+ 'do_cache': True
+ }
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -56,16 +56,23 @@ LLDBINIT_OBJDIR := .lldbinit.in
LLDBINIT_OBJDIR_PATH = $(DEPTH)
LLDBINIT_OBJDIR_FLAGS += -Dtopsrcdir=$(abspath $(topsrcdir))
PP_TARGETS += LLDBINIT_OBJDIR
LLDBINIT_FINAL_TARGET_FILES := $(DEPTH)/.lldbinit
LLDBINIT_FINAL_TARGET_DEST = $(FINAL_TARGET)
INSTALL_TARGETS += LLDBINIT_FINAL_TARGET
+# Put the .ycm_extra_conf.py file at the root of the objdir. It is used by
+# the vim plugin YouCompleteMe.
+YCM_FILES := $(topsrcdir)/.ycm_extra_conf.py
+YCM_DEST := $(abspath $(DEPTH))
+YCM_TARGET := export
+INSTALL_TARGETS += YCM
+
ifdef MOZTTDIR
# Install the Firefox OS fonts.
include $(MOZTTDIR)/fonts.mk
MOZTT_DEST = $(FINAL_TARGET)/fonts
MOZTT_FILES = $(patsubst external/moztt/%,$(MOZTTDIR)/%,$(filter external/moztt/%,$(subst :, ,$(PRODUCT_COPY_FILES))))
INSTALL_TARGETS += MOZTT
endif
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -78,16 +78,17 @@ MACH_MODULES = [
'dom/bindings/mach_commands.py',
'layout/tools/reftest/mach_commands.py',
'python/mach_commands.py',
'python/mach/mach/commands/commandinfo.py',
'python/compare-locales/mach_commands.py',
'python/mozboot/mozboot/mach_commands.py',
'python/mozbuild/mozbuild/mach_commands.py',
'python/mozbuild/mozbuild/backend/mach_commands.py',
+ 'python/mozbuild/mozbuild/compilation/codecomplete.py',
'python/mozbuild/mozbuild/frontend/mach_commands.py',
'services/common/tests/mach_commands.py',
'testing/luciddream/mach_commands.py',
'testing/mach_commands.py',
'testing/taskcluster/mach_commands.py',
'testing/marionette/mach_commands.py',
'testing/mochitest/mach_commands.py',
'testing/xpcshell/mach_commands.py',
--- a/mach
+++ b/mach
@@ -22,25 +22,24 @@ def ancestors(path):
break
def load_mach(topsrcdir):
sys.path[0:0] = [os.path.join(topsrcdir, "build")]
import mach_bootstrap
return mach_bootstrap.bootstrap(topsrcdir)
-def check_and_run_mach(dir_path, args):
+def check_and_get_mach(dir_path):
# If we find the mach bootstrap module, we are in the srcdir.
mach_path = os.path.join(dir_path, 'build/mach_bootstrap.py')
if os.path.isfile(mach_path):
- mach = load_mach(dir_path)
- sys.exit(mach.run(args))
+ return load_mach(dir_path)
+ return None
-
-def main(args):
+def get_mach():
# Check whether the current directory is within a mach src or obj dir.
for dir_path in ancestors(os.getcwd()):
# If we find a "mozinfo.json" file, we are in the objdir.
mozinfo_path = os.path.join(dir_path, 'mozinfo.json')
if os.path.isfile(mozinfo_path):
import json
info = json.load(open(mozinfo_path))
if 'mozconfig' in info and 'MOZCONFIG' not in os.environ:
@@ -51,24 +50,30 @@ def main(args):
#
# Note: subprocess requires native strings in os.environ on Windows
os.environ[b'MOZCONFIG'] = str(info['mozconfig'])
if 'topsrcdir' in info:
# Continue searching for mach_bootstrap in the source directory.
dir_path = info['topsrcdir']
- check_and_run_mach(dir_path, args)
+ mach = check_and_get_mach(dir_path)
+ if mach:
+ return mach
# If we didn't find a source path by scanning for a mozinfo.json, check
# whether the directory containing this script is a source directory.
- check_and_run_mach(os.path.dirname(__file__), args)
+ return check_and_get_mach(os.path.dirname(__file__))
- print('Could not run mach: No mach source directory found.')
- sys.exit(1)
+def main(args):
+ mach = get_mach()
+ if not mach:
+ print('Could not run mach: No mach source directory found.')
+ sys.exit(1)
+ sys.exit(mach.run(args))
if __name__ == '__main__':
if sys.platform == 'win32':
# This is a complete hack to work around the fact that Windows
# multiprocessing needs to import the original module (ie: this
# file), but only works if it has a .py extension.
#
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/compilation/codecomplete.py
@@ -0,0 +1,85 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# This modules provides functionality for dealing with code completion.
+
+import os
+
+from mach.decorators import (
+ CommandArgument,
+ CommandProvider,
+ Command,
+)
+
+from mozbuild.base import MachCommandBase
+
+@CommandProvider
+class Introspection(MachCommandBase):
+ """Instropection commands."""
+
+ @Command('compileflags', category='devenv',
+ description='Display the compilation flags for a given source file')
+ @CommandArgument('what', default=None,
+ help='Source file to display compilation flags for')
+ def compileflags(self, what):
+ from mozbuild.util import resolve_target_to_make
+ import shlex
+
+ top_make = os.path.join(self.topobjdir, 'Makefile')
+ if not os.path.exists(top_make):
+ print('Your tree has not been built yet. Please run '
+ '|mach build| with no arguments.')
+ return 1
+
+ path_arg = self._wrap_path_argument(what)
+
+ make_dir, make_target = resolve_target_to_make(self.topobjdir,
+ path_arg.relpath())
+
+ if make_dir is None and make_target is None:
+ return 1
+
+ build_vars = {}
+
+ def on_line(line):
+ elements = [s.strip() for s in line.split('=', 1)]
+
+ if len(elements) != 2:
+ return
+
+ build_vars[elements[0]] = elements[1]
+
+ try:
+ old_logger = self.log_manager.replace_terminal_handler(None)
+ self._run_make(directory=make_dir, target='showbuild', log=False,
+ print_directory=False, allow_parallel=False, silent=True,
+ line_handler=on_line)
+ finally:
+ self.log_manager.replace_terminal_handler(old_logger)
+
+ if what.endswith('.c'):
+ name = 'COMPILE_CFLAGS'
+ else:
+ name = 'COMPILE_CXXFLAGS'
+
+ if name not in build_vars:
+ return
+
+ flags = ['-isystem', '-I', '-include', '-MF']
+ new_args = []
+ path = os.path.join(self.topobjdir, make_dir)
+ for arg in shlex.split(build_vars[name]):
+ if new_args and new_args[-1] in flags:
+ arg = os.path.normpath(os.path.join(path, arg))
+ else:
+ flag = [(f, arg[len(f):]) for f in flags + ['--sysroot=']
+ if arg.startswith(f)]
+ if flag:
+ flag, val = flag[0]
+ if val:
+ arg = flag + os.path.normpath(os.path.join(path, val))
+ new_args.append(arg)
+
+ print(' '.join(new_args))
+