This project is an example of how to create a cross-platform Arma extension in Rust. The extension has no dependencies except on the core Rust libraries, and builds into a single .dll.
The extension will run on Linux and Windows, both 32-bit and 64-bit.
It supports:
- RVExtensionVersion
- RVExtension
- RVExtensionArgs
- RVExtensionRegisterCallback
Spoffy (https://github.com/Spoffy/Rust-Arma-Extension-Example)
Rust is a memory-safe, fast language that, while it has a bit of a learning curve, is much less prone to weird bugs in production than C and C++ (in my opinion). It has the added advantage that its standard library is cross-platform, so it's possible to easily build Windows and Linux compatible extensions - particularly when utilising things such as file access and networking.
You'll need to install an appropriate rust toolchain. It's recommended to use rustup
for this on both Windows and Linux, as you'll likely be needing to cross-compile. Also, it's really easy.
Once you have a toolchain installed, clone this package, then execute cargo build
, to build the library as appropriate for your platform.
If you're running on 64-bit Windows or Linux, you'll need to rename the .dll or .so to end in \_x64.(so/dll)
. It's also recommended (but not required) to remove the 'lib' prefix on Linux, as it's not needed.
You then need to add your .dll or .so to the Arma server's root directory (same as where the server binary is), or into an addon. (mods/@MyExtension/MyThing.dll). I've personally found the root directory to be more reliable for testing purposes.
Most Linux servers these days are 64-bit. However, the Arma Linux server is typically 32-bit. As such, you'll generally need to cross-compile.
If you're using rustup
to manage toolchains, you can just do rustup target add i686-unknown-linux-gnu
, then build the .so using cargo build --target=i686-unknown-linux-gnu
.
Firstly, you'll need to make sure you have a 32-bit toolchain. I recommend using rustup
, so you can run rustup target add i686-pc-windows-msvc
.
To cross-compile a 32-bit Windows library on 64-bit windows, simply type cargo build --target=i686-pc-windows-msvc
.
Only the MSVC toolchain is supported for 32-bit Windows compilation, due to the nature of the hacks needed to make it work (see .cargo/config for specifics).
This is an implementation detail. If you just want to build the example, you do not need to read this section.
Broadly speaking, Windows uses "stdcall" calling conventions to call functions in the DLL. In 32-bit Windows, the symbol names for these functions are 'decorated', meaning they look something like this: _RVExtension@12
. The @12 being the number of bytes of parameters the functions take.
As it happens, in the rust compiler's infinite wisdom, it generates a '.def' file for the MSVC toolchain linker, that describes the exported symbols. Unfortunately for us, there's no way to make it export the decorated functions (that I've been able to find).
Instead, we override the .def generated by Rust with our own file Win32.def
, which exports the symbols with the correct names.
This means we don't transitively export any dependencies that our Rust code imports, which is a bit of a shame, but it doesn't seem to break anything. This also is why the GCC toolchain is Windows is not supported. If someone wants to explore that possibility, feel free!
This is meant more as an example piece of code, than something to be used in production (though it's entirely possible to use this in production).
As such, it isn't a particularly nice interface between Arma and Rust - it's pretty much the bare minimum to create a safe implementation.
Synixebrett has created a much more fully-featured Rust-Arma interface using some rather fancy Rust macros. If you're looking for something that hides away most of the implementation for you, it's probably worth checking out: https://github.com/synixebrett/arma-rs