diff --git a/bindings/rust/evmc-client/Cargo.toml b/bindings/rust/evmc-client/Cargo.toml index 63e7abae3..ad4f82e91 100644 --- a/bindings/rust/evmc-client/Cargo.toml +++ b/bindings/rust/evmc-client/Cargo.toml @@ -10,9 +10,14 @@ license = "Apache-2.0" repository = "https://github.com/ethereum/evmc" description = "Bindings to EVMC (Client/Host specific)" edition = "2018" +build = "build.rs" [dependencies] -evmc-sys = { path = "../evmc-sys", version = "7.4.0" } -evmc-vm = { path = "../evmc-vm", version = "7.4.0" } -libloading = "0.5" +evmc-sys = { path = "../evmc-sys" } +evmc-vm = { path = "../evmc-vm" } +enum_primitive = "0.1.1" +num = "0.3" lazy_static = "1.4.0" + +[build-dependencies] +cmake = "0.1.44" diff --git a/bindings/rust/evmc-client/build.rs b/bindings/rust/evmc-client/build.rs new file mode 100644 index 000000000..07b68b437 --- /dev/null +++ b/bindings/rust/evmc-client/build.rs @@ -0,0 +1,30 @@ +// Copyright (C) 2020 Second State. +// This file is part of EVMC-Client. + +// EVMC-Client is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. + +// EVMC-Client is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use std::path::Path; +extern crate cmake; +use cmake::Config; + +fn build_link_evmc_tools() { + let dst = Config::new("../../../").build(); + let evmc_path = Path::new(&dst).join("build/lib/loader"); + println!("cargo:rustc-link-search=native={}", evmc_path.display()); + println!("cargo:rustc-link-lib=static=evmc-loader"); +} + +fn main() { + build_link_evmc_tools(); +} diff --git a/bindings/rust/evmc-client/src/lib.rs b/bindings/rust/evmc-client/src/lib.rs index c1f895805..c71a5ebf1 100644 --- a/bindings/rust/evmc-client/src/lib.rs +++ b/bindings/rust/evmc-client/src/lib.rs @@ -3,11 +3,12 @@ * Licensed under the Apache License, Version 2.0. */ +#[macro_use] +extern crate enum_primitive; pub mod host; mod loader; pub mod types; -pub use self::loader::EvmcLoaderErrorCode; -use crate::loader::evmc_load_and_create; +pub use crate::loader::{load_and_create, EvmcLoaderErrorCode}; use crate::types::*; use evmc_sys as ffi; use std::ffi::CStr; @@ -16,26 +17,6 @@ extern "C" { fn evmc_create() -> *mut ffi::evmc_vm; } -fn error(err: EvmcLoaderErrorCode) -> Result { - match err { - EvmcLoaderErrorCode::EvmcLoaderSucces => Ok(EvmcLoaderErrorCode::EvmcLoaderSucces), - EvmcLoaderErrorCode::EvmcLoaderCannotOpen => Err("evmc loader: library cannot open"), - EvmcLoaderErrorCode::EvmcLoaderSymbolNotFound => { - Err("evmc loader: the EVMC create function not found") - } - EvmcLoaderErrorCode::EvmcLoaderInvalidArgument => { - panic!("evmc loader: filename argument is invalid") - } - EvmcLoaderErrorCode::EvmcLoaderInstanceCreationFailure => { - Err("evmc loader: VM instance creation failure") - } - EvmcLoaderErrorCode::EvmcLoaderAbiVersionMismatch => { - Err("evmc loader: ABI version mismatch") - } - _ => Err("evmc loader: unexpected error"), - } -} - pub struct EvmcVm { handle: *mut ffi::evmc_vm, host_interface: *mut ffi::evmc_host_interface, @@ -141,13 +122,13 @@ impl EvmcVm { } pub fn load(fname: &str) -> (EvmcVm, Result) { - let (instance, ec) = evmc_load_and_create(fname); + let (instance, ec) = load_and_create(fname); ( EvmcVm { handle: instance, host_interface: Box::into_raw(Box::new(host::get_evmc_host_interface())), }, - error(ec), + ec, ) } diff --git a/bindings/rust/evmc-client/src/loader.rs b/bindings/rust/evmc-client/src/loader.rs index 0bba06c9a..757b97675 100644 --- a/bindings/rust/evmc-client/src/loader.rs +++ b/bindings/rust/evmc-client/src/loader.rs @@ -4,12 +4,22 @@ */ use evmc_sys as ffi; -use libloading::{Library, Symbol}; -use std::ptr; +use std::ffi::{CStr, CString}; +use std::os::raw::c_char; use std::str; +extern crate num; +use num::FromPrimitive; + +#[link(name = "evmc-loader")] +extern "C" { + fn evmc_load_and_create( + filename: *const c_char, + evmc_loader_error_code: *mut i32, + ) -> *mut ffi::evmc_vm; + fn evmc_last_error_msg() -> *const c_char; +} -type EvmcCreate = extern "C" fn() -> *mut ffi::evmc_vm; - +enum_from_primitive! { #[derive(Debug)] pub enum EvmcLoaderErrorCode { /** The loader succeeded. */ @@ -36,39 +46,28 @@ pub enum EvmcLoaderErrorCode { /** The VM option value is invalid. */ EvmcLoaderInvalidOptionValue = 7, } +} -pub fn evmc_load_and_create(fname: &str) -> (*mut ffi::evmc_vm, EvmcLoaderErrorCode) { - unsafe { - let mut instance: *mut ffi::evmc_vm = ptr::null_mut(); - - let library: Library = match Library::new(fname) { - Ok(lib) => lib, - Err(_) => { - return (instance, EvmcLoaderErrorCode::EvmcLoaderCannotOpen); - } - }; - - let evmc_create_fn: Symbol = match library.get(b"evmc_create\0") { - Ok(symbol) => symbol, - Err(_) => { - return (instance, EvmcLoaderErrorCode::EvmcLoaderSymbolNotFound); - } - }; - - instance = evmc_create_fn(); - - if instance.is_null() { - return ( - instance, - EvmcLoaderErrorCode::EvmcLoaderInstanceCreationFailure, - ); - } +fn error(err: EvmcLoaderErrorCode) -> Result { + match err { + EvmcLoaderErrorCode::EvmcLoaderSucces => Ok(EvmcLoaderErrorCode::EvmcLoaderSucces), + _ => unsafe { Err(CStr::from_ptr(evmc_last_error_msg()).to_str().unwrap()) }, + } +} - if (*instance).abi_version - != std::mem::transmute::(ffi::EVMC_ABI_VERSION) - { - return (instance, EvmcLoaderErrorCode::EvmcLoaderAbiVersionMismatch); - } - return (instance, EvmcLoaderErrorCode::EvmcLoaderSucces); +pub fn load_and_create( + fname: &str, +) -> ( + *mut ffi::evmc_vm, + Result, +) { + let c_str = CString::new(fname).unwrap(); + unsafe { + let mut error_code: i32 = 0; + let instance = evmc_load_and_create(c_str.as_ptr() as *const c_char, &mut error_code); + return ( + instance, + error(EvmcLoaderErrorCode::from_i32(error_code).unwrap()), + ); } }