mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 904572 - Add support for generating clang compilation database; r=glandium,r=gps
This commit is contained in:
parent
80df6c3cee
commit
90545a7bf0
@ -228,7 +228,7 @@ define([MOZ_BUILD_BACKEND],
|
||||
BUILD_BACKENDS="RecursiveMake"
|
||||
|
||||
MOZ_ARG_ENABLE_STRING(build-backend,
|
||||
[ --enable-build-backend={AndroidEclipse,CppEclipse,VisualStudio,FasterMake}
|
||||
[ --enable-build-backend={AndroidEclipse,CppEclipse,VisualStudio,FasterMake,CompileDB}
|
||||
Enable additional build backends],
|
||||
[ BUILD_BACKENDS="RecursiveMake `echo $enableval | sed 's/,/ /g'`"])
|
||||
|
||||
|
@ -131,6 +131,7 @@ MACH_MODULES = [
|
||||
'python/mozbuild/mozbuild/mach_commands.py',
|
||||
'python/mozbuild/mozbuild/backend/mach_commands.py',
|
||||
'python/mozbuild/mozbuild/compilation/codecomplete.py',
|
||||
'python/mozbuild/mozbuild/compilation/database.py',
|
||||
'python/mozbuild/mozbuild/frontend/mach_commands.py',
|
||||
'services/common/tests/mach_commands.py',
|
||||
'testing/luciddream/mach_commands.py',
|
||||
|
@ -26,12 +26,9 @@ class Introspection(MachCommandBase):
|
||||
help='Source file to display compilation flags for')
|
||||
def compileflags(self, what):
|
||||
from mozbuild.util import resolve_target_to_make
|
||||
import shlex
|
||||
from mozbuild.compilation import util
|
||||
|
||||
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.')
|
||||
if not util.check_top_objdir(self.topobjdir):
|
||||
return 1
|
||||
|
||||
path_arg = self._wrap_path_argument(what)
|
||||
@ -42,23 +39,7 @@ class Introspection(MachCommandBase):
|
||||
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)
|
||||
build_vars = util.get_build_vars(make_dir, self)
|
||||
|
||||
if what.endswith('.c'):
|
||||
name = 'COMPILE_CFLAGS'
|
||||
@ -68,20 +49,5 @@ class Introspection(MachCommandBase):
|
||||
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))
|
||||
print(util.get_flags(self.topobjdir, make_dir, build_vars, name))
|
||||
|
||||
|
119
python/mozbuild/mozbuild/compilation/database.py
Normal file
119
python/mozbuild/mozbuild/compilation/database.py
Normal file
@ -0,0 +1,119 @@
|
||||
# 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 mozbuild.base import MozbuildObject
|
||||
from mozbuild.compilation import util
|
||||
from mozbuild.backend.common import CommonBackend
|
||||
from mozbuild.frontend.data import (
|
||||
Sources,
|
||||
HostSources,
|
||||
UnifiedSources,
|
||||
GeneratedSources,
|
||||
)
|
||||
from mach.config import ConfigSettings
|
||||
from mach.logging import LoggingManager
|
||||
|
||||
|
||||
class CompileDBBackend(CommonBackend):
|
||||
def _init(self):
|
||||
CommonBackend._init(self)
|
||||
if not util.check_top_objdir(self.environment.topobjdir):
|
||||
raise Exception()
|
||||
|
||||
# The database we're going to dump out to.
|
||||
self._db = []
|
||||
|
||||
# The cache for per-directory flags
|
||||
self._flags = {}
|
||||
|
||||
log_manager = LoggingManager()
|
||||
self._cmd = MozbuildObject(self.environment.topsrcdir, ConfigSettings(),
|
||||
log_manager, self.environment.topobjdir)
|
||||
|
||||
|
||||
def consume_object(self, obj):
|
||||
if isinstance(obj, UnifiedSources):
|
||||
# For unified sources, only include the unified source file.
|
||||
# Note that unified sources are never used for host sources.
|
||||
for f in obj.unified_source_mapping:
|
||||
flags = self._get_dir_flags(obj.objdir)
|
||||
self._build_db_line(obj, self.environment, f[0],
|
||||
obj.canonical_suffix, flags, False)
|
||||
elif isinstance(obj, Sources) or isinstance(obj, HostSources) or \
|
||||
isinstance(obj, GeneratedSources):
|
||||
# For other sources, include each source file.
|
||||
for f in obj.files:
|
||||
flags = self._get_dir_flags(obj.objdir)
|
||||
self._build_db_line(obj, self.environment, f,
|
||||
obj.canonical_suffix, flags,
|
||||
isinstance(obj, HostSources))
|
||||
|
||||
return True
|
||||
|
||||
def consume_finished(self):
|
||||
import json
|
||||
# Output the database (a JSON file) to objdir/compile_commands.json
|
||||
outputfile = os.path.join(self.environment.topobjdir, 'compile_commands.json')
|
||||
with self._write_file(outputfile) as jsonout:
|
||||
json.dump(self._db, jsonout, indent=0)
|
||||
|
||||
def _get_dir_flags(self, directory):
|
||||
if directory in self._flags:
|
||||
return self._flags[directory]
|
||||
|
||||
from mozbuild.util import resolve_target_to_make
|
||||
|
||||
make_dir, make_target = resolve_target_to_make(self.environment.topobjdir, directory)
|
||||
if make_dir is None and make_target is None:
|
||||
raise Exception('Cannot figure out the make dir and target for ' + directory)
|
||||
|
||||
build_vars = util.get_build_vars(directory, self._cmd)
|
||||
|
||||
# We only care about the following build variables.
|
||||
for name in ('COMPILE_CFLAGS', 'COMPILE_CXXFLAGS',
|
||||
'COMPILE_CMFLAGS', 'COMPILE_CMMFLAGS'):
|
||||
if name not in build_vars:
|
||||
continue
|
||||
|
||||
build_vars[name] = util.get_flags(self.environment.topobjdir, directory,
|
||||
build_vars, name)
|
||||
|
||||
self._flags[directory] = build_vars
|
||||
return self._flags[directory]
|
||||
|
||||
def _build_db_line(self, obj, cenv, filename, canonical_suffix, flags, ishost):
|
||||
# Distinguish between host and target files.
|
||||
prefix = 'HOST_' if ishost else ''
|
||||
if canonical_suffix == '.c':
|
||||
compiler = cenv.substs[prefix + 'CC']
|
||||
cflags = flags['COMPILE_CFLAGS']
|
||||
# Add the Objective-C flags if needed.
|
||||
if filename.endswith('.m'):
|
||||
cflags += ' ' + flags['COMPILE_CMFLAGS']
|
||||
elif canonical_suffix == '.cpp':
|
||||
compiler = cenv.substs[prefix + 'CXX']
|
||||
cflags = flags['COMPILE_CXXFLAGS']
|
||||
# Add the Objective-C++ flags if needed.
|
||||
if filename.endswith('.mm'):
|
||||
cflags += ' ' + flags['COMPILE_CMMFLAGS']
|
||||
else:
|
||||
return
|
||||
|
||||
cmd = ' '.join([
|
||||
compiler,
|
||||
'-o', '/dev/null', '-c',
|
||||
cflags,
|
||||
filename,
|
||||
])
|
||||
|
||||
self._db.append({
|
||||
'directory': obj.objdir,
|
||||
'command': cmd,
|
||||
'file': filename
|
||||
})
|
||||
|
63
python/mozbuild/mozbuild/compilation/util.py
Normal file
63
python/mozbuild/mozbuild/compilation/util.py
Normal file
@ -0,0 +1,63 @@
|
||||
# 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 os
|
||||
import shlex
|
||||
|
||||
def check_top_objdir(topobjdir):
|
||||
top_make = os.path.join(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 False
|
||||
return True
|
||||
|
||||
def get_build_vars(directory, cmd):
|
||||
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 = cmd.log_manager.replace_terminal_handler(None)
|
||||
cmd._run_make(directory=directory, target='showbuild', log=False,
|
||||
print_directory=False, allow_parallel=False, silent=True,
|
||||
line_handler=on_line)
|
||||
finally:
|
||||
cmd.log_manager.replace_terminal_handler(old_logger)
|
||||
|
||||
return build_vars
|
||||
|
||||
def get_flags(topobjdir, make_dir, build_vars, name):
|
||||
flags = ['-isystem', '-I', '-include', '-MF']
|
||||
new_args = []
|
||||
path = os.path.join(topobjdir, make_dir)
|
||||
|
||||
# Take case to handle things such as the following correctly:
|
||||
# * -DMOZ_APP_VERSION='"40.0a1"'
|
||||
# * -DR_PLATFORM_INT_TYPES='<stdint.h>'
|
||||
# * -DAPP_ID='{ec8030f7-c20a-464f-9b0e-13a3a9e97384}
|
||||
# * -D__UNUSED__='__attribute__((unused))'
|
||||
lex = shlex.shlex(build_vars[name])
|
||||
lex.quotes = '"'
|
||||
lex.wordchars += '+/\'"-=.*{}()[]<>'
|
||||
|
||||
for arg in list(lex):
|
||||
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)
|
||||
|
||||
return ' '.join(new_args)
|
@ -108,7 +108,7 @@ def config_status(topobjdir='.', topsrcdir='.',
|
||||
help='print diffs of changed files.')
|
||||
parser.add_argument('-b', '--backend', nargs='+',
|
||||
choices=['RecursiveMake', 'AndroidEclipse', 'CppEclipse',
|
||||
'VisualStudio', 'FasterMake'],
|
||||
'VisualStudio', 'FasterMake', 'CompileDB'],
|
||||
default=default_backends,
|
||||
help='what backend to build (default: %s).' %
|
||||
' '.join(default_backends))
|
||||
@ -145,6 +145,9 @@ def config_status(topobjdir='.', topsrcdir='.',
|
||||
elif backend == 'FasterMake':
|
||||
from mozbuild.backend.fastermake import FasterMakeBackend
|
||||
backends_cls.append(FasterMakeBackend)
|
||||
elif backend == 'CompileDB':
|
||||
from mozbuild.compilation.database import CompileDBBackend
|
||||
backends_cls.append(CompileDBBackend)
|
||||
else:
|
||||
backends_cls.append(RecursiveMakeBackend)
|
||||
|
||||
|
@ -560,7 +560,7 @@ class Build(MachCommandBase):
|
||||
# conditions, but that is for another day.
|
||||
@CommandArgument('-b', '--backend', nargs='+',
|
||||
choices=['RecursiveMake', 'AndroidEclipse', 'CppEclipse',
|
||||
'VisualStudio', 'FasterMake'],
|
||||
'VisualStudio', 'FasterMake', 'CompileDB'],
|
||||
help='Which backend to build.')
|
||||
def build_backend(self, backend, diff=False):
|
||||
python = self.virtualenv_manager.python_path
|
||||
|
Loading…
Reference in New Issue
Block a user