Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use Cargo to build a library as both an rlib and a dylib but with different contents?

I would like to make a project that contains:

  • a library
  • bindings for C
  • an executable that uses the library

The directory structure, excluding temporary files and other trash:

.
├── Cargo.toml
├── src
│   ├── c_bindings.rs // contains C bindings for library
│   ├── compression.rs
│   ├── const_data.rs
│   ├── hash.rs
│   ├── lib.rs // library
│   └── main.rs // simple executable that uses library
└── target
    └── debug
        ├── gost_stribog
        ├── libgost_stribog.rlib

I want cargo build do this:

  • build Rust library (rlib) that will ignore c_bindings.rs
  • C library (dylib) that will use c_bindings.rs
  • executable

The debug directory should be:

└── target
    └── debug
        ├── gost_stribog
        ├── libgost_stribog.rlib
        ├── libgost_stribog.so

What should my Cargo.toml look like?

like image 302
Flowneee Avatar asked Mar 10 '23 17:03

Flowneee


2 Answers

Opinionated answer: don't.

Instead, split your code into two or three separate crates:

  1. The core library.
  2. The C bindings for the library.
  3. (Optional) The executable.

Then, move your c_bindings.rs to the bindings crate as just lib.rs. It can depend on the core library. You can also move main.rs into another crate that also depends on the core library.

These three crates can be in the same source code repository, but will be built with separate invocations.

A Cargo workspace may prove to be useful; in fact it's listed as an explicit reason ("An FFI crate with a sub-crate for FFI bindings").

like image 118
Shepmaster Avatar answered Mar 30 '23 00:03

Shepmaster


Actually, you can. and here is how.
$PROJECT_ROOT/.cargo/config.rs

[build]
rustflags = ["-C", "prefer-dynamic"]

remeber that you will need to distribute your application with the rust standard library as well.

$ ls $(rustc --print=sysroot)/lib                                 
libLLVM-13-rust-1.57.0-beta.so  librustc_driver-3aebdc12af579500.so  libstd-c8bc39dac3997df6.so  libtest-4d997b51b1a49b1f.so  rustlib

in my case it's named libstd-c8bc39dac3997df6.so, because I'm on linux, if you are on windows, it should be in the bin folder instead of the lib folder.

also, you will need a script to run the program on linux and on MacOS. on linux and on macos you dont just put the library in the same directory as you application and expect it to work, instead you have 2 options.

  1. Put the libraries inside the /usr/lib folder and then run it.
  2. make a script that:
exec LD_LIBRARY_PATH=$PWD ./YOU_APPLICATION $@ # this last commands tells sh to get the command line arguments.

Just that. :)

like image 39
lmtr0 Avatar answered Mar 30 '23 01:03

lmtr0