try to use in-memory files in linux

This commit is contained in:
Folkert 2022-05-22 13:17:30 +02:00
parent e81875cca7
commit d4e475338d
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C

View file

@ -5,13 +5,14 @@ use build::BuiltFile;
use bumpalo::Bump; use bumpalo::Bump;
use clap::{Arg, ArgMatches, Command}; use clap::{Arg, ArgMatches, Command};
use roc_build::link::LinkType; use roc_build::link::LinkType;
use roc_error_macros::user_error; use roc_error_macros::{internal_error, user_error};
use roc_load::{LoadingProblem, Threading}; use roc_load::{LoadingProblem, Threading};
use roc_mono::ir::OptLevel; use roc_mono::ir::OptLevel;
use std::env; use std::env;
use std::ffi::{CString, OsStr}; use std::ffi::{CString, OsStr};
use std::io; use std::io::{self, Write};
use std::path::Path; use std::os::unix::prelude::FromRawFd;
use std::path::{Path, PathBuf};
use std::process; use std::process;
use target_lexicon::BinaryFormat; use target_lexicon::BinaryFormat;
use target_lexicon::{ use target_lexicon::{
@ -160,6 +161,14 @@ pub fn build_app<'a>() -> Command<'a> {
) )
.subcommand(Command::new(CMD_RUN) .subcommand(Command::new(CMD_RUN)
.about("Run a .roc file even if it has build errors") .about("Run a .roc file even if it has build errors")
.arg(
Arg::new(FLAG_TARGET)
.long(FLAG_TARGET)
.help("Choose a different target")
.default_value(Target::default().as_str())
.possible_values(Target::OPTIONS)
.required(false),
)
.arg(flag_optimize.clone()) .arg(flag_optimize.clone())
.arg(flag_max_threads.clone()) .arg(flag_max_threads.clone())
.arg(flag_opt_size.clone()) .arg(flag_opt_size.clone())
@ -504,35 +513,35 @@ fn roc_run<'a, I: IntoIterator<Item = &'a OsStr>>(
) -> io::Result<i32> { ) -> io::Result<i32> {
match triple.architecture { match triple.architecture {
Architecture::Wasm32 => { Architecture::Wasm32 => {
todo!("figure out what to do with wasm"); let path = roc_run_executable_file_path(cwd, binary_bytes)?;
// // If possible, report the generated executable name relative to the current dir. // If possible, report the generated executable name relative to the current dir.
// let generated_filename = binary_bytes let generated_filename = path
// .strip_prefix(env::current_dir().unwrap()) .strip_prefix(env::current_dir().unwrap())
// .unwrap_or(binary_bytes); .unwrap_or(&path);
//
// // No need to waste time freeing this memory, // No need to waste time freeing this memory,
// // since the process is about to exit anyway. // since the process is about to exit anyway.
// std::mem::forget(arena); std::mem::forget(arena);
//
// if cfg!(target_family = "unix") { if cfg!(target_family = "unix") {
// use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
//
// run_with_wasmer( run_with_wasmer(
// generated_filename, generated_filename,
// args.into_iter().map(|os_str| os_str.as_bytes()), args.into_iter().map(|os_str| os_str.as_bytes()),
// ); );
// } else { } else {
// run_with_wasmer( run_with_wasmer(
// generated_filename, generated_filename,
// args.into_iter().map(|os_str| { args.into_iter().map(|os_str| {
// os_str.to_str().expect( os_str.to_str().expect(
// "Roc does not currently support passing non-UTF8 arguments to Wasmer.", "Roc does not currently support passing non-UTF8 arguments to Wasmer.",
// ) )
// }), }),
// ); );
// } }
//
// Ok(0) Ok(0)
} }
_ => { _ => {
if cfg!(target_family = "unix") { if cfg!(target_family = "unix") {
@ -546,38 +555,75 @@ fn roc_run<'a, I: IntoIterator<Item = &'a OsStr>>(
fn roc_run_unix<I: IntoIterator<Item = S>, S: AsRef<OsStr>>( fn roc_run_unix<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
cwd: &Path, cwd: &Path,
args: I, _args: I,
binary_bytes: &mut [u8], binary_bytes: &mut [u8],
) -> ! { ) -> std::io::Result<i32> {
use std::os::unix::ffi::OsStrExt;
unsafe { unsafe {
let flags = 0; let path = roc_run_executable_file_path(cwd, binary_bytes)?;
let fd = libc::memfd_create("roc_file_descriptor\0".as_ptr().cast(), flags); let path_cstring = CString::new(path.as_os_str().as_bytes()).unwrap();
libc::write(fd, binary_bytes.as_ptr().cast(), binary_bytes.len());
// use std::path::PathBuf;
let path = format!("/proc/self/fd/{}\0", fd);
let array_with_null_pointer = &[0usize]; let array_with_null_pointer = &[0usize];
let c = libc::execve( let execve_result = libc::execve(
path.as_ptr().cast(), path_cstring.as_ptr().cast(),
array_with_null_pointer.as_ptr().cast(), array_with_null_pointer.as_ptr().cast(),
array_with_null_pointer.as_ptr().cast(), array_with_null_pointer.as_ptr().cast(),
); );
// Get the current value of errno if execve_result != 0 {
let e = errno::errno(); internal_error!(
"libc::execve({:?}, ..., ...) failed: {:?}",
// Extract the error code as an i32 path,
let code = e.0; errno::errno()
);
// Display a human-friendly error message }
println!("Error {}: {}", code, e);
println!("after {:?}", c);
} }
unreachable!() Ok(1)
}
fn roc_run_executable_file_path(cwd: &Path, binary_bytes: &mut [u8]) -> std::io::Result<PathBuf> {
if cfg!(target_os = "linux") {
// on linux, we use the `memfd_create` function to create an in-memory anonymous file.
let flags = 0;
let anonymous_file_name = "roc_file_descriptor\0";
let fd = unsafe { libc::memfd_create(anonymous_file_name.as_ptr().cast(), flags) };
if fd == 0 {
internal_error!(
"libc::memfd_create({:?}, {}) failed: file descriptor is 0",
anonymous_file_name,
flags
);
}
// NOTE: this `fd` is special, using the rust `std::fs::File` functions does not work
let write_result =
unsafe { libc::write(fd, binary_bytes.as_ptr().cast(), binary_bytes.len()) };
if write_result != 0 {
internal_error!(
"libc::write({:?}, ..., {}) failed: {:?}",
fd,
binary_bytes.len(),
errno::errno()
);
}
let path = format!("/proc/self/fd/{}", fd);
Ok(PathBuf::from(path))
} else {
// we have not found a way yet to use a virtual file on MacOs. Hence we fall back to just
// writing the file to the file system, and using that file.
let app_path_buf = cwd.join("roc_app_binary");
std::fs::write(&app_path_buf, binary_bytes)?;
Ok(app_path_buf)
}
} }
fn roc_run_non_unix<I: IntoIterator<Item = S>, S: AsRef<OsStr>>( fn roc_run_non_unix<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(