如何在Rust中优雅地#include“ gtk-layer-shell.h”

问题描述

我正在尝试在Rust代码中包含一些C ++代码,并且具有以下include语句:

#include "gtk-layer-shell.h"

我在build.rs中指定了文件的位置,但是由于所有的依赖关系,所以有点混乱。我的build.rs看起来像这样:

extern crate cpp_build;

fn main() {
    let include_layer_shell = "/usr/include/gtk-layer-shell";
    let include_gtk = "/usr/include/gtk-3.0";
    let include_glib = "/usr/include/glib-2.0";
    let include_glib_config = "/usr/lib/glib-2.0/include";
    let include_pango = "/usr/include/pango-1.0";
    let include_harfbuzz = "/usr/include/harfbuzz";
    let include_cairo = "/usr/include/cairo";
    let include_gdk_pixbuf = "/usr/include/gdk-pixbuf-2.0";
    let include_atk = "/usr/include/atk-1.0";
    cpp_build::Config::new()
        .include(include_layer_shell)
        .include(include_gtk)
        .include(include_glib)
        .include(include_glib_config)
        .include(include_pango)
        .include(include_harfbuzz)
        .include(include_cairo)
        .include(include_gdk_pixbuf)
        .include(include_atk)
        .build("src/main.rs");
}

有没有一种方法可以更优雅地包含它,仅指定gtk-layer-shell.h的位置,并自动找到所有其他位置?我还希望能够为aarch64交叉编译应用程序。我现在设置的方式我想我必须根据拱形来更改路径,这似乎也有些混乱。

谢谢您的帮助! :)

PS: 我之所以需要C ++代码,基本上只是因为我不知道如何在Rust中编写gtk_layer_init_for_window (gtk_window);,所以如果有人知道如何完全避免使用C ++代码,那会更好! >

解决方法

感谢您的建议,我现在使用gir来生成绑定和安全的Rust包装器。这很容易,但仅适用于GTK相关的事物,并且需要.gir文件。可以在这里找到教程:https://github.com/gtk-rs/gir

在使用bindgen和pkg_config板条箱之前,将build.rs更改为以下内容:

extern crate bindgen;
extern crate pkg_config;

use std::env;
use std::path::PathBuf;

fn main() {
    let library = pkg_config::Config::new()
        .probe("gtk-layer-shell-0")
        .expect("No gtk-layer-shell found on your system");
    let include_paths = library
        .include_paths
        .into_iter()
        .map(|p| p.into_os_string().into_string().unwrap())
        .collect::<Vec<_>>();

    for path in library.link_paths {
        println!("cargo:rustc-link-path={}",path.to_str().unwrap());
    }
    for lib in library.libs {
        println!("cargo:rustc-link-lib={}",lib);
    }

    // Tell cargo to invalidate the built crate whenever the wrapper changes
    println!("cargo:rerun-if-changed=wrapper.h");

    // The bindgen::Builder is the main entry point
    // to bindgen,and lets you build up options for
    // the resulting bindings.
    let mut bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        // Tell cargo to invalidate the built crate whenever any of the
        // included header files changed.
        .parse_callbacks(Box::new(bindgen::CargoCallbacks));

    for path in include_paths {
        bindings = bindings.clang_args(&["-F",&path]);
    }

    let bindings = bindings
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}