0

I am currently trying to build a small Rust library which is callable from Python (via the magic of ctypes). I succeeded in making a "Hello, world!"-level function and importing it into Python, but ran into difficulty when I tried to add another layer of complexity by adding a prime-finding function, which makes use of primes - outside the Rust standard library. In short, if I run cargo build, then I get the following compilation error:

  --> src/lib.rs:10:5
   |
10 | use primes;
   |     ^^^^^^ no `primes` in the root

Rust Package Structure

The structure of my Rust package is very straightforward:

|__src
|    |__lib.rs
|__Cargo.toml

Code

I thought it might be helpful to show you what the code in this little package looks like.

Cargo.toml

[package]
name = "hosker_primes"
version = "1.0.0"
authors = ["Tom Hosker"]

[lib]
name = "primes_lib"
crate-type = ["dylib"]

[dependencies]
primes = "0.3.0"

src/lib.rs

use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_int;
use std::str;

use primes;

fn main() {
    println!("{}", _find_nth_prime(3));
}

fn _find_nth_prime(n: i32) -> i32 {
    let mut count = 0;
    let mut current = 0;

    while count < n {
        current += 1;

        if primes::is_prime(current) {
            count += 1;
        }
    }

    return current as i32;
}

#[no_mangle]
pub extern "C" fn make_contact(c_string_ptr: *const c_char) {
    let bytes = unsafe { CStr::from_ptr(c_string_ptr).to_bytes() };
    let silly_word = str::from_utf8(bytes).unwrap();

    println!("Congratulations! You have made contact with the PRIMES library.");
    println!("This is the silly word you gave me: {}", silly_word);
}

#[no_mangle]
pub extern "C" fn find_nth_prime(c_int_ptr: *const c_int) -> *const c_int {
    let int_ptr = unsafe { c_int_ptr.as_ref().unwrap() };
    let result = _find_nth_prime(*int_ptr) as *const c_int;

    return result;
}
4
  • I'm not able to reproduce the issue.
    – PitaJ
    Commented Jan 23 at 15:17
  • @PitaJ That's disappointing. Forgive my scepticism, but are you sure you've constructed your package exactly as I have? In particular, are you sure that you've included a lib.rs file and NOT a main.rs, and have you included the dylib stuff in your Cargo.toml?
    – Tom Hosker
    Commented Jan 23 at 15:33
  • @PitaJ I suspect you may have unconsciously added a missing line while attempting to reproduce my issue. See my answer below.
    – Tom Hosker
    Commented Jan 23 at 16:34
  • ot: use primes; is a no-op (aside from failing to compile when there is no crate or module primes, but if you use it at all, that will suffice as well.)
    – cafce25
    Commented Jan 24 at 15:43

1 Answer 1

0

I have found a solution, however:

  1. I discovered it purely by luck, and
  2. I have no idea why it works.

It seems that, if I add the following line to the package section of my Cargo.toml:

edition = "2021"

then everything just works!

Is this perhaps a failure of the Cargo interface? Would it not be more helpful if the user was alerted to the missing field, rather than some weird import issue flaring up further down the line?

3
  • 3
    For compatibility reasons Rust uses edition 2015 by default if you don't specify an explicit edition in your Cargo.toml. In edition 2015, external crates needed to be declared as extern crate primes; in main.rs or lib.rs.
    – Jmb
    Commented Jan 23 at 16:43
  • 2
    Note that if you create a new project with cargo new, it will automatically add the latest edition in the generated Cargo.toml.
    – Jmb
    Commented Jan 23 at 16:44
  • This is documented in more details in the editions guide
    – Jmb
    Commented Jan 23 at 16:47

Not the answer you're looking for? Browse other questions tagged or ask your own question.