Bug 1319228 - Generate rules for rust in the Tup backend via cargo --build-plan. r=ted

MozReview-Commit-ID: FoCBN9ywIuQ

--HG--
extra : rebase_source : b6b2fdda19492dec13840223ac650507f4648f18
This commit is contained in:
Chris Manchester 2018-06-13 22:33:22 -07:00
Родитель 82c138c9bf
Коммит 76dfb7be41
2 изменённых файлов: 228 добавлений и 1 удалений

Просмотреть файл

@ -0,0 +1,48 @@
# 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/.
from __future__ import absolute_import, unicode_literals
cargo_extra_outputs = {
'bindgen': [
'tests.rs',
'host-target.txt',
],
'cssparser': [
'tokenizer.rs',
],
'gleam': [
'gl_and_gles_bindings.rs',
'gl_bindings.rs',
'gles_bindings.rs',
],
'khronos_api': [
'webgl_exts.rs',
],
'libloading': [
'libglobal_static.a',
'src/os/unix/global_static.o',
],
'selectors': [
'ascii_case_insensitive_html_attributes.rs',
],
'style': [
'gecko/atom_macro.rs',
'gecko/pseudo_element_definition.rs',
'gecko_properties.rs',
'properties.rs',
'gecko/bindings.rs',
'gecko/structs.rs',
],
'webrender': [
'shaders.rs',
],
}
cargo_extra_flags = {
'style': [
'-l', 'static=global_static',
'-L', 'native=%(libloading_outdir)s',
]
}

Просмотреть файл

