Bug 1293253 - part 10 - emit {Host,}RustProgram objects from the frontend; r=chmanchester
authorNathan Froyd <froydnj@mozilla.com>
Mon, 28 Nov 2016 11:20:38 -0500
changeset 324487 09f249970fc319f7810d80886d34de54175abf8a
parent 324486 27c257be4c2e18221ee679c48e342b0b5b0ca9ed
child 324488 3fa64db7e2ff51f6608364003119469a94b9363d
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewerschmanchester
bugs1293253
milestone53.0a1
Bug 1293253 - part 10 - emit {Host,}RustProgram objects from the frontend; r=chmanchester
python/mozbuild/mozbuild/frontend/context.py
python/mozbuild/mozbuild/frontend/emitter.py
python/mozbuild/mozbuild/test/frontend/data/host-rust-program-no-cargo-toml/moz.build
python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/Cargo.toml
python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/moz.build
python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/Cargo.toml
python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/moz.build
python/mozbuild/mozbuild/test/frontend/data/rust-program-no-cargo-toml/moz.build
python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/Cargo.toml
python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/moz.build
python/mozbuild/mozbuild/test/frontend/data/rust-programs/Cargo.toml
python/mozbuild/mozbuild/test/frontend/data/rust-programs/moz.build
python/mozbuild/mozbuild/test/frontend/test_emitter.py
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -1338,16 +1338,30 @@ VARIABLES = {
         Each name in this variable corresponds to a hosst executable built
         from the corresponding source file with the same base name.
 
         If the configuration token ``HOST_BIN_SUFFIX`` is set, its value will
         be automatically appended to each name. If a name already ends with
         ``HOST_BIN_SUFFIX``, the name will remain unchanged.
         """),
 
+    'RUST_PROGRAMS': (StrictOrderingOnAppendList, list,
+        """Compile a list of Rust host executable names.
+
+        Each name in this variable corresponds to an executable built from
+        the Cargo.toml in the same directory.
+        """),
+
+    'HOST_RUST_PROGRAMS': (StrictOrderingOnAppendList, list,
+        """Compile a list of Rust executable names.
+
+        Each name in this variable corresponds to an executable built from
+        the Cargo.toml in the same directory.
+        """),
+
     'CONFIGURE_SUBST_FILES': (ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList), list,
         """Output files that will be generated using configure-like substitution.
 
         This is a substitute for ``AC_OUTPUT`` in autoconf. For each path in this
         list, we will search for a file in the srcdir having the name
         ``{path}.in``. The contents of this file will be read and variable
         patterns like ``@foo@`` will be substituted with the values of the
         ``AC_SUBST`` variables declared during configure.
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -42,31 +42,33 @@ from .data import (
     GeneratedSources,
     GeneratedWebIDLFile,
     ExampleWebIDLInterface,
     ExternalStaticLibrary,
     ExternalSharedLibrary,
     HostDefines,
     HostLibrary,
     HostProgram,
+    HostRustProgram,
     HostSimpleProgram,
     HostSources,
     InstallationTarget,
     IPDLFile,
     JARManifest,
     Library,
     Linkable,
     LocalInclude,
     ObjdirFiles,
     ObjdirPreprocessedFiles,
     PerSourceFlag,
     PreprocessedTestWebIDLFile,
     PreprocessedWebIDLFile,
     Program,
     RustLibrary,
+    RustProgram,
     SdkFiles,
     SharedLibrary,
     SimpleProgram,
     Sources,
     StaticLibrary,
     TestHarnessFiles,
     TestWebIDLFile,
     TestManifest,
@@ -550,16 +552,46 @@ class TreeMetadataEmitter(LoggingMixin):
             program = context.get(kind)
             if program:
                 check_unique_binary(program, kind)
                 self._binaries[program] = cls(context, program)
                 self._linkage.append((context, self._binaries[program],
                     kind.replace('PROGRAM', 'USE_LIBS')))
                 add_program(self._binaries[program], kind)
 
+        all_rust_programs = []
+        for kind, cls in [('RUST_PROGRAMS', RustProgram),
+                          ('HOST_RUST_PROGRAMS', HostRustProgram)]:
+            programs = context[kind]
+            if not programs:
+                continue
+
+            all_rust_programs.append((programs, kind, cls))
+
+        # Verify Rust program definitions.
+        if all_rust_programs:
+            config, cargo_file = self._parse_cargo_file(context);
+            bin_section = config.get('bin', None)
+            if not bin_section:
+                raise SandboxValidationError(
+                    'Cargo.toml in %s has no [bin] section' % context.srcdir,
+                    context)
+
+            defined_binaries = {b['name'] for b in bin_section}
+
+            for programs, kind, cls in all_rust_programs:
+                for program in programs:
+                    if program not in defined_binaries:
+                        raise SandboxValidationError(
+                            'Cannot find Cargo.toml definition for %s' % program,
+                            context)
+
+                    check_unique_binary(program, kind)
+                    self._binaries[program] = cls(context, program, cargo_file)
+
         for kind, cls in [
                 ('SIMPLE_PROGRAMS', SimpleProgram),
                 ('CPP_UNIT_TESTS', SimpleProgram),
                 ('HOST_SIMPLE_PROGRAMS', HostSimpleProgram)]:
             for program in context[kind]:
                 if program in self._binaries:
                     raise SandboxValidationError(
                         'Cannot use "%s" in %s, '
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-no-cargo-toml/moz.build
@@ -0,0 +1,1 @@
+HOST_RUST_PROGRAMS += ['none']
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+authors = ["nobody <nobody@mozilla.org>"]
+name = "testing"
+version = "0.0.1"
+
+[[bin]]
+name = "some"
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-program-nonexistent-name/moz.build
@@ -0,0 +1,1 @@
+HOST_RUST_PROGRAMS += ['none']
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+authors = ["nobody <nobody@mozilla.org>"]
+name = "testing"
+version = "0.0.1"
+
+[[bin]]
+name = "some"
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/host-rust-programs/moz.build
@@ -0,0 +1,1 @@
+HOST_RUST_PROGRAMS += ['some']
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-program-no-cargo-toml/moz.build
@@ -0,0 +1,1 @@
+RUST_PROGRAMS += ['none']
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+authors = ["nobody <nobody@mozilla.org>"]
+name = "testing"
+version = "0.0.1"
+
+[[bin]]
+name = "some"
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-program-nonexistent-name/moz.build
@@ -0,0 +1,1 @@
+RUST_PROGRAMS += ['none']
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-programs/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+authors = ["nobody <nobody@mozilla.org>"]
+name = "testing"
+version = "0.0.1"
+
+[[bin]]
+name = "some"
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/rust-programs/moz.build
@@ -0,0 +1,1 @@
+RUST_PROGRAMS += ['some']
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -22,23 +22,25 @@ from mozbuild.frontend.data import (
     ConfigFileSubstitution,
     Defines,
     DirectoryTraversal,
     Exports,
     FinalTargetPreprocessedFiles,
     GeneratedFile,
     GeneratedSources,
     HostDefines,
+    HostRustProgram,
     HostSources,
     IPDLFile,
     JARManifest,
     LinkageMultipleRustLibrariesError,
     LocalInclude,
     Program,
     RustLibrary,
+    RustProgram,
     SdkFiles,
     SharedLibrary,
     SimpleProgram,
     Sources,
     StaticLibrary,
     TestHarnessFiles,
     TestManifest,
     UnifiedSources,
@@ -1076,16 +1078,68 @@ class TestEmitterBasic(unittest.TestCase
     def test_multiple_rust_libraries(self):
         '''Test that linking multiple Rust libraries throws an error'''
         reader = self.reader('multiple-rust-libraries',
                              extra_substs=dict(RUST_TARGET='i686-pc-windows-msvc'))
         with self.assertRaisesRegexp(LinkageMultipleRustLibrariesError,
              'Cannot link multiple Rust libraries'):
             self.read_topsrcdir(reader)
 
+    def test_rust_program_no_cargo_toml(self):
+        '''Test that specifying RUST_PROGRAMS without a Cargo.toml fails.'''
+        reader = self.reader('rust-program-no-cargo-toml')
+        with self.assertRaisesRegexp(SandboxValidationError,
+             'No Cargo.toml file found'):
+            self.read_topsrcdir(reader)
+
+    def test_host_rust_program_no_cargo_toml(self):
+        '''Test that specifying HOST_RUST_PROGRAMS without a Cargo.toml fails.'''
+        reader = self.reader('host-rust-program-no-cargo-toml')
+        with self.assertRaisesRegexp(SandboxValidationError,
+             'No Cargo.toml file found'):
+            self.read_topsrcdir(reader)
+
+    def test_rust_program_nonexistent_name(self):
+        '''Test that specifying RUST_PROGRAMS that don't exist in Cargo.toml
+        correctly throws an error.'''
+        reader = self.reader('rust-program-nonexistent-name')
+        with self.assertRaisesRegexp(SandboxValidationError,
+             'Cannot find Cargo.toml definition for'):
+            self.read_topsrcdir(reader)
+
+    def test_host_rust_program_nonexistent_name(self):
+        '''Test that specifying HOST_RUST_PROGRAMS that don't exist in
+        Cargo.toml correctly throws an error.'''
+        reader = self.reader('host-rust-program-nonexistent-name')
+        with self.assertRaisesRegexp(SandboxValidationError,
+             'Cannot find Cargo.toml definition for'):
+            self.read_topsrcdir(reader)
+
+    def test_rust_programs(self):
+        '''Test RUST_PROGRAMS emission.'''
+        reader = self.reader('rust-programs',
+                             extra_substs=dict(RUST_TARGET='i686-pc-windows-msvc',
+                                               BIN_SUFFIX='.exe'))
+        objs = self.read_topsrcdir(reader)
+
+        self.assertEqual(len(objs), 1)
+        self.assertIsInstance(objs[0], RustProgram)
+        self.assertEqual(objs[0].name, 'some')
+
+    def test_host_rust_programs(self):
+        '''Test HOST_RUST_PROGRAMS emission.'''
+        reader = self.reader('host-rust-programs',
+                             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_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)