Skip to content

Windows Support (2025)#691

Draft
K0lb3 wants to merge 3 commits intoexaloop:developfrom
K0lb3:develop
Draft

Windows Support (2025)#691
K0lb3 wants to merge 3 commits intoexaloop:developfrom
K0lb3:develop

Conversation

@K0lb3
Copy link

@K0lb3 K0lb3 commented Aug 20, 2025

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

@cla-bot
Copy link

cla-bot bot commented Aug 20, 2025

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 info@exaloop.io to get yourself added.

@K0lb3
Copy link
Author

K0lb3 commented Aug 20, 2025

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

@K0lb3
Copy link
Author

K0lb3 commented Aug 20, 2025

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.

@arshajii
Copy link
Contributor

@cla-bot check

@cla-bot cla-bot bot added the cla-signed label Aug 20, 2025
@cla-bot
Copy link

cla-bot bot commented Aug 20, 2025

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

@K0lb3
Copy link
Author

K0lb3 commented Aug 20, 2025

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
Copy link
Author

K0lb3 commented Aug 21, 2025

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....

@ericurse
Copy link

long long story

@TaiXeflar
Copy link

TaiXeflar commented Aug 22, 2025

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.

@K0lb3
Copy link
Author

K0lb3 commented Aug 25, 2025

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.

@TaiXeflar
Copy link

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

@MaD70
Copy link

MaD70 commented Sep 1, 2025

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.

@TaiXeflar
Copy link

@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.

@MaD70
Copy link

MaD70 commented Sep 2, 2025

@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.

@adam-urbanczyk
Copy link

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
Copy link

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)

@TaiXeflar
Copy link

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.

@MaD70
Copy link

MaD70 commented Oct 15, 2025

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.

@adam-urbanczyk
Copy link

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: #671 (comment)

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

@MaD70
Copy link

MaD70 commented Oct 15, 2025

@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.

@0dminnimda
Copy link

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?

@dman82499
Copy link

dman82499 commented Dec 22, 2025

Ya'll may have to change the PR title to '2026' soon. Really do appreciate all the work that's been going in to make this possible tho.

@TaiXeflar
Copy link

TaiXeflar commented Jan 17, 2026

Progress on #69.

Windows work will be need lot of fix and adjustments on both C/C++ source and CMake files.
Even it is possiable to build, it need to fix on both build process and runtime debug.

Currently I use a ROGxMiku Device and Gemini master baiting to have a but unstable codon.exe build. First thing is make it able to build, then make it can run. Still under investigating why calling and have deadlock at initial status.

Here is a screenshot of codon.exe calling in a deadlock status:
image

There's several tricks as hint you may want to know/try:

Hint 1:
THERE IS NO WAY to build via POSIX compatiable layer as my several times testing with these environments.

  • cygwin
  • msys2
  • msys2-mingw64
  • mingw64
  • Linux Cross build mingw64-cross-compile
  • Linux Cross build llvm-mingw

BELIEVE ME, I'VE TRIED.

On the build failure reasons might be: cannot pass with ld: error: export ordinal to large, cannot pass 3rd-party libraries cmake tests while is cross compile etc.
It is not a good option if build on Windows POSIX compatiable layer that you need to pack them with Cygwin/MSYS2/MinGW64 runtime DLLs.
This is not the goal to Porting on Windows as ideal target "Native build on Windows".

Hint 2:
You must have a complete LLVM compiler with these compoments builds.

  • LLVM
  • Clang (LLVM C/C++ language Front End)
  • Flang (LLVM Fortran language Front End)
  • MLIR (LLVM Flang required)
  • openmp (codon required)
  • compiler-rt (LLVM Flang required runtime library clang-rt.builtins.lib)
  • libunwind (LLVM runtime exception handling library)
    Assume these libraries are set to same CMake install directory.

Hint 3:

  • Build LLVM, Clang, Flang with MSVC first, and Disable libxml2 support with -DLLVM_ENABLE_LIBXML2=OFF. After build, set $env:CMAKE_MT = mt.
  • Using we build clang compiler, please use MSVC frontend clang-cl.exe instead of clang.exe/clang++.exe. Then use it to compile compiler-rt.
    After install, copy clang_rt.builtins-x86_64.lib from LLVM CMake install dir llvm-install-dir/lib/windows to llvm-install-dir/lib and rename it to clang_rt.builtins.lib.

