I have been doing some research on how better to integrate cargo projects with beardbolt - a godbolt/compiler-explorer like tool for Emacs.
The default example that comes with beardbolt (and its predecessor RMSBolt) is only really suitable for rust code that doesn't include any dependencies. I however would like to work with cargo dependencies.
I've been able to get it working with a dependency by manually generating a rustc command for beardbolt to use (edited for legibility):
rustc --crate-name example --edition=2024 --crate-type bin -C opt-level=0 \
-L dependency=/home/john/.local/state/emacs/beardbolt-sandbox/target/debug/deps \
--extern ndarray=/home/john/.local/state/emacs/beardbolt-sandbox/target/debug/deps/libndarray-dd3e9807fe477367.rlib
beardbolt will then generate the following command (edited for legibility):
rustc --crate-name example --edition=2024 --crate-type bin -C opt-level=0 \
-L dependency=/home/john/.local/state/emacs/beardbolt-sandbox/target/debug/deps \
--extern ndarray=/home/john/.local/state/emacs/beardbolt-sandbox/target/debug/deps/libndarray-dd3e9807fe477367.rlib \
-C debuginfo=1 --emit link /tmp/beardbolt-dump-ErjehI.rs \
-o /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o \
&& objdump -d /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o \
--insn-width=16 -l -M att \
> /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o.disass
Instead of using --extern command line directive, you can just add extern crate crate_name; in your .rs file. I prefer this way, but I do not use Cargo at all. I also have a LinkedIn article regarding using rustc without Cargo.
I just tried that, and it doesn't seem to work (unless I'm doing something silly )
// NB: I based this from looking at
// https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html#more-details
extern crate ndarray;
use ndarray::array;
fn is_rms(a: char) -> i32 {
match a {
'R' => 1,
'M' => 2,
'S' => 3,
_ => 0,
}
}
fn main() {
let a: u8 = 1 + 1;
if is_rms(a as char) != 0 {
println!("{}", a);
};
is_rms('a');
let a = array![1, 2, 3, 4];
let b = array![8, 7, 6, 5];
let c = vec![1, 2, 3, 4];
let d = vec![2, 3, 4, 5];
dbg!(a.dot(&b));
}
rustc --crate-name example --edition=2024 --crate-type bin -C opt-level=0 -L dependency=/home/john/.local/state/emacs/beardbolt-sandbox/target/debug/deps -C opt-level=0 -C debuginfo=1 --emit link /tmp/beardbolt-dump-XuRiAs.rs -o /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o \
&& objdump -d /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o --insn-width=16 -l -M att > /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o.disass
error[E0463]: can't find crate for `ndarray`
--> /tmp/beardbolt-dump-XuRiAs.rs:1:1
|
1 | extern crate ndarray;
| ^^^^^^^^^^^^^^^^^^^^^ can't find crate
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0463`.
Compilation exited abnormally with code 1
It seems that extern crate doesn't solve the problem for me?
I actually did that in the example in my last reply, but it didn't seem to make a difference!
I am using cargo 1.94.0-nightly (b54051b15 2025-12-30), but it seems like build-plan has now been removed, so that doesn't seem like a feasible option anymore unfortunately.
However, that hint led me to this issue, which led me to cargo-outdir, which in turn led me to cargo build --message-format=json. From here I can find the .rlib paths! However they are only printed if they are built, so it doesn't fully solve the problem for me unfortunately. I was hoping that cargo check --message-format=json would include them, but it only seems to for one of the dependencies in the tree, autocfg.
Because .rlib files need to be created before you reference them. Cargo builds them automatically accordingly the dependencies tree. But, you may need to do that manually.
rustc --crate-name example --edition=2024 --crate-type bin -C opt-level=0 \
-L dependency=/home/john/.local/state/emacs/beardbolt-sandbox/target/debug/deps \
-C opt-level=0 -C debuginfo=1 --emit link /tmp/beardbolt-dump-71IBIj.rs -o /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o \ \
&& objdump -d /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o \
--insn-width=16 -l -M att > /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o.disass
With the following rust file:
extern crate ndarray;
use ndarray::array;
fn main() {
let a = array![1, 2, 3, 4];
let b = array![8, 7, 6, 5];
let c = vec![1, 2, 3, 4];
let d = vec![2, 3, 4, 5];
dbg!(a.dot(&b));
}
And I get:
error[E0463]: can't find crate for `ndarray`
--> /tmp/beardbolt-dump-DrU97k.rs:1:1
|
1 | extern crate ndarray;
| ^^^^^^^^^^^^^^^^^^^^^ can't find crate
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0463`.
Compilation exited abnormally with code 1
The problem is that Cargo hides libndarray.rlib under name libndarray-dd3e9807fe477367.rlib, you can try to reference it as extern crate ndarray_dd3e9807fe477367 as ndarray;, however I am not sure that it will work due using 'dash'.
That sounds right to me, but I wasn't able to get that to load either!
❯ ls target/debug/deps | grep ndarray
libndarray-382e4fc797d1bf82.rmeta
libndarray-dd3e9807fe477367.rlib # This is the lib I want to include
libndarray-dd3e9807fe477367.rmeta
ndarray-382e4fc797d1bf82.d
ndarray-dd3e9807fe477367.d
// I tried with lib prefixed as well - like in the rlib filename -
// with the same error returning
extern crate ndarray_dd3e9807fe477367 as ndarray;
fn main() {
let a = array![1, 2, 3, 4];
let b = array![8, 7, 6, 5];
let res = a.dot(&b);
dbg!(res);
}
rustc --crate-name example --edition=2024 --crate-type bin -C opt-level=0 -L dependency=/home/john/.local/state/emacs/beardbolt-sandbox/target/debug/deps -C debuginfo=1 --emit link /tmp/beardbolt-dump-qtrAGX.rs -o /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o \
&& objdump -d /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o --insn-width=16 -l -M att > /home/john/.local/state/emacs/beardbolt-sandbox/beardbolt.o.disass
Okay, indeed, it looks like extern crate in the source doesn't work (perhaps it's the 'dash' issue, as I pointed earlier). However, CLI --extern directive works perfectly. Here is your source:
use ndarray::array;
fn main() {
let a = array![1, 2, 3, 4];
let b = array![8, 7, 6, 5];
let res = a.dot(&b);
dbg!(res);
}
And here is a no Cargo build script:
project =example
main=${project}
common =..${~/~}..${~/~}simscript${~/~}comm-build.7b:file
crate_dir=./target/debug/deps
comp opts=[--extern, ndarray=./target/debug/deps/libndarray-eba4934cbedcdb29.rlib]
include(common);
Finally, you can use the document I created some time ago to understand as the linking mechanism works.
Note, that I use my own build script, however it should be easy to port it in Make you are using.
Rust is reading crates' metadata, and will distinguish them by their internal hash. Cargo adds extra-filename which IIRC affects that.
Cargo's file naming scheme and build dir layout are private implementation details, and mixing them with DIY builds will not work well.
You either should use rustc yourself for everything and build every dependency from scratch, building Rust like you would build a C project, or build via cargo commands without invoking rustc directly on Cargo's temp files.
That will not work. The crate name encoded in the crate metadata is still ndarray. Which means that if you use extern crate ndarray_dd3e9807fe477367, rustc will reject it as being the wrong crate. In any case rustc will already look for anything starting with libndarray and ending with .rlib in the crate search path if you use extern crate ndarray.
Despite your very clever recommendation, rustc doesn't care how you build 'rlib' file, and how you name it either. rustc only cares that the file name starts with 'lib' and has extension 'rlib'. I explained rustc behavior in my article.
This is more complicated, because rlib contains metadata identifying its own dependencies. You don't need to specify --extern for everything your program uses, only for the few top-level crates that your crate can refer to directly, and then rustc will use metadata to discover the rest. There's a non-trivial matching algorithm there: