codon icon indicating copy to clipboard operation
codon copied to clipboard

Windows Support (2025)

Open K0lb3 opened this issue 4 months ago • 21 comments

This PR is a new attempt to make codon work on Windows (#69 ) It isn't a continuation of the (very) dated #403 .

At the moment this PR doesn't work yet, serving primarily as visible progress and for communication. The commits marked as WIP should be removed/squashed before this draft PR becomes a real PR.

The setup I'm using is MinGW (13.2), LLVM (20.1.8), CMake (4.1.0), all installed via chocolatey.

The value of CODON_SYSTEM_LIBRARIES is currently irrelevant for Windows and the functionality might have to be adjusted slightly.

#675 might help a lot for making codon work well on Windows, as non-system shared libraries are a bit iffy on Windows, and well, actually even system ones due to some rare few breaking changes.

TODO: [x] no compile errors [ ] no linking errors [ ] tests pass [ ] lib copying works

K0lb3 avatar Aug 20 '25 00:08 K0lb3

Thank you for your pull request. We require contributors to agree to our Contributor License Agreement (https://exaloop.io/legal/cla), and we don't have @K0lb3 on file. In order for us to review and merge your code, please email [email protected] to get yourself added.

cla-bot[bot] avatar Aug 20 '25 00:08 cla-bot[bot]

My first milestone for this PR is that the codon target compiles successfully. Therefore I "disabled" via comments for now.

K0lb3 avatar Aug 20 '25 00:08 K0lb3

llvm and MinGW from choco might be "incompatible" for this project, as the llvm package seems to be targeting msvc. I'm going to try llvm-mingw as toolchain tomorrow.

K0lb3 avatar Aug 20 '25 00:08 K0lb3

@cla-bot check

arshajii avatar Aug 20 '25 17:08 arshajii

The cla-bot has been summoned, and re-checked this pull request!

cla-bot[bot] avatar Aug 20 '25 17:08 cla-bot[bot]

Small update.

GCC x LLVM is quite the pain on Windows.

For GCC and its libs MinGW can be used just fine, but LLVM in combination with that is annoying. As far as I can see there is no with mingw precompiled llvm with cmake files for Windows. ~~Due to that either the relevant cmake logic would have to be "ported" to make use of the precompiled llvm-mingw-ucrt, or llvm would have to be compiled with cmake file generation.~~

~~I'm leaning towards the later as I don't want to bother with even more cmake madness.~~

llvm-mingw doesn't include some header files used by codon, so llvm compiling it is....

K0lb3 avatar Aug 20 '25 22:08 K0lb3

Well, more fun.

llvm-openmp uses an masm format asm for Windows (32x and 64x), and MinGW doesn't ship an masm assembler. So another requirement for Windows has to be added, a masm compiler... Let's see if JWasm works.

At the very least arm isn't affected by this, as llvm seems to use a (linux) gcc based asm for it. ~~How comes this somehow starts to look like a hellhole?~~

Oh, and to add on top, cmake seems to detect the asm compiler incorrectly for MinGW, it tries to use gcc instead of as....

K0lb3 avatar Aug 21 '25 08:08 K0lb3

long long story

ericurse avatar Aug 21 '25 11:08 ericurse

My latest compile history is this (2025/7/18).

exaloop/codon v0.17, MSVC

  • Side-projects can be fixed by adjust CPM.cmake, or manually add needed libraries.
  • codon/CMakeLists.txt can be adjusted.
  • The part need fix is the exceptions in codon/runtime/exc.cpp where it uses unwind. Unwind is supported on macOS/Linux, but not supported in Windows UCRT and MinGW/MSYS2.

TaiXeflar avatar Aug 22 '25 06:08 TaiXeflar

I also started to adjust some of the dependencies in the cmake/deps.cmake as TaiXeflar mentioned.

Using read.c & allloc.c instead of mmapio.c & mmap.c for backtrace, switching from exaloop/bdwgc to a newer bdwgc/bdwgc, using exaloop/openmp as openmp library for __kmpc_set_gc_callbacks.

K0lb3 avatar Aug 25 '25 07:08 K0lb3

@K0lb3 Do you joined exaloop/codon's DC server? maybe we can have a chat there

TaiXeflar avatar Aug 25 '25 09:08 TaiXeflar

Well, more fun.

llvm-openmp uses an masm format asm for Windows (32x and 64x), and MinGW doesn't ship an masm assembler. So another requirement for Windows has to be added, a masm compiler... Let's see if JWasm works.

At the very least arm isn't affected by this, as llvm seems to use a (linux) gcc based asm for it. ~How comes this somehow starts to look like a hellhole?~

Oh, and to add on top, cmake seems to detect the asm compiler incorrectly for MinGW, it tries to use gcc instead of as....

@K0lb3 have you tried using MSYS2? I see they have the package mingw-w64-x86_64-llvm-openmp in their repository. If you install base-devel package (its dependencies are installed automatically) it provides you with a *nix development environment, but produces native Windows executables. You can install both GCC and clang.

P.S.: don't forget to check this page: Environments.

MaD70 avatar Sep 01 '25 21:09 MaD70

@MaD70 There's a assembly compile target at openmp/runtime/src/z_Windows_NT-586_asm.asm requires Macro Assembler where GCC toolchain doesn't have this. So is not any environment problems, it is GCC doesn't have Macro Assembler.

Available Macro Assembler is JWasm @K0lb3 using or by MSVC ml64.exe.

TaiXeflar avatar Sep 02 '25 17:09 TaiXeflar

@MaD70 There's a assembly compile target at openmp/runtime/src/z_Windows_NT-586_asm.asm requires Macro Assembler where GCC toolchain doesn't have this. So is not any environment problems, it is GCC doesn't have Macro Assembler.

Available Macro Assembler is JWasm @K0lb3 using or by MSVC ml64.exe.

@TaiXeflar obviously you don't know what MSYS2 is and didn’t bother to look at the links I included in my message, did you?

MSYS2 packages are usually precompiled binaries. I quote from MSYS2 home page:

Our package repository contains more than 3500 pre-built packages ready to install.

Follow this link to mingw-w64-x86_64-llvm-openmp package: you'll see there is a separate link to sources and under "Build Dependencies" you'll see there another MSYS2 package listed, mingw-w64-x86_64-uasm, a free MASM-compatible assembler based on JWasm (mingw-w64). If required, the software can be rebuilt from sources from within MSYS2.

MaD70 avatar Sep 02 '25 22:09 MaD70

Super interesting @K0lb3 ! +1 for trying msys2 and a clang only toolchain. Any reason you did not start with such a setup? Any thoughts/ideas/recommendations on using MSVC?

adam-urbanczyk avatar Oct 11 '25 19:10 adam-urbanczyk

I quickly tried with clang and this is what I get in the end. Any clues? Looks like missing symbols in an external lib, which is weird.

ld.lld: error: undefined symbol: GC_allow_register_threads
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_init)

ld.lld: error: undefined symbol: GC_register_my_thread
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_init)

