Skip to main content

export_plugin

Macro export_plugin 

Source
export_plugin!() { /* proc-macro */ }
Expand description

Generates the two symbols loaded by ETS2 or ATS for one plugin instance.

After the framework validates the SDK version, initialization pointer, and idle lifecycle state, the input is evaluated exactly once for that accepted initialization attempt. It may be a constructor, a struct literal, or any other expression whose value implements scs_sdk_plugin::TelemetryPlugin. The compiler enforces that trait bound when the generated factory coerces the value into the framework’s plugin object; an expression returning another type is a compile-time error.

The expansion owns a process-lifetime runtime object and emits:

  • scs_telemetry_init, using the SCS system calling convention;
  • scs_telemetry_shutdown, which drains registrations before dropping the active plugin value.

ABI functions and raw SDK pointers exist only inside the expansion and scs-sdk-plugin; the invoking application’s source remains ordinary safe Rust.

Invoke this macro exactly once in a plugin cdylib. Both exported names are fixed by the SCS loader contract, so two invocations in one link unit would define the same process runtime and symbols twice.

§Compile fixtures

The example below remains ignored as a rustdoc test because this proc-macro crate cannot depend back on scs-sdk-plugin without creating a Cargo dependency cycle. The same consumer code is compiled independently in scs-sdk-plugin/tests/fixtures/export-plugin/pass. A sibling fixture omits the trait implementation and must fail with E0277. Windows and Linux fixture builds also inspect the finished dynamic export tables for both SCS symbols.

§Example

#[derive(Default)]
struct MyPlugin;

impl scs_sdk_plugin::TelemetryPlugin for MyPlugin {
    fn metadata(&self) -> scs_sdk_plugin::PluginMetadata {
        scs_sdk_plugin::PluginMetadata::new("My Plugin", env!("CARGO_PKG_VERSION"))
    }

    fn compatibility(&self) -> scs_sdk_plugin::PluginCompatibility {
        use scs_sdk_plugin::sdk::{TelemetryApiVersion, game};
        use scs_sdk_plugin::{Game, GameCompatibility, PluginCompatibility};

        const GAMES: &[GameCompatibility] = &[GameCompatibility::new(
            Game::EuroTruckSimulator2,
            game::ets2::V1_00,
        )];
        PluginCompatibility::new(TelemetryApiVersion::V1_00, GAMES)
    }

    fn initialize(
        &mut self,
        _context: &mut scs_sdk_plugin::PluginContext<'_>,
    ) -> scs_sdk_plugin::PluginResult {
        Ok(())
    }
}

scs_sdk_plugin::export_plugin!(MyPlugin::default());