--- a/build/templates.mozbuild
+++ b/build/templates.mozbuild
@@ -124,11 +124,21 @@ def HostSimplePrograms(names, ext='.cpp'
HostStdCppCompat()
@template
def HostLibrary(name):
'''Template for build tools libraries.'''
HOST_LIBRARY_NAME = name
+@template
+def HostRustLibrary(name, features=None):
+ '''Template for host Rust libraries.'''
+ HostLibrary(name)
+
+ IS_RUST_LIBRARY = True
+
+ if features:
+ HOST_RUST_LIBRARY_FEATURES = features
+
include('gecko_templates.mozbuild')
include('test_templates.mozbuild')
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -542,17 +542,17 @@ STATIC_LIBS_DEPS := $(foreach l,$(STATIC
GLOBAL_DEPS += Makefile $(addprefix $(DEPTH)/config/,$(INCLUDED_AUTOCONF_MK)) $(MOZILLA_DIR)/config/config.mk
##############################################
ifdef COMPILE_ENVIRONMENT
OBJ_TARGETS = $(OBJS) $(PROGOBJS) $(HOST_OBJS) $(HOST_PROGOBJS)
compile:: host target
-host:: $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(HOST_RUST_PROGRAMS)
+host:: $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(HOST_RUST_PROGRAMS) $(HOST_RUST_LIBRARY_FILE)
target:: $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(RUST_LIBRARY_FILE) $(RUST_PROGRAMS)
include $(MOZILLA_DIR)/config/makefiles/target_binaries.mk
endif
##############################################
ifneq (1,$(NO_PROFILE_GUIDED_OPTIMIZE))
@@ -963,16 +963,29 @@ endif
# build.
force-cargo-library-build:
$(REPORT_BUILD)
$(CARGO_BUILD) --lib $(cargo_target_flag) $(rust_features_flag)
$(RUST_LIBRARY_FILE): force-cargo-library-build
endif # RUST_LIBRARY_FILE
+ifdef HOST_RUST_LIBRARY_FILE
+
+ifdef HOST_RUST_LIBRARY_FEATURES
+host_rust_features_flag := --features "$(HOST_RUST_LIBRARY_FEATURES)"
+endif
+
+force-cargo-host-library-build:
+ $(REPORT_BUILD)
+ $(CARGO_BUILD) --lib $(cargo_host_flag) $(host_rust_features_flag)
+
+$(HOST_RUST_LIBRARY_FILE): force-cargo-host-library-build
+endif # HOST_RUST_LIBRARY_FILE
+
ifdef RUST_PROGRAMS
force-cargo-program-build:
$(REPORT_BUILD)
$(CARGO_BUILD) $(addprefix --bin ,$(RUST_CARGO_PROGRAMS)) $(cargo_target_flag)
$(RUST_PROGRAMS): force-cargo-program-build
endif # RUST_PROGRAMS
ifdef HOST_RUST_PROGRAMS
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -56,16 +56,17 @@ from ..frontend.data import (
JavaJarData,
Library,
LocalInclude,
ObjdirFiles,
ObjdirPreprocessedFiles,
PerSourceFlag,
Program,
RustLibrary,
+ HostRustLibrary,
RustProgram,
SharedLibrary,
SimpleProgram,
Sources,
StaticLibrary,
TestManifest,
VariablePassthru,
XPIDLFile,
@@ -1200,20 +1201,25 @@ class RecursiveMakeBackend(CommonBackend
backend_file.write('FORCE_STATIC_LIB := 1\n')
backend_file.write('REAL_LIBRARY := %s\n' % libdef.lib_name)
if libdef.is_sdk:
backend_file.write('SDK_LIBRARY := %s\n' % libdef.import_name)
if libdef.no_expand_lib:
backend_file.write('NO_EXPAND_LIBS := 1\n')
def _process_rust_library(self, libdef, backend_file):
- backend_file.write_once('RUST_LIBRARY_FILE := %s\n' % libdef.import_name)
+ lib_var = 'RUST_LIBRARY_FILE'
+ feature_var = 'RUST_LIBRARY_FEATURES'
+ if isinstance(libdef, HostRustLibrary):
+ lib_var = 'HOST_RUST_LIBRARY_FILE'
+ feature_var = 'HOST_RUST_LIBRARY_FEATURES'
+ backend_file.write_once('%s := %s\n' % (libdef.LIB_FILE_VAR, libdef.import_name))
backend_file.write('CARGO_FILE := $(srcdir)/Cargo.toml\n')
if libdef.features:
- backend_file.write('RUST_LIBRARY_FEATURES := %s\n' % ' '.join(libdef.features))
+ backend_file.write('%s := %s\n' % (libdef.FEATURES_VAR, ' '.join(libdef.features)))
def _process_host_library(self, libdef, backend_file):
backend_file.write('HOST_LIBRARY_NAME = %s\n' % libdef.basename)
def _build_target_for_obj(self, obj):
return '%s/%s' % (mozpath.relpath(obj.objdir,
self.environment.topobjdir), obj.KIND)
@@ -1260,17 +1266,17 @@ class RecursiveMakeBackend(CommonBackend
backend_file.write_once('STATIC_LIBS += %s/%s\n'
% (relpath, lib.import_name))
write_shared_and_system_libs(lib)
else:
assert lib.variant != lib.COMPONENT
backend_file.write_once('SHARED_LIBS += %s/%s\n'
% (relpath, lib.import_name))
elif isinstance(obj, (HostLibrary, HostProgram, HostSimpleProgram)):
- assert isinstance(lib, HostLibrary)
+ assert isinstance(lib, (HostLibrary, HostRustLibrary))
backend_file.write_once('HOST_LIBS += %s/%s\n'
% (relpath, lib.import_name))
# We have to link any Rust libraries after all intermediate static
# libraries have been listed to ensure that the Rust libraries are
# searched after the C/C++ objects that might reference Rust symbols.
if isinstance(obj, SharedLibrary):
self._process_rust_libraries(obj, backend_file, pretty_relpath)
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -954,16 +954,23 @@ VARIABLES = {
'RUST_LIBRARY_FEATURES': (List, list,
"""Cargo features to activate for this library.
This variable should not be used directly; you should be using the
RustLibrary template instead.
"""),
+ 'HOST_RUST_LIBRARY_FEATURES': (List, list,
+ """Cargo features to activate for this host library.
+
+ This variable should not be used directly; you should be using the
+ HostRustLibrary template instead.
+ """),
+
'UNIFIED_SOURCES': (ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList), list,
"""Source code files that can be compiled together.
This variable contains a list of source code files to compile,
that can be concatenated all together and built as a single source
file. This can help make the build faster and reduce the debug info
size.
"""),
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -415,17 +415,17 @@ class SimpleProgram(BaseProgram):
class HostSimpleProgram(HostMixin, BaseProgram):
"""Context derived container object for each program in
HOST_SIMPLE_PROGRAMS"""
SUFFIX_VAR = 'HOST_BIN_SUFFIX'
KIND = 'host'
-def cargo_target_directory(context, target_var='RUST_TARGET'):
+def cargo_target_directory(context, target_var):
# cargo creates several directories and places its build artifacts
# in those directories. The directory structure depends not only
# on the target, but also what sort of build we are doing.
rust_build_kind = 'release'
if context.config.substs.get('MOZ_DEBUG'):
rust_build_kind = 'debug'
return mozpath.join(context.config.substs[target_var], rust_build_kind)
@@ -521,32 +521,35 @@ class RustLibrary(StaticLibrary):
"""Context derived container object for a static library"""
__slots__ = (
'cargo_file',
'crate_type',
'dependencies',
'deps_path',
'features',
)
+ TARGET_SUBST_VAR = 'RUST_TARGET'
+ FEATURES_VAR = 'RUST_LIBRARY_FEATURES'
+ LIB_FILE_VAR = 'RUST_LIBRARY_FILE'
def __init__(self, context, basename, cargo_file, crate_type, dependencies,
features, **args):
StaticLibrary.__init__(self, context, basename, **args)
self.cargo_file = cargo_file
self.crate_type = crate_type
# We need to adjust our naming here because cargo replaces '-' in
# package names defined in Cargo.toml with underscores in actual
# filenames. But we need to keep the basename consistent because
# many other things in the build system depend on that.
assert self.crate_type == 'staticlib'
self.lib_name = '%s%s%s' % (context.config.lib_prefix,
basename.replace('-', '_'),
context.config.lib_suffix)
self.dependencies = dependencies
- build_dir = cargo_target_directory(context)
+ build_dir = cargo_target_directory(context, self.TARGET_SUBST_VAR)
self.import_name = mozpath.join(build_dir, self.lib_name)
self.deps_path = mozpath.join(build_dir, 'deps')
self.features = features
class SharedLibrary(Library):
"""Context derived container object for a shared library"""
__slots__ = (
@@ -627,16 +630,24 @@ class ExternalSharedLibrary(SharedLibrar
build system."""
class HostLibrary(HostMixin, BaseLibrary):
"""Context derived container object for a host library"""
KIND = 'host'
+class HostRustLibrary(HostMixin, RustLibrary):
+ """Context derived container object for a host rust library"""
+ KIND = 'host'
+ TARGET_SUBST_VAR = 'RUST_HOST_TARGET'
+ FEATURES_VAR = 'HOST_RUST_LIBRARY_FEATURES'
+ LIB_FILE_VAR = 'HOST_RUST_LIBRARY_FILE'
+
+
class TestManifest(ContextDerived):
"""Represents a manifest file containing information about tests."""
__slots__ = (
# The type of test manifest this is.
'flavor',
# Maps source filename to destination filename. The destination
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -58,16 +58,17 @@ from .data import (
LocalInclude,
ObjdirFiles,
ObjdirPreprocessedFiles,
PerSourceFlag,
PreprocessedTestWebIDLFile,
PreprocessedWebIDLFile,
Program,
RustLibrary,
+ HostRustLibrary,
RustProgram,
SdkFiles,
SharedLibrary,
SimpleProgram,
Sources,
StaticLibrary,
TestHarnessFiles,
TestWebIDLFile,
@@ -409,17 +410,17 @@ class TreeMetadataEmitter(LoggingMixin):
'%s %s of crate %s has a non-relative path' % (description, dep_crate_name, crate_name),
context)
if not os.path.exists(mozpath.join(context.config.topsrcdir, crate_dir, dep_path)):
raise SandboxValidationError(
'%s %s of crate %s refers to a non-existent path' % (description, dep_crate_name, crate_name),
context)
- def _rust_library(self, context, libname, static_args):
+ def _rust_library(self, context, libname, static_args, cls=RustLibrary):
# We need to note any Rust library for linking purposes.
config, cargo_file = self._parse_cargo_file(context)
crate_name = config['package']['name']
if crate_name != libname:
raise SandboxValidationError(
'library %s does not match Cargo.toml-defined package %s' % (libname, crate_name),
context)
@@ -461,25 +462,26 @@ class TreeMetadataEmitter(LoggingMixin):
if panic != 'abort':
raise SandboxValidationError(
('Cargo.toml for %s does not specify `panic = "abort"`'
' in [profile.%s] section') % (libname, profile_name),
context)
dependencies = set(config.get('dependencies', {}).iterkeys())
- features = context.get('RUST_LIBRARY_FEATURES', [])
+ features = context.get(cls.FEATURES_VAR, [])
unique_features = set(features)
if len(features) != len(unique_features):
raise SandboxValidationError(
'features for %s should not contain duplicates: %s' % (libname, features),
context)
- return RustLibrary(context, libname, cargo_file, crate_type,
- dependencies, features, **static_args)
+ return cls(context, libname, cargo_file, crate_type, dependencies,
+ features, **static_args)
+
def _handle_linkables(self, context, passthru, generated_files):
linkables = []
host_linkables = []
def add_program(prog, var):
if var.startswith('HOST_'):
host_linkables.append(prog)
else:
@@ -549,17 +551,22 @@ class TreeMetadataEmitter(LoggingMixin):
host_libname = context.get('HOST_LIBRARY_NAME')
libname = context.get('LIBRARY_NAME')
if host_libname:
if host_libname == libname:
raise SandboxValidationError('LIBRARY_NAME and '
'HOST_LIBRARY_NAME must have a different value', context)
- lib = HostLibrary(context, host_libname)
+
+ is_rust_library = context.get('IS_RUST_LIBRARY')
+ if is_rust_library:
+ lib = self._rust_library(context, host_libname, {}, cls=HostRustLibrary)
+ else:
+ lib = HostLibrary(context, host_libname)
self._libs[host_libname].append(lib)
self._linkage.append((context, lib, 'HOST_USE_LIBS'))
host_linkables.append(lib)
final_lib = context.get('FINAL_LIBRARY')
if not libname and final_lib:
# If no LIBRARY_NAME is given, create one.
libname = context.relsrcdir.replace('/', '_')
--- a/python/mozbuild/mozbuild/test/backend/common.py
+++ b/python/mozbuild/mozbuild/test/backend/common.py
@@ -57,16 +57,38 @@ CONFIGS = defaultdict(lambda: {
'non_global_defines': [],
'substs': {
'COMPILE_ENVIRONMENT': '1',
'RUST_TARGET': 'x86_64-unknown-linux-gnu',
'LIB_PREFIX': 'lib',
'LIB_SUFFIX': 'a',
},
},
+ 'host-rust-library': {
+ 'defines': {},
+ 'non_global_defines': [],
+ 'substs': {
+ 'COMPILE_ENVIRONMENT': '1',
+ 'RUST_HOST_TARGET': 'x86_64-unknown-linux-gnu',
+ 'RUST_TARGET': 'armv7-linux-androideabi',
+ 'LIB_PREFIX': 'lib',
+ 'LIB_SUFFIX': 'a',
+ },
+ },
+ 'host-rust-library-features': {
+ 'defines': {},
+ 'non_global_defines': [],
+ 'substs': {
+ 'COMPILE_ENVIRONMENT': '1',
+ 'RUST_HOST_TARGET': 'x86_64-unknown-linux-gnu',
+ 'RUST_TARGET': 'armv7-linux-androideabi',
+ 'LIB_PREFIX': 'lib',
+ 'LIB_SUFFIX': 'a',
+ },
+ },
'rust-library-features': {
'defines': {},
'non_global_defines': [],
'substs': {
'COMPILE_ENVIRONMENT': '1',
'RUST_TARGET': 'x86_64-unknown-linux-gnu',
'LIB_PREFIX': 'lib',
'LIB_SUFFIX': 'a',
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/backend/data/host-rust-library-features/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "hostrusttool"
+version = "0.1.0"
+authors = [
+ "Nobody <nobody@mozilla.org>",
+]
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/backend/data/host-rust-library-features/moz.build
@@ -0,0 +1,19 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+@template
+def HostLibrary(name):
+ '''Template for libraries.'''
+ HOST_LIBRARY_NAME = name
+
+@template
+def HostRustLibrary(name, features=None):
+ '''Template for Rust libraries.'''
+ HostLibrary(name)
+
+ IS_RUST_LIBRARY = True
+
+ if features:
+ HOST_RUST_LIBRARY_FEATURES = features
+
+HostRustLibrary('hostrusttool', ['musthave', 'cantlivewithout'])
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/backend/data/host-rust-library/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "hostrusttool"
+version = "0.1.0"
+authors = [
+ "Nobody <nobody@mozilla.org>",
+]
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/backend/data/host-rust-library/moz.build
@@ -0,0 +1,19 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+@template
+def HostLibrary(name):
+ '''Template for libraries.'''
+ HOST_LIBRARY_NAME = name
+
+@template
+def HostRustLibrary(name, features=None):
+ '''Template for Rust libraries.'''
+ HostLibrary(name)
+
+ IS_RUST_LIBRARY = True
+
+ if features:
+ HOST_RUST_LIBRARY_FEATURES = features
+
+HostRustLibrary('hostrusttool')
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -744,16 +744,45 @@ class TestRecursiveMakeBackend(BackendTe
expected = [
'RUST_LIBRARY_FILE := x86_64-unknown-linux-gnu/release/libgkrust.a',
'CARGO_FILE := $(srcdir)/Cargo.toml',
]
self.assertEqual(lines, expected)
+ def test_host_rust_library(self):
+ """Test that a Rust library is written to backend.mk correctly."""
+ env = self._consume('host-rust-library', RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, 'backend.mk')
+ lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+
+ expected = [
+ 'HOST_RUST_LIBRARY_FILE := x86_64-unknown-linux-gnu/release/libhostrusttool.a',
+ 'CARGO_FILE := $(srcdir)/Cargo.toml',
+ ]
+
+ self.assertEqual(lines, expected)
+
+ def test_host_rust_library_with_features(self):
+ """Test that a host Rust library with features is written to backend.mk correctly."""
+ env = self._consume('host-rust-library-features', RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, 'backend.mk')
+ lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+
+ expected = [
+ 'HOST_RUST_LIBRARY_FILE := x86_64-unknown-linux-gnu/release/libhostrusttool.a',
+ 'CARGO_FILE := $(srcdir)/Cargo.toml',
+ 'HOST_RUST_LIBRARY_FEATURES := musthave cantlivewithout',
+ ]
+
+ self.assertEqual(lines, expected)
+
def test_rust_library_with_features(self):
"""Test that a Rust library with features is written to backend.mk correctly."""
env = self._consume('rust-library-features', RecursiveMakeBackend)
backend_path = mozpath.join(env.topobjdir, 'backend.mk')
lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
expected = [
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-libraries/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "host-lib"
+version = "0.1.0"
+authors = [
+ "Nobody <nobody@mozilla.org>",
+]
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-libraries/moz.build
@@ -0,0 +1,19 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+@template
+def HostLibrary(name):
+ '''Template for libraries.'''
+ HOST_LIBRARY_NAME = name
+
+@template
+def HostRustLibrary(name, features=None):
+ '''Template for Rust libraries.'''
+ HostLibrary(name)
+
+ IS_RUST_LIBRARY = True
+
+ if features:
+ RUST_LIBRARY_FEATURES = features
+
+HostRustLibrary('host-lib')
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -20,16 +20,17 @@ from mozbuild.frontend.data import (
ConfigFileSubstitution,
Defines,
DirectoryTraversal,
Exports,
FinalTargetPreprocessedFiles,
GeneratedFile,
GeneratedSources,
HostDefines,
+ HostRustLibrary,
HostRustProgram,
HostSources,
IPDLFile,
JARManifest,
LinkageMultipleRustLibrariesError,
LocalInclude,
Program,
RustLibrary,
@@ -1143,16 +1144,27 @@ class TestEmitterBasic(unittest.TestCase
extra_substs=dict(RUST_HOST_TARGET='i686-pc-windows-msvc',
HOST_BIN_SUFFIX='.exe'))
objs = self.read_topsrcdir(reader)
self.assertEqual(len(objs), 1)
self.assertIsInstance(objs[0], HostRustProgram)
self.assertEqual(objs[0].name, 'some')
+ def test_host_rust_libraries(self):
+ '''Test HOST_RUST_LIBRARIES emission.'''
+ reader = self.reader('host-rust-libraries',
+ extra_substs=dict(RUST_HOST_TARGET='i686-pc-windows-msvc',
+ HOST_BIN_SUFFIX='.exe'))
+ objs = self.read_topsrcdir(reader)
+ self.assertEqual(len(objs), 1)
+ self.assertIsInstance(objs[0], HostRustLibrary)
+ self.assertRegexpMatches(objs[0].lib_name, 'host_lib')
+ self.assertRegexpMatches(objs[0].import_name, 'host_lib')
+
def test_crate_dependency_path_resolution(self):
'''Test recursive dependencies resolve with the correct paths.'''
reader = self.reader('crate-dependency-path-resolution',
extra_substs=dict(RUST_TARGET='i686-pc-windows-msvc'))
objs = self.read_topsrcdir(reader)
self.assertEqual(len(objs), 1)
self.assertIsInstance(objs[0], RustLibrary)