| use crate::common::*; |
| |
| const INCLUDE_DIRS: &[&str] = &["libffi", "libffi/include", "include/msvc"]; |
| |
| // libffi expects us to include the same folder in case of x86 and x86_64 architectures |
| const INCLUDE_DIRS_X86: &[&str] = &["libffi/src/x86"]; |
| const INCLUDE_DIRS_X86_64: &[&str] = &["libffi/src/x86"]; |
| const INCLUDE_DIRS_AARCH64: &[&str] = &["libffi/src/aarch64"]; |
| |
| const BUILD_FILES: &[&str] = &[ |
| "tramp.c", |
| "closures.c", |
| "prep_cif.c", |
| "raw_api.c", |
| "types.c", |
| ]; |
| const BUILD_FILES_X86: &[&str] = &["x86/ffi.c"]; |
| const BUILD_FILES_X86_64: &[&str] = &["x86/ffi.c", "x86/ffiw64.c"]; |
| const BUILD_FILES_AARCH64: &[&str] = &["aarch64/ffi.c"]; |
| |
| fn add_file(build: &mut cc::Build, file: &str) { |
| build.file(format!("libffi/src/{}", file)); |
| } |
| |
| fn unsupported(arch: &str) -> ! { |
| panic!("Unsupported architecture: {}", arch) |
| } |
| |
| pub fn build_and_link() { |
| let target = env::var("TARGET").unwrap(); |
| let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); |
| |
| // we should collect all include dirs together with platform specific ones |
| // to pass them over to the asm pre-processing step |
| let mut all_includes = vec![]; |
| for each_include in INCLUDE_DIRS { |
| all_includes.push(*each_include); |
| } |
| for each_include in match target_arch.as_str() { |
| "x86" => INCLUDE_DIRS_X86, |
| "x86_64" => INCLUDE_DIRS_X86_64, |
| "aarch64" => INCLUDE_DIRS_AARCH64, |
| _ => unsupported(&target_arch), |
| } { |
| all_includes.push(*each_include); |
| } |
| |
| let asm_path = pre_process_asm(all_includes.as_slice(), &target, &target_arch); |
| let mut build = cc::Build::new(); |
| |
| for each_include in all_includes { |
| build.include(each_include); |
| } |
| |
| for each_source in BUILD_FILES { |
| add_file(&mut build, each_source); |
| } |
| for each_source in match target_arch.as_str() { |
| "x86" => BUILD_FILES_X86, |
| "x86_64" => BUILD_FILES_X86_64, |
| "aarch64" => BUILD_FILES_AARCH64, |
| _ => unsupported(&target_arch), |
| } { |
| add_file(&mut build, each_source); |
| } |
| |
| build |
| .file(asm_path) |
| .define("WIN32", None) |
| .define("_LIB", None) |
| .define("FFI_BUILDING", None) |
| .warnings(false) |
| .compile("libffi"); |
| } |
| |
| pub fn probe_and_link() { |
| // At the time of writing it wasn't clear if MSVC builds will support |
| // dynamic linking of libffi; assuming it's even installed. To ensure |
| // existing MSVC setups continue to work, we just compile libffi from source |
| // and statically link it. |
| build_and_link(); |
| } |
| |
| pub fn pre_process_asm(include_dirs: &[&str], target: &str, target_arch: &str) -> String { |
| let folder_name = match target_arch { |
| "x86" => "x86", |
| "x86_64" => "x86", |
| "aarch64" => "aarch64", |
| _ => unsupported(target_arch), |
| }; |
| |
| let file_name = match target_arch { |
| "x86" => "sysv_intel", |
| "x86_64" => "win64_intel", |
| "aarch64" => "win64_armasm", |
| _ => unsupported(target_arch), |
| }; |
| |
| let mut cmd = cc::windows_registry::find(target, "cl.exe").expect("Could not locate cl.exe"); |
| |
| // When cross-compiling we should provide MSVC includes as part of the INCLUDE env.var |
| let build = cc::Build::new(); |
| for (key, value) in build.get_compiler().env() { |
| if key.to_string_lossy() == "INCLUDE" { |
| cmd.env( |
| "INCLUDE", |
| format!("{};{}", value.to_string_lossy(), include_dirs.join(";")), |
| ); |
| } |
| } |
| |
| cmd.arg("/EP"); |
| cmd.arg(format!("libffi/src/{}/{}.S", folder_name, file_name)); |
| |
| let out_path = format!("libffi/src/{}/{}.asm", folder_name, file_name); |
| let asm_file = fs::File::create(&out_path).expect("Could not create output file"); |
| |
| cmd.stdout(asm_file); |
| |
| run_command("Pre-process ASM", &mut cmd); |
| |
| out_path |
| } |