@ -5,6 +5,7 @@
from __future__ import absolute_import, unicode_literals
import os
import itertools
import json
import sys
import shutil
@ -45,6 +46,7 @@ from ..frontend.data import (
HostLibrary,
HostProgram,
HostSimpleProgram,
RustLibrary,
SharedLibrary,
Sources,
StaticLibrary,
@ -59,6 +61,10 @@ from ..frontend.context import (
ObjDirPath,
RenamedSourcePath,
)
from .cargo_build_defs import (
cargo_extra_outputs,
cargo_extra_flags,
)
class BackendTupfile(object):
@ -82,6 +88,7 @@ class BackendTupfile(object):
self.sources = defaultdict(list)
self.host_sources = defaultdict(list)
self.variables = {}
self.rust_library = None
self.static_lib = None
self.shared_lib = None
self.programs = []
@ -245,6 +252,7 @@ class TupBackend(CommonBackend):
# will be built before any rules that list this as an input.
self._installed_idls = '$(MOZ_OBJ_ROOT)/<installed-idls>'
self._installed_files = '$(MOZ_OBJ_ROOT)/<installed-files>'
self._rust_libs = '$(MOZ_OBJ_ROOT)/<rust-libs>'
# The preprocessor including source-repo.h and buildid.h creates
# dependencies that aren't specified by moz.build and cause errors
# in Tup. Express these as a group dependency.
@ -546,6 +554,8 @@ class TupBackend(CommonBackend):
backend_file.host_sources[obj.canonical_suffix].extend(obj.files)
elif isinstance(obj, VariablePassthru):
backend_file.variables = obj.variables
elif isinstance(obj, RustLibrary):
backend_file.rust_library = obj
elif isinstance(obj, StaticLibrary):
backend_file.static_lib = obj
elif isinstance(obj, SharedLibrary):
@ -583,7 +593,8 @@ class TupBackend(CommonBackend):
self._gen_static_library),
(backend_file.programs, self._gen_programs),
(backend_file.host_programs, self._gen_host_programs),
(backend_file.host_library, self._gen_host_library)):
(backend_file.host_library, self._gen_host_library),
(backend_file.rust_library, self._gen_rust)):
if var:
backend_file.export_shell()
gen_method(backend_file)
@ -621,6 +632,174 @@ class TupBackend(CommonBackend):
tup = self.environment.substs.get('TUP', 'tup')
self._cmd.run_process(cwd=self.environment.topsrcdir, log_name='tup', args=[tup, 'init'])
def _get_cargo_flags(self, obj):
cargo_flags = ['--build-plan', '-Z', 'unstable-options']
if not self.environment.substs.get('MOZ_DEBUG_RUST'):
cargo_flags += ['--release']
cargo_flags += [
'--frozen',
'--manifest-path', mozpath.join(obj.srcdir, 'Cargo.toml'),
'--lib',
'--target=%s' % self.environment.substs['RUST_TARGET'],
]
if obj.features:
cargo_flags += [
'--features', ' '.join(obj.features)
]
return cargo_flags
def _get_cargo_env(self, backend_file):
lib = backend_file.rust_library
env = {
'CARGO_TARGET_DIR': mozpath.normpath(mozpath.join(lib.objdir,
lib.target_dir)),
'RUSTC': self.environment.substs['RUSTC'],
'MOZ_SRC': self.environment.topsrcdir,
'MOZ_DIST': self.environment.substs['DIST'],
'LIBCLANG_PATH': self.environment.substs['MOZ_LIBCLANG_PATH'],
'CLANG_PATH': self.environment.substs['MOZ_CLANG_PATH'],
'PKG_CONFIG_ALLOW_CROSS': '1',
'RUST_BACKTRACE': 'full',
'MOZ_TOPOBJDIR': self.environment.topobjdir,
'PYTHON': self.environment.substs['PYTHON'],
'PYTHONDONTWRITEBYTECODE': '1',
}
cargo_incremental = self.environment.substs.get('CARGO_INCREMENTAL')
if cargo_incremental is not None:
# TODO (bug 1468527): CARGO_INCREMENTAL produces outputs that Tup
# doesn't know about, disable it unconditionally for now.
pass # env['CARGO_INCREMENTAL'] = cargo_incremental
rust_simd = self.environment.substs.get('MOZ_RUST_SIMD')
if rust_simd is not None:
env['RUSTC_BOOTSTRAP'] = '1'
linker_env_var = ('CARGO_TARGET_%s_LINKER' %
self.environment.substs['RUST_TARGET_ENV_NAME'])
env.update({
'MOZ_CARGO_WRAP_LDFLAGS': ' '.join(backend_file.local_flags['LDFLAGS']),
'MOZ_CARGO_WRAP_LD': backend_file.environment.substs['CC'],
linker_env_var: mozpath.join(self.environment.topsrcdir,
'build', 'cargo-linker'),
'RUSTFLAGS': '%s %s' % (' '.join(self.environment.substs['MOZ_RUST_DEFAULT_FLAGS']),
' '.join(self.environment.substs['RUSTFLAGS'])),
})
return env
def _gen_cargo_rules(self, backend_file, build_plan, cargo_env):
invocations = build_plan['invocations']
processed = set()
def get_libloading_outdir():
for invocation in invocations:
if (invocation['package_name'] == 'libloading' and
invocation['outputs'][0].endswith('.rlib')):
return invocation['env']['OUT_DIR']
def display_name(invocation):
output_str = ''
if invocation['outputs']:
output_str = ' -> %s' % ' '.join([os.path.basename(f)
for f in invocation['outputs']])
return '{name} v{version} {kind}{output}'.format(
name=invocation['package_name'],
version=invocation['package_version'],
kind=invocation['kind'],
output=output_str
)
def cargo_quote(s):
return shell_quote(s.replace('\n', '\\n'))
def _process(key, invocation):
if key in processed:
return
processed.add(key)
inputs = set()
shortname = invocation['package_name']
for dep in invocation['deps']:
# We'd expect to just handle dependencies transitively (so use
# invocations[dep]['outputs'] here, but because the weird host dependencies
# sometimes get used in the final library and not intermediate
# libraries, tup doesn't work well with them. So build up the full set
# of intermediate dependencies with 'full-deps'
depmod = invocations[dep]
_process(dep, depmod)
inputs.update(depmod['full-deps'])
command = [
'cd %s &&' % invocation['cwd'],
'env',
]
envvars = invocation.get('env')
for k, v in itertools.chain(cargo_env.iteritems(),
envvars.iteritems()):
command.append("%s=%s" % (k, cargo_quote(v)))
command.append(invocation['program'])
command.extend(cargo_quote(a.replace('dep-info,', ''))
for a in invocation['args'])
outputs = invocation['outputs']
if os.path.basename(invocation['program']) == 'build-script-build':
for output in cargo_extra_outputs.get(shortname, []):
outputs.append(os.path.join(invocation['env']['OUT_DIR'], output))
if (invocation['target_kind'][0] == 'custom-build' and
os.path.basename(invocation['program']) == 'rustc'):
flags = cargo_extra_flags.get(shortname, [])
for flag in flags:
command.append(flag % {'libloading_outdir': get_libloading_outdir()})
if 'rustc' in invocation['program']:
header = 'RUSTC'
else:
inputs.add(invocation['program'])
header = 'RUN'
invocation['full-deps'] = set(inputs)
invocation['full-deps'].update(invocation['outputs'])
backend_file.rule(
command,
inputs=sorted(inputs),
outputs=outputs,
extra_outputs=[self._rust_libs],
extra_inputs=[self._installed_files],
display='%s %s' % (header, display_name(invocation)),
)
for dst, link in invocation['links'].iteritems():
backend_file.symlink_rule(link, dst, self._rust_libs)
for val in enumerate(invocations):
_process(*val)
def _gen_rust(self, backend_file):
# TODO (bug 1468547): The gtest rust library depends on many of the same
# libraries as the main rust library, so we'll need to handle these all
# at once in order to build the gtest rust library.
if 'toolkit/library/gtest' in backend_file.objdir:
return
cargo_flags = self._get_cargo_flags(backend_file.rust_library)
cargo_env = self._get_cargo_env(backend_file)
output_lines = []
def accumulate_output(line):
output_lines.append(line)
cargo_status = self._cmd.run_process(
[self.environment.substs['CARGO'], 'build'] + cargo_flags,
line_handler=accumulate_output,
explicit_env=cargo_env)
cargo_plan = json.loads(''.join(output_lines))
self._gen_cargo_rules(backend_file, cargo_plan, cargo_env)
self.backend_input_files |= set(cargo_plan['inputs'])
def _process_generated_file(self, backend_file, obj):
# TODO: These are directories that don't work in the tup backend
# yet, because things they depend on aren't built yet.