liveBook · Manning

Dynamic library

As explained in Refactoring to Rust

A dynamic module is a compiled extension loaded into a host program at runtime rather than statically embedded in it.

A dynamic library lets a compiled component work with an existing program without putting all its code into that program. A C calculator can call a Rust function from a C-compatible dynamic library. NGINX can load a dynamic module into memory after it starts, allowing the module to be rebuilt without recompiling the whole NGINX binary. section 3.2.2 section 4.2

For the calculator, Cargo’s default rlib is an intermediate artifact for Rust compilation, not the library the C linker needs. Configure the Rust crate as a cdylib, build it, and put the resulting library on the linker search path. The exported function must also use C calling conventions; building a library alone does not make an ordinary Rust function callable from C. section 3.2.2

[lib]
crate-type = ["cdylib"]

This Cargo setting changes the crate output to a dynamic library compatible with native C programs. section 3.2.2

Listing 3.6 Rust solve function that can be exported as compatible with C
#[no_mangle]
pub extern "C" fn solve(
  line: *const c_char, solution: *mut c_int) -> c_int {
  0
}

The small Rust stub shows the other half of the boundary: an exported function with a C-compatible declaration. section 3.2.2

The NGINX case uses a host-specific build path. A module configuration file and C starter code supply the hooks NGINX expects; its configure command adds the directory as a dynamic module. The build produces a module .so alongside the NGINX executable, and an NGINX configuration directive names the module to load. The C starter can call a Rust HTTP handler, keeping the integration incremental. section 4.2

load_module ../nginx-1.19.3/objs/ngx_http_calculator.so;  #1

worker_processes 1;
daemon off;
error_log /dev/stderr info;  #2

events {
  worker_connections  1024;
}

http {
  access_log /dev/stdout;  #3

  server {
    listen       8080;

    location /calculate {
      calculate on;  #4
    }
  }
}

The configuration shows where NGINX loads the compiled module and enables its calculator directive. section 4.2

Two boundary failures

A calculator link attempt reports an undefined reference to solve when the expected callable symbol is unavailable. An NGINX startup attempt reports an undefined ngx_http_calculator_handler symbol while loading its module. Both errors point to a missing function at the boundary, not to a need to rewrite the host program. section 3.2.2 section 4.2

How Refactoring to Rust covers it

How deep it goes
Walks through crate output, linking, exported functions, and NGINX module build steps; defers rewriting NGINX initialization code in Rust.
Examples
Uses a C calculator calling Rust solve and an NGINX HTTP module with a Rust handler.
What it assumes
Starts with an existing C program or NGINX installation, while introducing the Cargo configuration needed for C-compatible output.
What you can do after
Build it from scratch: produce a C-compatible Rust dynamic library or configure, build, and load an NGINX dynamic module.
How it connects
Connects dynamic libraries to Cargo crate types, C calling conventions, linker search paths, NGINX modules, and HTTP handlers.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Refactoring to Rust. The section links point to the parts of the book it draws on.