.. |gp4a| replace:: *GNAT Pro for Ada* .. |gp4r| replace:: *GNAT Pro for Rust* .. _Developing_Mixed_Language_Projects: Developing Mixed Language Projects ********************************** With a |gp4a| subscription, you can use the ``gprbuild`` tool in |gp4r| to create applications that combine Ada and Rust. This chapter illustrates how to write a program with an Ada main procedure that invokes Rust functions from static and dynamic library crates. Combining Ada and Rust involves using a C interface on the Ada side and the ``std::ffi`` or ``core::ffi`` (Foreign Function Interface) module in the Rust code. This section is specific to native Linux and native Windows. For instructions on building and running mixed language projects that execute on ``no_std`` targets or require cross-compilation, please see :ref:`Platform_Specific_Information`. Current Limitations =================== This version of |gp4r| covers only the use case of an Ada main with Rust libraries. Future versions should offer complete mixed language support, including support for a Rust main with Ada libraries. Ada Main with Rust Library ========================== We will start by creating a Rust library and an Ada main, which will output the greetings ``Hello from Rust!`` and ``Hello from Ada!``, respectively. The directory structure we are about to create is not mandatory for mixed language development. It simply illustrates the division of the source code across languages. In a directory of your choice, create the following directory structure: .. only:: html or latex .. image:: developing_mixed_lang-ada_with_rust.png .. only:: not (html or latex) .. code-block:: none ada_with_rust/ +-- ada/ +-- rust/ Rust Library ------------ Creating ~~~~~~~~ Navigate to directory :file:`ada_with_rust/rust` and execute: .. code-block:: bash $ cargo new --lib hello_from_rust By default, the :command:`cargo new --lib` command will create a package for an ``rlib`` (Rust static library) that adds two numbers. The command should create directory :file:`hello_from_rust` with the following contents: .. only:: html or latex .. image:: developing_mixed_lang-hello_from_rust.png .. only:: not (html or latex) .. code-block:: none hello_from_rust/ +-- Cargo.toml +-- src/ +-- lib.rs * :file:`Cargo.toml` is the manifest file used by :command:`cargo`. * :file:`src/lib.rs` contains the source code of the library. However, an ``rlib`` is not suitable for mixed language development. To convert the library into either a ``cdylib`` (native dynamic library) or a ``staticlib`` (native static library), edit file :file:`Cargo.toml` as follows: .. code-block:: toml [package] name = "hello_from_rust" version = "0.1.0" edition = "2021" [lib] crate-type = ["staticlib"] [dependencies] The ``crate-type`` property indicates the package kind. Consult `The Manifest Format <../_static/cargo/reference/manifest.html>`_ for further details. Edit file :file:`src/lib.rs` as follows: .. code-block:: rust #[no_mangle] pub extern "C" fn hello_from_rust() { println!("Hello from Rust!"); } Functions that are intended for use by other languages through the C ABI must be subject to attribute ``#[no_mangle]`` and marked as ``extern "C"``. Attribute ``#[no_mangle]`` causes the related item to be publicly exported from the produced library or object file. ABI specification ``extern "C"`` indicates that the related item uses the C ABI. Consult `Foreign Function Interface <../_static/nomicon/ffi.html>`_ for further details. Building ~~~~~~~~ To build the Rust library, execute: .. code-block:: bash $ cargo build --release The command should terminate successfully with output similar to the following: .. code-block:: none Compiling hello_from_rust v0.1.0 () Finished release [optimized] target(s) in