I'm building Roc on Windows (native windows, not wsl), and I'm running into this issue when building roc-bindgen
:
Compiling roc-bindgen v0.1.0 (C:\Users\abadi\Code\roc\bindgen)
error: linking with `link.exe` failed: exit code: 1120
...some very long text here..
= note: libroc_std-017ef31d29c35272.rlib(roc_std-017ef31d29c35272.3pajtss0nuz675y5.rcgu.o) : error LNK2019: unresolved external symbol roc_alloc referenced in function _ZN7roc_std8roc_list16RocList$LT$T$GT$17extend_from_slice17ha55bf35b00637735E
libroc_std-017ef31d29c35272.rlib(roc_std-017ef31d29c35272.3pajtss0nuz675y5.rcgu.o) : error LNK2019: unresolved external symbol roc_realloc referenced in function _ZN7roc_std8roc_list16RocList$LT$T$GT$17extend_from_slice17ha55bf35b00637735E
libroc_std-017ef31d29c35272.rlib(roc_std-017ef31d29c35272.3pajtss0nuz675y5.rcgu.o) : error LNK2019: unresolved external symbol roc_dealloc referenced in function _ZN83_$LT$roc_std..roc_list..RocList$LT$T$GT$$u20$as$u20$roc_std..rc..ReferenceCount$GT$9decrement17he3a4633907039d98E
C:\Users\abadi\Code\roc\target\debug\deps\roc_bindgen.exe : fatal error LNK1120: 3 unresolved externals
error: could not compile `roc-bindgen` due to previous error
Here's some information about my set up:
Any help deciphering that error message will be appreciated!
so unfortunately we don't have Roc building on native Windows at all yet :sweat_smile:
the main thing missing is linking; I don't personally have any experience with linking on Windows in general
Yes, that's exactly why I want to build it on Windows :lol: I already worked around a couple of compilation errors with zig and compiling LLVM, but now I'm stuck on this error. Alas, I don't have any experience with linking on Windows either.
The error message is saying that it can't find 3 functions: roc_alloc, roc_realloc, and roc_dealloc. These are memory management functions that are supposed to be provided to the app from the platform.
But as Richard says, we don't have this working on Windows in general yet. If someone can get it working that would be an amazing contribution!
In general to create a Roc program we are linking the "host" (the "foreign language" part of the platform) with the Roc app. The host and app are compiled to two object files, then we link them. Here, the app object file has some "unresolved symbols" that should get resolved when we link it to the host. But that is not happening because of some configuration issue.
@Brendan Hansknecht suggested to try linking with lld instead of with link.exe
@Abadi Kurniawan feel free to make a PR for the zig and llvm fixes. I think we can set up a free windows github action runner(=CI) that checks cargo build
so we can keep that working.
Is Windows still in an incomplete state?
yes, though much more complete. Our examples actually work on windows now
but certain features that make roc development easier don't work (e.g. dbg
and expect
Side note: I've been wanting to set up windows nightly releases for a long time but I hit a memory access violation that is only triggered inside github actions. Like on the same laptop it works outside of github actions.
Hey guys I've never done functional programming but this language looks really interesting and I would like to learn this and be part of the contribution
I've been looking into this windows issue and discovered something interesting, I can run a produced exe (platform-switching\rocLovesRust.exe
) many times without error but using the roc binary to run something prebuilt fails regularly roc.exe run .\examples\platform-switching\rocLovesRust.roc --prebuilt-platform=true
which is strange...
My best guess is that surgical linking isn't fully clean and ends up building in top of the old exe (or something of that nature) leaving to slightly different results each time.
Fascinating, so if I understand correctly, after roc.exe run .\examples\platform-switching\rocLovesRust.roc --prebuilt-platform=true
has failed, running just .\examples\platform-switching\rocLovesRust.exe
should fail as well?
I've found that running just the exe works after a failure with --prebuilt-platform=true
Oh, interesting.
Then i guess it would have to be with roc linking in memory and then directly executing that code?
Somehow the on disk version is fine, but running the in memory version has issues
That sounds really strange to be flaky
Nowadays I am getting regular crashes in the build command, I've painstakingly narrowed it down to hasher.finalize()
in hash_func_id_trivial
inside the morphic code. The hasher comes from a dependency sha2, it's not been known to crash on windows, but someone did encounter something similar on an embedded device; issue.
We use sha2 hashing? Why?
I would assume we would want to switch that out for a faster algorithm anyway
hmm yeah why use a cryptographic hash here?
This is the line of code btw: link
I would assume we would want to switch that out for a faster algorithm anyway
That would be great because I expect that swapping it for something else will fix it.
we could just use rust's DefaultHasher
there right?
probably, but it's SipHash - which is slow but resistent to hash flooding, which we don't care about :sweat_smile:
although it would be a quick way to verify whether that's the problem!
Progress update:
@Brendan Hansknecht's changes to the hashing algorithm fixed that issue on windows :tada:
I'm now investigating the next crash point, libc::execve(...
. I think tomorrow I'll start with a minimal rust program with the most basic libc::execve call and check if that works on windows CI
it did work on windows
ah not on CI maybe, but it works on my machine at least
Yeah, it works on my windows PC too
Why did we opt for execve instead of std::process::Command
there @Folkert de Vries?
mainly so we don't have to spawn an extra process
on linux an extra benefit is that we can use fexecve
, which can use an in-memory program, saving a write to disk too
I've looked into it and on windows libc::execve
uses _execve which appears to create a new process anyway: "Each of these functions loads and executes a new process".
So for windows only, can I replace the libc::execve
with a std::process::Command
alternative?
that is what we had before and it caused other issues
I don't remember what exactly
but, you cannot get execve
to work on the CI machine at all?
It works sometimes but fails about 9 out of 10 times
It did work well with a execve hello world example I tried
Oh god, I found it :tada: :tada:
// don't waste time deallocating; the process ends anyway
// ManuallyDrop will leak the bytes because we don't drop manually
let bytes = &ManuallyDrop::new(std::fs::read(&binary_path).unwrap());
Apparently windows CI doesn't like that
Removing the &ManuallyDrop
from my earlier post did not fix the problem, I was testing three times in a row and think I just "got lucky". Many days of debugging later I made some changes and was finally able to reproduce the problem locally. I now only have a segmentation fault when the roc app reads stdin through the benchmarks zig platform. You also get a segfault on linux when running nqueens and pressing enter instead of an integer+enter. I think I might have been able to diagnose this issue much sooner if we used a rust platform at crates/cli_testing_examples/benchmarks/platform/
, what do you all think about replacing that one?
fine by me! I think we should have at least 1 Zig example platform in examples/
so people can see what it looks like, but for benchmarks I think we can use whatever's most convenient for us
I'd rather not, rust is much slower which is really annoying when debugging with those examples
why would rust have helped in this casse?
Rust would not have segfaulted when the input provided through stdin is not what it expected.
But given that "rust is much slower which is really annoying when debugging with those examples" I'll check if I can make the zig platform more robust when handling stdin.
I was wrong to blame zig here, looks like the segmentation fault was caused on the roc side, still figuring out the details...
Last updated: Jul 06 2025 at 12:14 UTC