Hint 4:

  • The reason of flang is openblas library (defined in cmake/deps.cmake). Exaloop/llvm-project llvm fork is able build.
  • Codon uses $env:CODON_SYSTEM_LIBRARIES to find gfortran libs. But on Windows, we might need change it to LLVM's lib dir, and set required fortran libs to LLVM's FortranRuntime.lib and FortranDecimal.lib.
  • If we cross using clang-cl.exe and gfortran.exe, there will gfortran compile test failure.

Hint 5:

  • Codon uses _Unwind_* symbols to solve runtime exceptions, but Windows use SEH exception handling and does not avail on it. This will hit lld-link linking error on target codonrt.dll. So you need do cmake tricks on libunwind to force it pass compile with your clang-cl build on Windows. This trick is to solve linking error, but still need a major investigation on will this runtime exception handling works or not.

Hint 6:

  • Windows doesn't have libatomic_ops. This is a dependicy for bdwgc (defined in cmake/deps.cmake), and can be solved with package managers on Linux platforms.
    On Windows, this is not common library and have no cmake config files, which make CMAKE_PREFIX_PATH cannot find library paths.
  • Use MSVC to build it and install it somewhere, then export its INCLUDE and LIB paths via sysdm.cpl.
  • If there's other same requirements, as same solving here.

Hint 7:

  • XZ can't solve cmake required target properties xz, xzdec. Idk why this happens, but you can use version >= 5.6.3 to solve this. Mine is 5.8.1 version.

Hint 8: You need to handle unistd.h for missing include.

Hint 9: You will need to adjust a lot of source codes (like adding _WIN32 macro or something else) and CMake files to specify ${MSVC} compile behavior.

Others may need for many times compile to find more problems there that I cant post all.

@giladreich
Copy link

@TaiXeflar Any reason for not using the MSVC compiler?

I remember getting this project to build natively on Windows with MSVC about a year ago. I was able to run it and compile with it executables, but I got tired getting all the tests passing, and the test suite was also pretty slow.
I don't recall experiencing most of the issues you mentioned, except for the dependencies situation and exception handling where I had to abstract this code into using Windows specific exception handling.

@MaD70
Copy link

MaD70 commented Jan 17, 2026

@TaiXeflar wrote:

...
Hint 1: THERE IS NO WAY to build via POSIX compatiable layer as my several times testing with these environments.

  • cygwin
  • msys2
  • msys2-mingw64
  • mingw64
  • Linux Cross build mingw64-cross-compile
  • Linux Cross build llvm-mingw
    ...

You are conflating different things:

  • Cygwin is a POSIX compatibility layer for Windows that provides a Unix-like environment and API on top of the Windows kernel, allowing software written for Unix/Linux to be compiled and run on Windows with minimal changes, using a dedicated runtime (cygwin1.dll).
  • MSYS2 uses a POSIX environment (derived from Cygwin) to provide POSIX-style development tools.
  • MinGW64 and UCRT64 are MSYS2-provided toolchains based on mingw-w64 that build native Windows applications using the Win32 API and the Microsoft C runtime (MSVCRT for MinGW64, UCRT for UCRT64). They do not provide a POSIX compatibility layer and the resulting executables do not depend on MSYS2 or Cygwin.
    Within MSYS2, they are used alongside the MSYS POSIX environment: MSYS supplies Unix-like build tools (shell, make, pkg-config, etc.), while MinGW64/UCRT64 toolchains use those tools to produce native Windows binaries.

A common misconception is that software written for Unix-like systems can be built unchanged in the MSYS2 MinGW64/UCRT64 environment. In reality, these toolchains do not provide a POSIX API; they target the native Windows API, so Unix-specific code must be adapted or replaced for the build to succeed.

@TaiXeflar
Copy link

@MaD70
Yeah, after finding docs I apologize for the misunderstanding on MinGW-w64. But I will keep MSVC not GCC.

When this develop start, I and K0lb3 have already disscussed it before and we selected MSVC as our compiler. So we're really confused why here we need change the toolchain to GCC/JWasm/uasm.

@giladreich

Any reason for not using the MSVC compiler?

Can you provide the build details? I'm using MSVC at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants