# How to compile to stand-alone executable using StaticCompiler in Windows?

**URL:** <https://discourse.julialang.org/t/how-to-compile-to-stand-alone-executable-using-staticcompiler-in-windows/106767>\
**Category:** General Usage\
**Tags:** windows, compilation\
**Created:** [November 26, 2023, 9:50pm UTC](https://discourse.julialang.org/t/how-to-compile-to-stand-alone-executable-using-staticcompiler-in-windows/106767 "2023-11-26T21:50:21Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Thomas008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thomas008/32/204169_2.png) [@Thomas008](https://discourse.julialang.org/u/Thomas008)\
**Post date:** [November 26, 2023, 9:50pm UTC](https://discourse.julialang.org/t/how-to-compile-to-stand-alone-executable-using-staticcompiler-in-windows/106767/1 "2023-11-26T21:50:21Z")

</div>

I published this question already in [https://stackoverflow.com/questions/77551695/how-to-compile-julia-code-as-stand-alone-executable-with-help-of-staticcompiler](https://stackoverflow.com/questions/77551695/how-to-compile-julia-code-as-stand-alone-executable-with-help-of-staticcompiler).  
I’d like to compile to small executable in Windows, e.g. with help of StaticCompiler. StaticCompiler is successful for Linux, and it would be great, if it can be used in Windows, too. The problem is that the generated executable does not print a string (neither to stdout nor to a file). Do you have any experiences or suggestions to get StaticCompiler or GPUCompiler work to print a string under windows?

For example, I tried:

```julia
using StaticCompiler, StaticTools
f() = println(c"h")
compile_executable(f,(),"./")

```

This produces an object file (“f.o”), but linking fails (linking the objective file with a wrapper-file, wrapper.c, to create an executable). StaticCompiler uses clang for linking. Clang fails here, prompting the error message “f.o unknown file type”. The developers of StaticCompiler recommended trying the compiler that PackageCompiler installs as an artifact. This is in my case gcc, and indeed gcc links without error.

However, the generated executable does not print anything to stdout. But generally the executable seems to work. E.g. compiling `f() = getchar()` works.

Under the hood, StaticTools translates `println` to a LLVM IR that calls @puts. For example, putting ‘h’ would be the Julia LLVM IR

```julia
function f()
  Base.llvmcall(("""
    declare i32 @puts(i8*)
    define i32 @main() {
      %a = alloca i8
      store i8 104, i8* %a
      call i32 @puts(i8* %a)
      ret i32 0
    }
  """, "main"), Int32, Nothing, Nothing)
end

```

This works in the Repl, but when applying `compile_executable`, the generated executable does not print anything to stdout.

StaticCompiler uses GPUCompiler to produce a LLVM IR module that is then translated in machine code. In this case, the LLVM IR module produced from the LLVM IR depicted above is:

```julia
source_filename = "start"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-w64-mingw32"

define i32 @t() local_unnamed_addr #0 {
top:
  %0 = call fastcc i32 @julia_t_1040u1042()
  ret i32 %0
}

define internal fastcc i32 @julia_t_1040u1042() unnamed_addr {
  %a = alloca i8, align 1
  store i8 65, i8* %a, align 1
  %1 = call i32 @puts(i8* noundef nonnull %a)
  ret i32 0
}

declare i32 @puts(i8*) local_unnamed_addr

attributes #0 = { "probe-stack"="inline-asm" }

!llvm.module.flags = !{!0, !1}

!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}

```

My questions: Why does StaticCompiler fails printing output in Windows? Does the Julia LLVM IR, or the string representation in StaticTools, or the GPUCompiler configuration or implementation, or some environment variables, have to be adapted for Windows?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 26, 2023, 9:55pm UTC](https://discourse.julialang.org/t/how-to-compile-to-stand-alone-executable-using-staticcompiler-in-windows/106767/2 "2023-11-26T21:55:08Z")

</div>

StaticCompiler.jl states one if its limitations is “Doesn’t work on Windows (but works in WSL on Windows 10+). PRs welcome.” in its README.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 26, 2023, 9:59pm UTC](https://discourse.julialang.org/t/how-to-compile-to-stand-alone-executable-using-staticcompiler-in-windows/106767/3 "2023-11-26T21:59:03Z")

</div>

I put a littile thought into this a year ago:

> <https://github.com/brenhinkeller/StaticTools.jl/issues/20>
>
> Currently , \`stdoutp()\` will fail on Windows.
> 
> \`\`\`
> FATAL ERROR: Symbol "stdou…t"not found
> signal (22): SIGABRT
> in expression starting at ~\\.julia\\dev\\StaticTools\\test\\testllvmio.jl:3
> crt\_sig\_handler at /cygdrive/c/buildbot/worker/package\_win64/build/src\\signals-win.c:92
> raise at C:\\WINDOWS\\System32\\msvcrt.dll (unknown line)
> abort at C:\\WINDOWS\\System32\\msvcrt.dll (unknown line)
> addModule at /cygdrive/c/buildbot/worker/package\_win64/build/src\\jitlayers.cpp:763
> \`\`\`
> 
> 
> To get C stdio on Windows, I think we need to implement the equivalent of these calls. \`\_\_iob\_func\` is defined in \`msvcrt.dll\`.
> 
> \`\`\`julia
> ccall(:\_\_iob\_func, Ptr{Nothing}, (Cuint,), 0) #stdin
> ccall(:\_\_iob\_func, Ptr{Nothing}, (Cuint,), 1) #stdout
> ccall(:\_\_iob\_func, Ptr{Nothing}, (Cuint,), 2) #stderr
> \`\`\`
> 
> Do you have a method for converting these to their \`llvmcall\` equivalents?

My thought is that the easiest path may be through a MSYS2 like environment for native Windows. WSL2 might be an easier alternative for now.

---

<div class="post-metadata">

**Author:** ![Thomas008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thomas008/32/204169_2.png) [@Thomas008](https://discourse.julialang.org/u/Thomas008)\
**Post date:** [November 30, 2023, 8:57pm UTC](https://discourse.julialang.org/t/how-to-compile-to-stand-alone-executable-using-staticcompiler-in-windows/106767/4 "2023-11-30T20:57:20Z")

</div>

Our goal is to overcome this limitation and to support StaticCompiler to work on Windows. I imagine, there are some people using Windows who want to apply StaticCompiler.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 30, 2023, 9:11pm UTC](https://discourse.julialang.org/t/how-to-compile-to-stand-alone-executable-using-staticcompiler-in-windows/106767/5 "2023-11-30T21:11:30Z")

</div>

Are you representing some larger group or company?

I would be happy to collaborate on this. I’m probably one of thr few who uses Windows regularly while also having some limited knowledge on Julia internals.

---

<div class="post-metadata">

**Author:** ![Thomas008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thomas008/32/204169_2.png) [@Thomas008](https://discourse.julialang.org/u/Thomas008)\
**Post date:** [December 4, 2023, 10:26pm UTC](https://discourse.julialang.org/t/how-to-compile-to-stand-alone-executable-using-staticcompiler-in-windows/106767/6 "2023-12-04T22:26:28Z")

</div>

We are not a larger group or a company, but two people.  
We would be very happy to collaborate with you. We are highly interested to support people who want to use Julia on Windows. We think the whole Julia community would benefit from this.

---

<div class="post-metadata">

**Author:** ![Thomas008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thomas008/32/204169_2.png) [@Thomas008](https://discourse.julialang.org/u/Thomas008)\
**Post date:** [December 5, 2023, 4:04pm UTC](https://discourse.julialang.org/t/how-to-compile-to-stand-alone-executable-using-staticcompiler-in-windows/106767/7 "2023-12-05T16:04:17Z")

</div>

Here are some further attempts: I have tried to generate a LLVM IR from a simple C-program (the way (B) Brehnin Keller suggested in the issues of StaticTools  
[https://github.com/brenhinkeller/StaticTools.jl/issues/20](https://github.com/brenhinkeller/StaticTools.jl/issues/20)).

I used a simple C program “put.c” that writes an “A” to stdout:

```julia
#include <stdio.h>

int main(void) {
   printf("A");
}

```

Using `clang -emit-llvm -S put.c -o put.ll` I got the following LLVM IR:

```julia
@.str = private unnamed_addr constant [2 x i8] c"A\00", align 1

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
  %1 = call i32 (ptr, ...) @printf(ptr noundef @.str)
  ret i32 0
}

declare dso_local i32 @printf(ptr noundef, ...) #1

attributes #0 = { noinline nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}

!0 = !{i32 1, !"wchar_size", i32 2}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"uwtable", i32 2}
!3 = !{i32 1, !"MaxTLSAlign", i32 65536}
!4 = !{!"clang version 17.0.4 (https://github.com/llvm/llvm-project.git 309d55140c46384b6de7a7573206cbeba3f7077f)"}

```

I put this in a Base.llvmcall() of Julia with some slight adaptions: The constant `c"A\00"` did not work, Julia came up with some syntax error.  
Also with the type `ptr` an error occurred . So I used `i8*` instead. The adapted LLVM IR for Julia is the following:

```julia
function t()
Base.llvmcall(("""	

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%a = alloca i64
store i64 65, i64* %a
  %1 = call i32 (i64*, ...) @printf(i64* noundef %a)
  ret i32 0
}

declare dso_local i32 @printf(i64* noundef, ...) #1

attributes #0 = { noinline nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}

!0 = !{i32 1, !"wchar_size", i32 2}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"uwtable", i32 2}
!3 = !{i32 1, !"MaxTLSAlign", i32 65536}
!4 = !{!"clang version 17.0.4 (https://github.com/llvm/llvm-project.git 309d55140c46384b6de7a7573206cbeba3f7077f)"}
               """, "main"), Int32, Nothing, Nothing)
end

```

Then I applied

```julia
using StaticTools, StaticCompiler
compile_executable(t,(),"./")

```

resulting in an object file` t.o`. After linking with gcc an executable is generated.

`gcc wrapper.c t.o -o t.exe`

However, the executalbe `t.exe` did not give an output. The returned error code is “False”.

When applying clang for linking, I got  
`"t.o unknown file type"`

When compiling a function like  
`t() = getchar()`  
the generated executable works (expecting an input). Only outputting to stdout or to a file does not work and results in an error. To me, this suggests, that the LLVM IR might be wrong.  
Do you have any suggestions how to make the executable could print a string, or how the LLVM IR should look like?

---

<div class="post-metadata">

**Author:** ![Thomas008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thomas008/32/204169_2.png) [@Thomas008](https://discourse.julialang.org/u/Thomas008)\
**Post date:** [January 12, 2024, 11:56am UTC](https://discourse.julialang.org/t/how-to-compile-to-stand-alone-executable-using-staticcompiler-in-windows/106767/8 "2024-01-12T11:56:02Z")

</div>

The solution for adapting StaticCompiler for Windows is running llc to get the native object file from the LLVM IR, instead of using GPUCompiler. llc is the static compiler from LLVM. We used the following code in the function `generate_obj()`:

```julia

if Sys.iswindows()
      ir_path = joinpath(path, "$filenamebase.ll")
      open(ir_path, "w") do io
        write(io, string(mod))
      end
      run(`cmd /c llc -filetype=obj -mtriple=x86_64-w64-windows-gnu $ir_path -o $obj_path`)

```

Meanwhile llc is integrated in clang. So it suffices in the function `generate_obj()`:

```julia
if Sys.iswindows()
      ir_path = joinpath(path, "$filenamebase.ll")
      open(ir_path, "w") do io
        write(io, string(mod))
      end
...
end

```

and in the function `generate_executable()`:

```julia

if Sys.iswindows()
          ir_path = joinpath(path, "$filename.ll")
          run(`cmd /c clang -Wno-override-module $wrapper_path $ir_path -o $exec_path`
...
end

```

We are going to implement the adaptions to windows in a PR for StaticCompiler.

---

<div class="post-metadata">

**Author:** ![Thomas008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thomas008/32/204169_2.png) [@Thomas008](https://discourse.julialang.org/u/Thomas008)\
**Post date:** [January 15, 2024, 3:03pm UTC](https://discourse.julialang.org/t/how-to-compile-to-stand-alone-executable-using-staticcompiler-in-windows/106767/9 "2024-01-15T15:03:24Z")

</div>

Here is a [repo](https://github.com/Thomas008/StaticCompiler.jl) that is a fork of [StaticCompiler](https://github.com/tshort/StaticCompiler.jl) containing those adaptions to Windows.  
It requires clang (the clang delivered in the artifacts does not work on my machine (because of new Julia version I use, and so on).
