aya_rustc_llvm_proxy/
lib.rs

1#![deny(warnings)]
2#![allow(
3    non_snake_case,
4    unused_imports,
5    unused_macros,
6    deprecated,
7    clippy::missing_safety_doc
8)]
9
10//! This is a **fork** of the [rustc-llvm-proxy](https://github.com/denzp/rustc-llvm-proxy) crate.
11//!
12//! Dynamically proxy LLVM calls into Rust own shared library! 🎉
13//!
14//! ## Use cases
15//! Normally there is no much need for the crate, except a couple of exotic cases:
16//!
17//! * Your crate is some kind build process helper that leverages LLVM (e.g. [bpf-linker](https://github.com/aya-rs/bpf-linker)),
18//! * Your crate needs to stay up to date with Rust LLVM version (again [bpf-linker](https://github.com/aya-rs/bpf-linker)),
19//! * You would prefer not to have dependencies on host LLVM libs (as always [bpf-linker](https://github.com/aya-rs/bpf-linker)).
20//!
21//! ## Usage
22//! First, you need to make sure no other crate links your binary against system LLVM library.
23//! In case you are using `llvm-sys`, this can be achieved with a special feature:
24//!
25//! ``` toml
26//! [dependencies.llvm-sys]
27//! version = "70"
28//! features = ["no-llvm-linking"]
29//! ```
30//!
31//! Then all you need to do is to include the crate into your project:
32//!
33//! ``` toml
34//! [dependencies]
35//! rustc-llvm-proxy = "0.4"
36//! ```
37//!
38//! ``` rust
39//! extern crate aya_rustc_llvm_proxy;
40//! ```
41
42use libloading::Library;
43
44pub mod init;
45
46static SHARED_LIB: std::sync::LazyLock<Library> = std::sync::LazyLock::new(|| {
47    for (var, is_bin) in [
48        ("LD_LIBRARY_PATH", false),
49        ("DYLD_FALLBACK_LIBRARY_PATH", false),
50        ("PATH", true),
51    ] {
52        let Some(unparsed) = std::env::var_os(var) else {
53            continue;
54        };
55        let paths = std::env::split_paths(&unparsed);
56        for mut path in paths {
57            if is_bin {
58                path.pop();
59                path.push("lib");
60            }
61            let files = match path.read_dir() {
62                Ok(files) => files,
63                Err(err) => {
64                    eprintln!("unable to read dir {}: {}", path.display(), err);
65                    continue;
66                }
67            };
68            for (i, file) in files.enumerate() {
69                let file = match file {
70                    Ok(file) => file,
71                    Err(err) => {
72                        eprintln!(
73                            "unable to read dir entry {} in {}: {}",
74                            i,
75                            path.display(),
76                            err
77                        );
78                        continue;
79                    }
80                };
81                let path = file.path();
82                let Some(stem) = path.file_stem() else {
83                    continue;
84                };
85                let Some(stem) = stem.to_str() else { continue };
86                if stem.starts_with("libLLVM") {
87                    match unsafe { Library::new(&path) } {
88                        Ok(library) => return library,
89                        Err(error) => {
90                            eprintln!(
91                                "unable to open LLVM shared lib {}: {}",
92                                path.display(),
93                                error
94                            );
95                            continue;
96                        }
97                    }
98                }
99            }
100        }
101    }
102    panic!("unable to find LLVM shared lib")
103});
104
105/// LLVM C-API symbols with dynamic resolving.
106pub mod proxy {
107    use super::SHARED_LIB;
108
109    include!(concat!(env!("OUT_DIR"), "/llvm_gen.rs"));
110}