blob: 51dba9f58b7419a5c2f2d7834a7ba8b4d7f6b944 [file] [log] [blame] [edit]
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
}