Can't link to the harfbuzz dynamic library with Rust FFI

351 views Asked by At

I want to use a Rust file main.rs to bind a C file src/c_ffi/myharfbuzz.c that links a dynamic library (for example hb.h and hb-ot.h). When I compile it with cargo run, it shows the error:

/usr/bin/ld: .../target/debug/build/uahji2-109ed7d174e31932/out/libmyharfbuzz.a(myharfbuzz.o): in function `example':
.../src/c_ffi/myharfbuzz.c:18: undefined reference to `hb_blob_create_from_file'
      /usr/bin/ld: .../src/c_ffi/myharfbuzz.c:19: undefined reference to `hb_face_create'
      /usr/bin/ld: .../src/c_ffi/myharfbuzz.c:21: undefined reference to `hb_ot_var_get_axis_count'
      /usr/bin/ld: .../src/c_ffi/myharfbuzz.c:22: undefined reference to `hb_ot_var_get_axis_infos'

It seems that ld can't find the dynamic library hb.h

Here are my files:

src/main.rs

use std::ffi::CString;
use std::os::raw::c_char;

#[link(name = "myharfbuzz")]
extern "C" {
    fn example(s: *const std::os::raw::c_char, a: i32, b: i32);
}

fn main() {
    let prompt = CString::new("Rust").unwrap();

    unsafe {
        example(prompt.as_ptr(), 7, 11);
    }
}

src/c_ffi/myharfbuzz.c

#include <stdint.h>
#include <stdio.h>
#include <hb.h>
#include <hb-ot.h>
#include <stdint.h>



void example(int32_t a, int32_t b){
printf("%d + %d = %d\n", a, b, a + b);

char *filename = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc";
printf("%s", filename);

hb_blob_t *blob = hb_blob_create_from_file(filename);
hb_face_t *face = hb_face_create(blob, 0);
hb_ot_var_axis_info_t *axes_array;
int axes = hb_ot_var_get_axis_count(face);
hb_ot_var_get_axis_infos(face, 0, &axes, axes_array);
printf("%d", axes_array);
}

In my build.rs the include path was set, but ld emitted the linking error:

use std::env;
use std::path::Path;
extern crate pkg_config;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    println!("OUT_DIR = {:?}", out_dir);
    let harfbuzz_config = pkg_config::Config::new().probe("harfbuzz").unwrap();
    println!("{:?}", harfbuzz_config);

    let linked_path = harfbuzz_config.link_paths[0].clone();

    let mut builder = cc::Build::new();
    builder
        .files(&["src/c_ffi/myharfbuzz.c"])
        .includes(harfbuzz_config.include_paths)
        .includes(harfbuzz_config.link_paths)
        .flag(&format!("-lharfbuzz"))
        .compile(&format!("myharfbuzz"));

    println!("cargo:rerun-if-changed=build.rs");

    println!("cargo:rustc-link-search=native={:?}", linked_path);
    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=static=myharfbuzz");
}
1

There are 1 answers

0
Kornel On

Linking with #[link] directive is unlikely to work, because Rust will not put any effort into searching where the given library is installed.

For linking with C/system dependencies you should be using sys crates. There is harfbuzz-sys.