diff --git a/build/docs/rust.rst b/build/docs/rust.rst index acdb07b20a57..0332deda74a2 100644 --- a/build/docs/rust.rst +++ b/build/docs/rust.rst @@ -4,43 +4,51 @@ Including Rust Code in Firefox ============================== -The build system has support for building and linking Rust crates. -Rust code is built using ``cargo`` in the typical way, so it is -straightforward to take an existing Rust crate and integrate it -into Firefox. +The build system has support for building, linking, and vendoring Rust crates. +It is straightforward to take an existing Rust crate and integrate it into +Firefox. -Linking Rust Crates into libxul +Linking Rust crates into libxul =============================== Rust crates that you want to link into libxul should be listed in the -``dependencies`` section of `toolkit/library/rust/shared/Cargo.toml `_. +``dependencies`` section of +`toolkit/library/rust/shared/Cargo.toml `_. After adding your crate, execute ``cargo update -p gkrust-shared`` -to update the ``Cargo.lock`` file. You'll also -need to add an ``extern crate`` reference to +to update the ``Cargo.lock`` file. You'll also need to add an ``extern crate`` +reference to `toolkit/library/rust/shared/lib.rs `_. This ensures that the Rust code will be linked properly into libxul as well as the copy of libxul used for gtests. By default, all Cargo packages in the mozilla-central repository are part of -the same `workspace `_ +the same +`workspace `_ and will share the ``Cargo.lock`` file and ``target`` directory in the root of the repository. You can change this behavior by adding a path to the -``excludes`` list in the top-level ``Cargo.toml`` file. You may want to do +``exclude`` list in the top-level ``Cargo.toml`` file. You may want to do this if your package's development workflow includes dev-dependencies that aren't needed by general Firefox developers or test infrastructure. -Linking Rust Crates into something else +The actual build mechanism is as follows. The build system generates a special +'Rust unified library' crate, compiles that to a static library +(``libgkrust.a``), and links that into libxul, so all public symbols will be +available to C++ code. Building a static library that is linked into a dynamic +library is easier than building dynamic libraries directly, and it also avoids +some subtle issues around how mozalloc works that make the Rust dynamic library +path a little wonky. + +Linking Rust crates into something else ======================================= -There currently is not any Rust code being linked into binaries other than -libxul. If you would like to do so, you'll need to create a directory with -a ``Cargo.toml`` file for your crate, and a ``moz.build`` file that contains: +To link Rust code into libraries other than libxul, create a directory with a +``Cargo.toml`` file for your crate, and a ``moz.build`` file that contains: .. code-block:: python RustLibrary('crate_name') -Where *crate_name* matches the name from the ``[package]`` section of your +where ``crate_name`` matches the name from the ``[package]`` section of your ``Cargo.toml``. You can refer to `the moz.build file `_ and `the Cargo.toml file `_ that are used for libxul. You can then add ``USE_LIBS += ['crate_name']`` to the ``moz.build`` file @@ -48,18 +56,40 @@ that defines the binary as you would with any other library in the tree. .. important:: - You cannot link a Rust crate into an intermediate library that will wind - up being linked into libxul. The build system enforces that only a single + You cannot link a Rust crate into an intermediate library that will be + eventually linked into libxul. The build system enforces that only a single ``RustLibrary`` may be linked into a binary. If you need to do this, you will have to add a ``RustLibrary`` to link to any standalone binaries that link the intermediate library, and also add the Rust crate to the libxul dependencies as in `linking Rust Crates into libxul`_. -Where Should I put my Crate? +Standalone Rust programs +======================== + +It is also possible to build standalone Rust programs. First, put the Rust +program (including the ``Cargo.toml`` file and the ``src`` directory) in its +own directory, and add an empty ``moz.build`` file to the same directory. + +Then, if the standalone Rust program must run on the compile target (e.g. +because it's shipped with Firefox) then add this rule to the ``moz.build`` +file: + +.. code-block:: python + + RUST_PROGRAMS = ['prog_name'] + +where *prog_name* is the name of the executable as specified in the +``Cargo.toml`` (and probably also matches the name of the directory). + +Otherwise, if the standalone Rust program must run on the compile host (e.g. +because it's used to build Firefox but not shipped with Firefox) then do the +same thing, but use ``HOST_RUST_PROGRAMS`` instead of ``RUST_PROGRAMS``. + +Where should I put my crate? ============================ If your crate's canonical home is mozilla-central, you can put it next to the -other code in the module it belongs to. +related code in the appropriate directory. If your crate is mirrored into mozilla-central from another repository, and will not be actively developed in mozilla-central, you can simply list it @@ -70,12 +100,51 @@ If your crate is mirrored into mozilla-central from another repository, but will be actively developed in both locations, you should send mail to the dev-builds mailing list to start a discussion on how to meet your needs. +Third-party crate dependencies +============================== -Crate dependencies -================== +Third-party dependencies for in-tree Rust crates are *vendored* into the +``third_party/rust`` directory of mozilla-central. This means that a copy of +each third-party crate's code is committed into mozilla-central. As a result, +building Firefox does not involve downloading any third-party crates. -All dependencies for in-tree Rust crates are vendored into the -``third_party/rust`` directory. Currently if you add a dependency on a new -crate you must run ``mach vendor rust`` to vendor the dependencies into -that directory. In the future we hope to make it so that you only need to -vendor the dependencies in order to build your changes in a CI push. +If you add a dependency on a new crate you must run ``mach vendor rust`` to +vendor the dependencies into that directory. (Note that ``mach vendor rust`` +`may not work as well on Windows `_ +as on other platforms.) + +When it comes to checking the suitability of third-party code for inclusion +into mozilla-central, keep the following in mind. + +- ``mach vendor rust`` will check that the licenses of all crates are suitable. +- You should review the crate code to some degree to check that it looks + reasonable (especially for unsafe code) and that it has reasonable tests. +- Other than that, there is no formal sign-off procedure, but one may be added + in the future. + +Note that all dependencies will be vendored, even ones that aren't used due to +disabled features. It's possible that multiple versions of a crate will end up +vendored into mozilla-central. + +Patching third-party crates +=========================== + +Sometimes you might want to temporarily patch a third-party crate, for local +builds or for a try push. + +To do this, first add an entry to the ``[patch.crates-io]`` section of the +top-level ``Cargo.toml`` that points to the crate within ``third_party``. For +example + +.. code-block:: toml + + bitflags = { path = "third_party/rust/bitflags" } + +Next, run ``cargo update -p $CRATE_NAME --precise $VERSION``, where +``$CRATE_NAME`` is the name of the patched crate, and ``$VERSION`` is its +version number. This will update the ``Cargo.lock`` file. + +Then, make the local changes to the crate. + +Finally, make sure you don't accidentally land the changes to the crate or the +``Cargo.lock`` file.