1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#![deny(warnings)]
#![allow(non_snake_case, unused_imports, unused_macros)]

//! Dynamically proxy LLVM calls into Rust own shared library! 🎉
//!
//! ## Use cases
//! Normally there is no much need for the crate, except a couple of exotic cases:
//!
//! * Your crate is some kind build process helper that leverages LLVM (e.g. [ptx-linker](https://github.com/denzp/rust-ptx-linker)),
//! * Your crate needs to stay up to date with Rust LLVM version (again [ptx-linker](https://github.com/denzp/rust-ptx-linker)),
//! * You would prefer not to have dependencies on host LLVM libs (as always [ptx-linker](https://github.com/denzp/rust-ptx-linker)).
//!
//! ## Usage
//! First, you need to make sure no other crate links your binary against system LLVM library.
//! In case you are using `llvm-sys`, this can be achieved with a special feature:
//!
//! ``` toml
//! [dependencies.llvm-sys]
//! version = "70"
//! features = ["no-llvm-linking"]
//! ```
//!
//! Then all you need to do is to include the crate into your project:
//!
//! ``` toml
//! [dependencies]
//! rustc-llvm-proxy = "0.1"
//! ```
//!
//! ``` rust
//! extern crate rustc_llvm_proxy;
//! ```

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate failure;

extern crate libc;
extern crate libloading as lib;
extern crate llvm_sys;

use lib::Library;

mod path;
use path::find_lib_path;

pub mod init;

lazy_static! {
    static ref SHARED_LIB: Library = {
        let lib_path = match find_lib_path() {
            Ok(path) => path,

            Err(error) => {
                eprintln!("{}", error);
                panic!();
            }
        };

        match Library::new(lib_path) {
            Ok(path) => path,

            Err(error) => {
                eprintln!("Unable to open LLVM shared lib: {}", error);
                panic!();
            }
        }
    };
}

/// Commonly used LLVM CAPI symbols with dynamic resolving
pub mod proxy {
    use super::SHARED_LIB;

    use llvm_sys::analysis::*;
    use llvm_sys::debuginfo::*;
    use llvm_sys::disassembler::*;
    use llvm_sys::error::*;
    use llvm_sys::error_handling::*;
    use llvm_sys::execution_engine::*;
    use llvm_sys::link_time_optimizer::*;
    use llvm_sys::lto::*;
    use llvm_sys::object::*;
    use llvm_sys::orc::*;
    use llvm_sys::prelude::*;
    use llvm_sys::target::*;
    use llvm_sys::target_machine::*;
    use llvm_sys::transforms::pass_manager_builder::*;
    use llvm_sys::*;

    macro_rules! create_proxy {
        ($name:ident ; $ret_ty:ty ; $($arg:ident : $arg_ty:ty),*) => {
            #[no_mangle]
            pub unsafe extern "C" fn $name($($arg: $arg_ty),*) -> $ret_ty {
                let entrypoint = {
                    SHARED_LIB
                        .get::<unsafe extern "C" fn($($arg: $arg_ty),*) -> $ret_ty>(stringify!($name).as_bytes())
                };

                match entrypoint {
                    Ok(entrypoint) => entrypoint($($arg),*),

                    Err(_) => {
                        eprintln!("Unable to find symbol '{}' in the LLVM shared lib", stringify!($name));
                        panic!();
                    }
                }
            }
        };
    }

    include!(concat!(env!("OUT_DIR"), "/llvm_gen.rs"));
}