Merge pull request #2610 from rtfeldman/windows_fixes

`cargo build` on windows
This commit is contained in:
Richard Feldman 2022-03-02 18:20:06 -05:00 committed by GitHub
commit d91df42147
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 142 additions and 67 deletions

View file

@ -196,20 +196,24 @@ export CPPFLAGS="-I/usr/local/opt/llvm/include"
### LLVM installation on Windows ### LLVM installation on Windows
Installing LLVM's prebuilt binaries doesn't seem to be enough for the `llvm-sys` crate that Roc depends on, so I had to build LLVM from source **Warning** While `cargo build` works on windows, linking roc programs does not yet, see issue #2608. This also means the repl, the editor and many tests will not work on windows.
on Windows. After lots of help from [**@IanMacKenzie**](https://github.com/IanMacKenzie) (thank you, Ian!), here's what worked for me: Installing LLVM's prebuilt binaries doesn't seem to be enough for the `llvm-sys` crate that Roc depends on, so I had to follow the steps below:
1. I downloaded and installed [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16) (a full Visual Studio install should work tool; the Build Tools are just the CLI tools, which is all I wanted) 1. I downloaded and installed [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16) (a full Visual Studio install should work too; the Build Tools are just the CLI tools, which is all I wanted)
1. In the installation configuration, under "additional components" I had to check both "C++ ATL for latest v142 build tools (x86 & x64)" and also "C++/CLI support for v142 build tools" [note: as of September 2021 this should no longer be necessary - the next time anyone tries this, please try it without this step and make a PR to delete this step if it's no longer needed!] 1. Download the custom LLVM 7z archive [here](https://github.com/PLC-lang/llvm-package-windows/releases/tag/v12.0.1).
1. I launched the "x64 Native Tools Command Prompt for Visual Studio 2019" application (note: not the similarly-named "x86" one!) 1. [Download 7-zip](https://www.7-zip.org/) to be able to extract this archive.
1. Make sure [Python 2.7](https://www.python.org/) and [CMake 3.17](http://cmake.org/) are installed on your system. 1. Extract the 7z file to where you want to permanently keep the folder.
1. I followed most of the steps under LLVM's [building from source instructions](https://github.com/llvm/llvm-project#getting-the-source-code-and-building-llvm) up to the `cmake -G ...` command, which didn't work for me. Instead, at that point I did the following step. 1. In powershell, set the `LLVM_SYS_120_PREFIX` environment variable (check [here](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.2#saving-changes-to-environment-variables) to make this a permanent environment variable):
1. I ran `cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release ../llvm` to generate a NMake makefile. ```
1. Once that completed, I ran `nmake` to build LLVM. (This took about 2 hours on my laptop.) [Environment]::SetEnvironmentVariable(
1. Finally, I set an environment variable `LLVM_SYS_100_PREFIX` to point to the `build` directory where I ran the `cmake` command. "Path",
[Environment]::GetEnvironmentVariable("Path", "User") + ";C:\Users\anton\Downloads\LLVM-12.0.1-win64\bin",
"User"
)
```
Once all that was done, `cargo` ran successfully for Roc! Once all that was done, `cargo build` ran successfully for Roc!
### Build speed on WSL/WSL2 ### Build speed on WSL/WSL2

20
Cargo.lock generated
View file

@ -1222,7 +1222,7 @@ checksum = "1d428afc93ad288f6dffc1fa5f4a78201ad2eec33c5a522e51c181009eb09061"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"dynasm", "dynasm",
"memmap2 0.5.0", "memmap2 0.5.3",
] ]
[[package]] [[package]]
@ -2095,9 +2095,9 @@ dependencies = [
[[package]] [[package]]
name = "memmap2" name = "memmap2"
version = "0.5.0" version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4647a11b578fead29cdbb34d4adef8dd3dc35b876c9c6d5240d83f205abfe96e" checksum = "057a3db23999c867821a7a59feb06a578fcb03685e983dff90daf9e7d24ac08f"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@ -3286,6 +3286,7 @@ dependencies = [
"roc_unify", "roc_unify",
"snafu", "snafu",
"ven_graph", "ven_graph",
"winapi",
] ]
[[package]] [[package]]
@ -3594,7 +3595,7 @@ dependencies = [
"bumpalo", "bumpalo",
"clap 3.0.0-beta.5", "clap 3.0.0-beta.5",
"iced-x86", "iced-x86",
"memmap2 0.5.0", "memmap2 0.5.3",
"object 0.26.2", "object 0.26.2",
"roc_build", "roc_build",
"roc_collections", "roc_collections",
@ -3822,13 +3823,6 @@ dependencies = [
[[package]] [[package]]
name = "roc_std" name = "roc_std"
version = "0.1.0" version = "0.1.0"
dependencies = [
"indoc",
"libc",
"pretty_assertions",
"quickcheck",
"quickcheck_macros",
]
[[package]] [[package]]
name = "roc_target" name = "roc_target"
@ -3927,7 +3921,7 @@ checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
[[package]] [[package]]
name = "rustyline" name = "rustyline"
version = "9.1.1" version = "9.1.1"
source = "git+https://github.com/rtfeldman/rustyline?tag=v9.1.1#7053ae0fe0ee710d38ed5845dd979113382994dc" source = "git+https://github.com/rtfeldman/rustyline?rev=e74333c#e74333c0d618896b88175bf06645108f996fe6d0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if 1.0.0", "cfg-if 1.0.0",
@ -3950,7 +3944,7 @@ dependencies = [
[[package]] [[package]]
name = "rustyline-derive" name = "rustyline-derive"
version = "0.6.0" version = "0.6.0"
source = "git+https://github.com/rtfeldman/rustyline?tag=v9.1.1#7053ae0fe0ee710d38ed5845dd979113382994dc" source = "git+https://github.com/rtfeldman/rustyline?rev=e74333c#e74333c0d618896b88175bf06645108f996fe6d0"
dependencies = [ dependencies = [
"quote", "quote",
"syn", "syn",

View file

@ -38,7 +38,6 @@ members = [
"repl_eval", "repl_eval",
"repl_test", "repl_test",
"repl_wasm", "repl_wasm",
"roc_std",
"test_utils", "test_utils",
"utils", "utils",
"docs", "docs",
@ -50,6 +49,8 @@ exclude = [
# The tests will still correctly build them. # The tests will still correctly build them.
"cli_utils", "cli_utils",
"compiler/test_mono_macros", "compiler/test_mono_macros",
# `cargo build` would cause roc_std to be built with default features which errors on windows
"roc_std",
] ]
# Needed to be able to run `cargo run -p roc_cli --no-default-features` - # Needed to be able to run `cargo run -p roc_cli --no-default-features` -
# see www/build.sh for more. # see www/build.sh for more.

View file

@ -21,10 +21,14 @@ roc_target = { path = "../compiler/roc_target" }
roc_error_macros = { path = "../error_macros" } roc_error_macros = { path = "../error_macros" }
arrayvec = "0.7.2" arrayvec = "0.7.2"
bumpalo = { version = "3.8.0", features = ["collections"] } bumpalo = { version = "3.8.0", features = ["collections"] }
libc = "0.2.106"
page_size = "0.4.2" page_size = "0.4.2"
snafu = { version = "0.6.10", features = ["backtraces"] } snafu = { version = "0.6.10", features = ["backtraces"] }
ven_graph = { path = "../vendor/pathfinding" } ven_graph = { path = "../vendor/pathfinding" }
libc = "0.2.106"
[dev-dependencies] [dev-dependencies]
indoc = "1.0.3" indoc = "1.0.3"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.9", features = ["memoryapi"]}

View file

@ -10,12 +10,10 @@
/// ///
/// Pages also use the node value 0 (all 0 bits) to mark nodes as unoccupied. /// Pages also use the node value 0 (all 0 bits) to mark nodes as unoccupied.
/// This is important for performance. /// This is important for performance.
use libc::{MAP_ANONYMOUS, MAP_PRIVATE, PROT_READ, PROT_WRITE};
use std::any::type_name; use std::any::type_name;
use std::ffi::c_void; use std::ffi::c_void;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::{align_of, size_of, MaybeUninit}; use std::mem::{align_of, size_of, MaybeUninit};
use std::ptr::null;
pub const NODE_BYTES: usize = 32; pub const NODE_BYTES: usize = 32;
@ -108,14 +106,32 @@ impl Pool {
// addresses from the OS which will be lazily translated into // addresses from the OS which will be lazily translated into
// physical memory one 4096-byte page at a time, once we actually // physical memory one 4096-byte page at a time, once we actually
// try to read or write in that page's address range. // try to read or write in that page's address range.
libc::mmap( #[cfg(unix)]
null::<c_void>() as *mut c_void, {
bytes_to_mmap, use libc::{MAP_ANONYMOUS, MAP_PRIVATE, PROT_READ, PROT_WRITE};
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, libc::mmap(
0, std::ptr::null_mut(),
0, bytes_to_mmap,
) PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
0,
0,
)
}
#[cfg(windows)]
{
use winapi::um::memoryapi::VirtualAlloc;
use winapi::um::winnt::PAGE_READWRITE;
use winapi::um::winnt::{MEM_COMMIT, MEM_RESERVE};
VirtualAlloc(
std::ptr::null_mut(),
bytes_to_mmap,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE,
)
}
} as *mut [MaybeUninit<u8>; NODE_BYTES]; } as *mut [MaybeUninit<u8>; NODE_BYTES];
// This is our actual capacity, in nodes. // This is our actual capacity, in nodes.
@ -230,10 +246,24 @@ impl<T> std::ops::IndexMut<NodeId<T>> for Pool {
impl Drop for Pool { impl Drop for Pool {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
libc::munmap( #[cfg(unix)]
self.nodes as *mut c_void, {
NODE_BYTES * self.capacity as usize, libc::munmap(
); self.nodes as *mut c_void,
NODE_BYTES * self.capacity as usize,
);
}
#[cfg(windows)]
{
use winapi::um::memoryapi::VirtualFree;
use winapi::um::winnt::MEM_RELEASE;
VirtualFree(
self.nodes as *mut c_void,
NODE_BYTES * self.capacity as usize,
MEM_RELEASE,
);
}
} }
} }
} }

View file

@ -20,4 +20,6 @@ serde = { version = "1.0.130", features = ["derive"] }
serde-xml-rs = "0.5.1" serde-xml-rs = "0.5.1"
strip-ansi-escapes = "0.1.1" strip-ansi-escapes = "0.1.1"
tempfile = "3.2.0" tempfile = "3.2.0"
[target.'cfg(unix)'.dependencies]
rlimit = "0.6.2" rlimit = "0.6.2"

View file

@ -1,11 +1,12 @@
use crate::helpers::{example_file, run_cmd, run_roc}; use crate::helpers::{example_file, run_cmd, run_roc};
use criterion::{black_box, measurement::Measurement, BenchmarkGroup}; use criterion::{black_box, measurement::Measurement, BenchmarkGroup};
use rlimit::{setrlimit, Resource}; use std::{path::Path, thread};
use std::path::Path;
const CFOLD_STACK_SIZE: usize = 8192 * 100000;
fn exec_bench_w_input<T: Measurement>( fn exec_bench_w_input<T: Measurement>(
file: &Path, file: &Path,
stdin_str: &str, stdin_str: &'static str,
executable_filename: &str, executable_filename: &str,
expected_ending: &str, expected_ending: &str,
bench_group_opt: Option<&mut BenchmarkGroup<T>>, bench_group_opt: Option<&mut BenchmarkGroup<T>>,
@ -31,7 +32,7 @@ fn exec_bench_w_input<T: Measurement>(
fn check_cmd_output( fn check_cmd_output(
file: &Path, file: &Path,
stdin_str: &str, stdin_str: &'static str,
executable_filename: &str, executable_filename: &str,
expected_ending: &str, expected_ending: &str,
) { ) {
@ -41,11 +42,16 @@ fn check_cmd_output(
.unwrap() .unwrap()
.to_string(); .to_string();
if cmd_str.contains("cfold") { let out = if cmd_str.contains("cfold") {
increase_stack_limit(); let child = thread::Builder::new()
} .stack_size(CFOLD_STACK_SIZE)
.spawn(move || run_cmd(&cmd_str, &[stdin_str], &[]))
.unwrap();
let out = run_cmd(&cmd_str, &[stdin_str], &[]); child.join().unwrap()
} else {
run_cmd(&cmd_str, &[stdin_str], &[])
};
if !&out.stdout.ends_with(expected_ending) { if !&out.stdout.ends_with(expected_ending) {
panic!( panic!(
@ -69,7 +75,20 @@ fn bench_cmd<T: Measurement>(
.to_string(); .to_string();
if cmd_str.contains("cfold") { if cmd_str.contains("cfold") {
increase_stack_limit(); #[cfg(unix)]
use rlimit::{setrlimit, Resource};
#[cfg(unix)]
setrlimit(
Resource::STACK,
CFOLD_STACK_SIZE as u64,
CFOLD_STACK_SIZE as u64,
)
.expect("Failed to increase stack limit.");
#[cfg(windows)]
println!("Skipping the cfold benchmark on windows, I can't adjust the stack size and use criterion at the same time.");
#[cfg(windows)]
return;
} }
if let Some(bench_group) = bench_group_opt { if let Some(bench_group) = bench_group_opt {
@ -85,12 +104,6 @@ fn bench_cmd<T: Measurement>(
} }
} }
fn increase_stack_limit() {
let new_stack_limit = 8192 * 100000;
setrlimit(Resource::STACK, new_stack_limit, new_stack_limit)
.expect("Failed to increase stack limit.");
}
pub fn bench_nqueens<T: Measurement>(bench_group_opt: Option<&mut BenchmarkGroup<T>>) { pub fn bench_nqueens<T: Measurement>(bench_group_opt: Option<&mut BenchmarkGroup<T>>) {
exec_bench_w_input( exec_bench_w_input(
&example_file("benchmarks", "NQueens.roc"), &example_file("benchmarks", "NQueens.roc"),

View file

@ -46,6 +46,10 @@ pub fn link(
operating_system: OperatingSystem::Darwin, operating_system: OperatingSystem::Darwin,
.. ..
} => link_macos(target, output_path, input_paths, link_type), } => link_macos(target, output_path, input_paths, link_type),
Triple {
operating_system: OperatingSystem::Windows,
..
} => link_windows(target, output_path, input_paths, link_type),
_ => panic!("TODO gracefully handle unsupported target: {:?}", target), _ => panic!("TODO gracefully handle unsupported target: {:?}", target),
} }
} }
@ -1049,6 +1053,15 @@ fn link_wasm32(
Ok((child, output_path)) Ok((child, output_path))
} }
fn link_windows(
_target: &Triple,
_output_path: PathBuf,
_input_paths: &[&str],
_link_type: LinkType,
) -> io::Result<(Child, PathBuf)> {
todo!("Add windows support to the surgical linker. See issue #2608.")
}
#[cfg(feature = "llvm")] #[cfg(feature = "llvm")]
pub fn module_to_dylib( pub fn module_to_dylib(
module: &inkwell::module::Module, module: &inkwell::module::Module,

View file

@ -41,6 +41,11 @@ pub fn target_triple_str(target: &Triple) -> &'static str {
operating_system: OperatingSystem::Darwin, operating_system: OperatingSystem::Darwin,
.. ..
} => "x86_64-unknown-darwin10", } => "x86_64-unknown-darwin10",
Triple {
architecture: Architecture::X86_64,
operating_system: OperatingSystem::Windows,
..
} => "x86_64-pc-windows-gnu",
_ => panic!("TODO gracefully handle unsupported target: {:?}", target), _ => panic!("TODO gracefully handle unsupported target: {:?}", target),
} }
} }

View file

@ -50,12 +50,17 @@ fn main() {
); );
// OBJECT FILES // OBJECT FILES
#[cfg(windows)]
const BUILTINS_HOST_FILE: &str = "builtins-host.obj";
#[cfg(not(windows))]
const BUILTINS_HOST_FILE: &str = "builtins-host.o";
generate_object_file( generate_object_file(
&bitcode_path, &bitcode_path,
"BUILTINS_HOST_O", "BUILTINS_HOST_O",
"object", "object",
"builtins-host.o", BUILTINS_HOST_FILE,
); );
generate_object_file( generate_object_file(
@ -104,7 +109,7 @@ fn generate_object_file(
println!("Moving zig object `{}` to: {}", zig_object, dest_obj); println!("Moving zig object `{}` to: {}", zig_object, dest_obj);
// we store this .o file in rust's `target` folder (for wasm we need to leave a copy here too) // we store this .o file in rust's `target` folder (for wasm we need to leave a copy here too)
run_command(&bitcode_path, "cp", &[src_obj, dest_obj]); fs::copy(src_obj, dest_obj).expect("Failed to copy object file.");
} }
fn generate_bc_file( fn generate_bc_file(

View file

@ -1,2 +1,2 @@
Windows is not yet supported, we have a big project in the works that will make it easier to achieve this. Windows is not yet supported, we have a big project in the works (see issue #2608) that will allow this.
Until then we recommend using Ubuntu through the "Windows Subsystem for Linux". Until then we recommend using Ubuntu through the "Windows Subsystem for Linux".

View file

@ -24,7 +24,7 @@ roc_collections = { path = "../compiler/collections" }
bumpalo = { version = "3.8.0", features = ["collections"] } bumpalo = { version = "3.8.0", features = ["collections"] }
clap = { version = "3.0.0-beta.5", default-features = false, features = ["std", "color", "suggestions"] } clap = { version = "3.0.0-beta.5", default-features = false, features = ["std", "color", "suggestions"] }
iced-x86 = { version = "1.15.0", default-features = false, features = ["std", "decoder", "op_code_info", "instr_info"] } iced-x86 = { version = "1.15.0", default-features = false, features = ["std", "decoder", "op_code_info", "instr_info"] }
memmap2 = "0.5.0" memmap2 = "0.5.3"
object = { version = "0.26.2", features = ["read", "write"] } object = { version = "0.26.2", features = ["read", "write"] }
serde = { version = "1.0.130", features = ["derive"] } serde = { version = "1.0.130", features = ["derive"] }
bincode = "1.3.3" bincode = "1.3.3"

View file

@ -20,7 +20,6 @@ use std::io;
use std::io::{BufReader, BufWriter}; use std::io::{BufReader, BufWriter};
use std::mem; use std::mem;
use std::os::raw::c_char; use std::os::raw::c_char;
use std::os::unix::fs::PermissionsExt;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
@ -1615,9 +1614,14 @@ fn surgery_impl(
let flushing_data_duration = flushing_data_start.elapsed().unwrap(); let flushing_data_duration = flushing_data_start.elapsed().unwrap();
// Make sure the final executable has permision to execute. // Make sure the final executable has permision to execute.
let mut perms = fs::metadata(out_filename)?.permissions(); // TODO windows alternative?
perms.set_mode(perms.mode() | 0o111); #[cfg(target_family = "unix")]
fs::set_permissions(out_filename, perms)?; {
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(out_filename)?.permissions();
perms.set_mode(perms.mode() | 0o111);
fs::set_permissions(out_filename, perms)?;
}
let total_duration = total_start.elapsed().unwrap(); let total_duration = total_start.elapsed().unwrap();

View file

@ -18,8 +18,8 @@ bumpalo = { version = "3.8.0", features = ["collections"] }
const_format = "0.2.22" const_format = "0.2.22"
inkwell = {path = "../vendor/inkwell"} inkwell = {path = "../vendor/inkwell"}
libloading = "0.7.1" libloading = "0.7.1"
rustyline = {git = "https://github.com/rtfeldman/rustyline", tag = "v9.1.1"} rustyline = {git = "https://github.com/rtfeldman/rustyline", rev = "e74333c"}
rustyline-derive = {git = "https://github.com/rtfeldman/rustyline", tag = "v9.1.1"} rustyline-derive = {git = "https://github.com/rtfeldman/rustyline", rev = "e74333c"}
target-lexicon = "0.12.2" target-lexicon = "0.12.2"
# TODO: make llvm optional # TODO: make llvm optional
@ -31,7 +31,7 @@ roc_load = {path = "../compiler/load"}
roc_mono = {path = "../compiler/mono"} roc_mono = {path = "../compiler/mono"}
roc_parse = {path = "../compiler/parse"} roc_parse = {path = "../compiler/parse"}
roc_repl_eval = {path = "../repl_eval"} roc_repl_eval = {path = "../repl_eval"}
roc_std = {path = "../roc_std"} roc_std = {path = "../roc_std", default-features = false}
roc_target = {path = "../compiler/roc_target"} roc_target = {path = "../compiler/roc_target"}
roc_types = {path = "../compiler/types"} roc_types = {path = "../compiler/types"}

View file

@ -17,4 +17,4 @@ libc = "0.2.106"
[features] [features]
default = ["platform"] default = ["platform"]
platform = [] platform = []