ld.lld: error: undefined symbol: GC_remove_roots
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_init)
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_gc_remove_roots)

ld.lld: error: undefined symbol: __kmpc_set_gc_callbacks
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_init)

ld.lld: error: undefined symbol: GC_wait_for_reclaim
>>> referenced by libgc.a(alloc.c.obj):(GC_collect_a_little_inner)
>>> referenced by libgc.a(alloc.c.obj):(GC_collect_a_little_inner)
>>> referenced by libgc.a(alloc.c.obj):(GC_try_to_collect_inner)
>>> referenced 1 more times

ld.lld: error: undefined symbol: GC_stop_world
>>> referenced by libgc.a(alloc.c.obj):(GC_stopped_mark)
>>> referenced by libgc.a(misc.c.obj):(GC_stop_world_external)

ld.lld: error: undefined symbol: GC_start_world
>>> referenced by libgc.a(alloc.c.obj):(GC_stopped_mark)
>>> referenced by libgc.a(alloc.c.obj):(GC_stopped_mark)
>>> referenced by libgc.a(misc.c.obj):(GC_start_world_external)

ld.lld: error: undefined symbol: GC_allocate_ml
>>> referenced by libgc.a(alloc.c.obj):(.refptr.GC_allocate_ml)
>>> referenced by libgc.a(reclaim.c.obj)
>>> referenced by libgc.a(misc.c.obj)

ld.lld: error: undefined symbol: GC_need_to_lock
>>> referenced by libgc.a(alloc.c.obj):(.refptr.GC_need_to_lock)
>>> referenced by libgc.a(reclaim.c.obj)
>>> referenced by libgc.a(misc.c.obj)

ld.lld: error: undefined symbol: GC_thr_init
>>> referenced by libgc.a(misc.c.obj):(GC_init)

ld.lld: error: undefined symbol: GC_start_mark_threads_inner
>>> referenced by libgc.a(misc.c.obj):(GC_init)
>>> referenced by libgc.a(misc.c.obj):(GC_start_mark_threads)

ld.lld: error: undefined symbol: GC_init_parallel
>>> referenced by libgc.a(misc.c.obj):(GC_init)

ld.lld: error: undefined symbol: GC_do_blocking_inner
>>> referenced by libgc.a(misc.c.obj):(GC_do_blocking)

ld.lld: error: undefined symbol: GC_in_thread_creation
>>> referenced by libgc.a(misc.c.obj):(.refptr.GC_in_thread_creation)

ld.lld: error: undefined symbol: GC_push_all_stacks
>>> referenced by libgc.a(os_dep.c.obj):(GC_default_push_other_roots)

ld.lld: error: undefined symbol: GC_push_thread_structures
>>> referenced by libgc.a(mark_rts.c.obj):(GC_push_roots)

ld.lld: error: undefined symbol: GC_mark_thread_local_free_lists
>>> referenced by libgc.a(mark_rts.c.obj):(GC_push_roots)

ld.lld: error: undefined symbol: GC_acquire_mark_lock
>>> referenced by libgc.a(mark.c.obj):(GC_mark_some)
>>> referenced by libgc.a(mark.c.obj):(GC_wait_for_markers_init)
>>> referenced by libgc.a(mark.c.obj):(GC_mark_local)
>>> referenced 8 more times

ld.lld: error: undefined symbol: GC_notify_all_marker
>>> referenced by libgc.a(mark.c.obj):(GC_mark_some)
>>> referenced by libgc.a(mark.c.obj):(GC_mark_some)
>>> referenced by libgc.a(mark.c.obj):(GC_mark_local)
>>> referenced 3 more times

ld.lld: error: undefined symbol: GC_wait_marker
>>> referenced by libgc.a(mark.c.obj):(GC_mark_some)
>>> referenced by libgc.a(mark.c.obj):(GC_help_marker)
>>> referenced by libgc.a(mark.c.obj):(GC_mark_local)

adam-urbanczyk avatar Oct 12 '25 20:10 adam-urbanczyk

I quickly tried with clang and this is what I get in the end. Any clues? Looks like missing symbols in an external lib, which is weird.

ld.lld: error: undefined symbol: GC_allow_register_threads
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_init)

ld.lld: error: undefined symbol: GC_register_my_thread
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_init)

ld.lld: error: undefined symbol: GC_remove_roots
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_init)
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_gc_remove_roots)

ld.lld: error: undefined symbol: __kmpc_set_gc_callbacks
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_init)

ld.lld: error: undefined symbol: GC_wait_for_reclaim
>>> referenced by libgc.a(alloc.c.obj):(GC_collect_a_little_inner)
>>> referenced by libgc.a(alloc.c.obj):(GC_collect_a_little_inner)
>>> referenced by libgc.a(alloc.c.obj):(GC_try_to_collect_inner)
>>> referenced 1 more times

ld.lld: error: undefined symbol: GC_stop_world
>>> referenced by libgc.a(alloc.c.obj):(GC_stopped_mark)
>>> referenced by libgc.a(misc.c.obj):(GC_stop_world_external)

ld.lld: error: undefined symbol: GC_start_world
>>> referenced by libgc.a(alloc.c.obj):(GC_stopped_mark)
>>> referenced by libgc.a(alloc.c.obj):(GC_stopped_mark)
>>> referenced by libgc.a(misc.c.obj):(GC_start_world_external)

ld.lld: error: undefined symbol: GC_allocate_ml
>>> referenced by libgc.a(alloc.c.obj):(.refptr.GC_allocate_ml)
>>> referenced by libgc.a(reclaim.c.obj)
>>> referenced by libgc.a(misc.c.obj)

ld.lld: error: undefined symbol: GC_need_to_lock
>>> referenced by libgc.a(alloc.c.obj):(.refptr.GC_need_to_lock)
>>> referenced by libgc.a(reclaim.c.obj)
>>> referenced by libgc.a(misc.c.obj)

ld.lld: error: undefined symbol: GC_thr_init
>>> referenced by libgc.a(misc.c.obj):(GC_init)

ld.lld: error: undefined symbol: GC_start_mark_threads_inner
>>> referenced by libgc.a(misc.c.obj):(GC_init)
>>> referenced by libgc.a(misc.c.obj):(GC_start_mark_threads)

ld.lld: error: undefined symbol: GC_init_parallel
>>> referenced by libgc.a(misc.c.obj):(GC_init)

ld.lld: error: undefined symbol: GC_do_blocking_inner
>>> referenced by libgc.a(misc.c.obj):(GC_do_blocking)

ld.lld: error: undefined symbol: GC_in_thread_creation
>>> referenced by libgc.a(misc.c.obj):(.refptr.GC_in_thread_creation)

ld.lld: error: undefined symbol: GC_push_all_stacks
>>> referenced by libgc.a(os_dep.c.obj):(GC_default_push_other_roots)

ld.lld: error: undefined symbol: GC_push_thread_structures
>>> referenced by libgc.a(mark_rts.c.obj):(GC_push_roots)

ld.lld: error: undefined symbol: GC_mark_thread_local_free_lists
>>> referenced by libgc.a(mark_rts.c.obj):(GC_push_roots)

ld.lld: error: undefined symbol: GC_acquire_mark_lock
>>> referenced by libgc.a(mark.c.obj):(GC_mark_some)
>>> referenced by libgc.a(mark.c.obj):(GC_wait_for_markers_init)
>>> referenced by libgc.a(mark.c.obj):(GC_mark_local)
>>> referenced 8 more times

ld.lld: error: undefined symbol: GC_notify_all_marker
>>> referenced by libgc.a(mark.c.obj):(GC_mark_some)
>>> referenced by libgc.a(mark.c.obj):(GC_mark_some)
>>> referenced by libgc.a(mark.c.obj):(GC_mark_local)
>>> referenced 3 more times

ld.lld: error: undefined symbol: GC_wait_marker
>>> referenced by libgc.a(mark.c.obj):(GC_mark_some)
>>> referenced by libgc.a(mark.c.obj):(GC_help_marker)
>>> referenced by libgc.a(mark.c.obj):(GC_mark_local)

Missing GC static libraries. This library is avail on macOS/Linux, not installed on Windows by default. And available toolchains(VS20XX/oneAPI/HIP/Strawberry) didn't provide GC libraries.

TaiXeflar avatar Oct 15 '25 05:10 TaiXeflar

I quickly tried with clang and this is what I get in the end. Any clues? Looks like missing symbols in an external lib, which is weird.

ld.lld: error: undefined symbol: GC_allow_register_threads
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_init)

ld.lld: error: undefined symbol: GC_register_my_thread
>>> referenced by CMakeFiles/codonrt.dir/codon/runtime/lib.cpp.obj:(seq_init)

[snipped]

@adam-urbanczyk I guess you don't have the Boehm Garbage Collector library available in your path. If you are using MSYS2, it is available as package mingw-w64-x86_64-gc. Just install it with:

pacman -S mingw-w64-x86_64-gc

and then try to recompile.

MaD70 avatar Oct 15 '25 09:10 MaD70

Hm, AFAICT bdwgc is compiled as a submodule of this project via CPM. Maybe wrong configuration then?

__kmpc_set_gc_callbacks seems to be explained here: https://github.com/exaloop/codon/issues/671#issuecomment-3152309213

If I understand this correctly, I need to at least build a custom OpenMP runtime and link against it.

adam-urbanczyk avatar Oct 15 '25 17:10 adam-urbanczyk

@adam-urbanczyk oh yes, I now see that in deps.cmake and they are using a local fork in exaloop/bdwgc, not the canonical source in bdwgc/bdwgc.

They also have exaloop/llvm-project, that is an LLVM fork based on LLVM 20 (instruction to build it) and exaloop/openmp, a LLVM OpenMP fork with GC hooks. But at the moment I can't find how this custom version of OpenMP is imported by Codon.

MaD70 avatar Oct 15 '25 22:10 MaD70

Is it an option to we get windows compiling without openmp at first? So the scope is smaller and the task is more likely to be done .. ever?

0dminnimda avatar Nov 09 '25 18:11 0dminnimda