# Will there be cross-compile support for Windows 7?

**URL:** <https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168>\
**Category:** Help & Support\
**Created:** [April 6, 2021, 12:59am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168 "2021-04-06T00:59:02Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![qwertfisch](https://avatars.discourse-cdn.com/v4/letter/q/f9ae1b/32.png) [@qwertfisch](https://forum.crystal-lang.org/u/qwertfisch)\
**Post date:** [April 6, 2021, 12:59am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/1 "2021-04-06T00:59:02Z")

</div>

Hello!  
I discovered Crystal some time ago and tried using it on my Linux notebook. This works fine, so I thought with the arrival of version 1.0, there should be a way using it on Windows (at least for hobby purposes).

I tried both suggested ways: either cross-compiling from scratch on a Linux host, or using the artifacts from Github CI with a precompiled `crystal.exe` (and libraries). Both ways showed me the same error message on executing any cross-compiled .exe file:

> The procedure entry point “GetCurrentThreadStackLimits” could not be located in the dynamic link library KERNEL32.dll

The precompiled `crystal.exe` itself prints out this message and stops, so this is no compilation problem on my side, but an executing problem.

From the [porting guide](https://github.com/crystal-lang/crystal/wiki/Porting-to-Windows) I tried compiling the helloworld program, which gives no errors on compiling or linking but on running the resulting `.exe` file. So I assume the cross-compiled .obj file is just not working on my Windows 7, which might originate in LLVM or some settings for it when using the switches `-cross-compile --target x86_64-pc-windows-msvc`.

On Windows 10 both the precompiled `crystal.exe` as well as my `helloworld.exe` (linked on Windows 7) execute just fine.

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [April 6, 2021, 3:05am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/2 "2021-04-06T03:05:26Z")

</div>

FWIW Windows 7 is end of life and is no longer supported so I would think native cross compiling support would not be something that is high on the priority list.

---

<div class="post-metadata">

**Author:** ![oprypin](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/oprypin/32/859_2.png) [@oprypin](https://forum.crystal-lang.org/u/oprypin)\
**Post date:** [April 6, 2021, 6:04am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/3 "2021-04-06T06:04:05Z")

</div>

Well yes, clearly that function is being used and clearly it’s not available in Windows 7.

> <https://github.com/crystal-lang/crystal/blob/dd40a2442fa186add8a82b74edb14a90aa1dae05/src/crystal/system/win32/thread.cr#L70>

You could try your luck replacing such functions until it works. Nobody else needed to do that and nobody will in the near future.

Perhaps [GetCurrentThreadStackLimits function (processthreadsapi.h) - Win32 apps | Microsoft Docs](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadstacklimits) → [NtCurrentTeb function (winnt.h) - Win32 apps | Microsoft Docs](https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-ntcurrentteb)

---

<div class="post-metadata">

**Author:** ![qwertfisch](https://avatars.discourse-cdn.com/v4/letter/q/f9ae1b/32.png) [@qwertfisch](https://forum.crystal-lang.org/u/qwertfisch)\
**Post date:** [April 6, 2021, 11:42am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/4 "2021-04-06T11:42:38Z")

</div>

Thanks for the hint. So now I know that `GetCurrentThreadStackLimits` is only available on Windows 8 or newer. Is there some kind of list of all these functions? Probably not and I would either have to look in all source files, or try/err until it works …

What is the lowest Windows version the LibC requires?

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 6, 2021, 11:50am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/5 "2021-04-06T11:50:42Z")

</div>

> [@qwertfisch](#):
>
> What is the lowest Windows version the LibC requires?

I don’t think anyone has ever checked that. Windows support is not finalized yet, so the focus is definitely on getting the basics running at least on current version. Backporting to older Windows versions is of course possible, but not a priority.

Off the top of my head, I recall the time implementation uses `GetSystemTimePreciseAsFileTime` which is available at Windows 8+. But I also left a to-do for older versions.

> <https://github.com/crystal-lang/crystal/blob/e7b46c40739902db70a2dceebd09caf1a7c70553/src/crystal/system/win32/time.cr#L18-L20>

Apart from that and the stack limits, I wouldn’t expect there are much more functions not supported in Windows 7.

---

<div class="post-metadata">

**Author:** ![konovod](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/konovod/32/229_2.png) [@konovod](https://forum.crystal-lang.org/u/konovod)\
**Post date:** [April 7, 2021, 10:22am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/6 "2021-04-07T10:22:58Z")

</div>

Not only crystal.exe, but also compiled crystal programs won’t run on Win7 due to these two functions. I’ve created an issue about it some time ago - [Crystal programs doesn't work on Windows 7 due to GetCurrentThreadStackLimits · Issue #10085 · crystal-lang/crystal · GitHub](https://github.com/crystal-lang/crystal/issues/10085) . There is a link to Stackoverflow on how to replace `GetCurrentThreadStackLimits` on Win7: [https://stackoverflow.com/a/52404641](https://stackoverflow.com/a/52404641).

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 7, 2021, 11:57am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/7 "2021-04-07T11:57:10Z")

</div>

PRs are welcome! Shouldn’t be hard to do, even without win32 experience.

---

<div class="post-metadata">

**Author:** ![qwertfisch](https://avatars.discourse-cdn.com/v4/letter/q/f9ae1b/32.png) [@qwertfisch](https://forum.crystal-lang.org/u/qwertfisch)\
**Post date:** [April 15, 2021, 12:26am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/8 "2021-04-15T00:26:18Z")

</div>

Finally I have managed compiling LLVM (version 10 had some bug which prevents compiling on Windows, but LLVM11 works) and then Crystal successfully. This was more effort than implementing the patch …

The compiler compiles itself on Windows 7, but my changes do not distinguish between Win7 and Win8+ yet. I wanted to include version checks, using [Version Helper Functions](https://docs.microsoft.com/en-us/windows/win32/sysinfo/version-helper-apis), but `cl` keeps telling me `unresolved external symbol` for `IsWindows8OrGreater`, despite the fact that this is included in `VersionHelpers.h` in Windows SDK.

Also other functions cannot be found, whereas the mentionend `NtCurrentTeb` (and others) **are** found. I am at a loss how to tell which functions from which libraries/include files the linker can see. Where is this defined in Crystal source? Somewhere must be a definition of “include this DLL and that DLL, and then try to find all referenced functions” …

I could implement the version helper functions directly in Crystal, but then would need to reference other things like [GetVersionExW](https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversionexw), which also might or might not be found. (I did not test this yet.)

(Sorry for possibly trivial questions, but I do not develop every day with external C functions and I might just need a tiny step in the right direction.)

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 15, 2021, 10:46am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/9 "2021-04-15T10:46:23Z")

</div>

> [@qwertfisch](#):
>
> despite the fact that this is included in `VersionHelpers.h` in Windows SDK.

Features from header files are not available in the binary libraries. Everything provided in a header file needs to be implemented in Crystal. For reference, the library bindings in Crystal (in `src/lib_c/x86_64-windows-msvc`) are essentially the equivalents of C header files. That’s where the library functions are defined so that Crystal knows about them.  
So the version helper functions should be implemented in `src/lib_c/x86_64-windows-msvc/version_helpers.cr`.  
`GetVersionExW` should be a symbol in `Kernel32.lib`, you just need to define the lib fun (in `sysinfoapi.h`).

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 15, 2021, 11:14am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/10 "2021-04-15T11:14:46Z")

</div>

Actually, choosing which library function to call based on runtime properties isn’t trivial. Because when you do it like this:

```auto
if LibC.IsWindows8OrGreater
  LibC.GetSystemTimePreciseAsFileTime
else
  LibC.GetSystemTimeAsFileTime
end

```

The binary is still linked against both functions which fails for Windows 7.

This can be solved by a compile time flag to distinguish between windows 7- and windows 8+ APIs.

```auto
# compile with `crystal build -Dwindows7` to enable the latter path
{% unless flag?("windows7") %}
  LibC.GetSystemTimePreciseAsFileTime
{% else %}
  LibC.GetSystemTimeAsFileTime
{% end %}

```

That could be used for getting started, but it’s not a great because you’d need to build two different windows binaries.

A more sophisticated solution is to look up the potentially unavailable symbols dynamically at runtime.  
But that’s another step. For now, you could just use a compile time flag to get the basic implementation going.

---

<div class="post-metadata">

**Author:** ![qwertfisch](https://avatars.discourse-cdn.com/v4/letter/q/f9ae1b/32.png) [@qwertfisch](https://forum.crystal-lang.org/u/qwertfisch)\
**Post date:** [April 16, 2021, 12:24am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/11 "2021-04-16T00:24:26Z")

</div>

> [@straight-shoota](#):
>
> > [@qwertfisch](#):
> >
> > despite the fact that this is included in `VersionHelpers.h` in Windows SDK.
> 
> Features from header files are not available in the binary libraries. Everything provided in a header file needs to be implemented in Crystal.

I thought so, but on the other hand using `NtCurrentTeb()` compiles fine with referencing as library binding, despite it is an inline function in `winnt.h`. I am a bit confused here.

> [@straight-shoota](#):
>
> `GetVersionExW` should be a symbol in `Kernel32.lib`, you just need to define the lib fun (in `sysinfoapi.h`).

Thanks. I tested some similar function definitions yesterday, but they did not work that way. (Also it was too late for coding.) I discovered today these were randomly chosen from `User32.lib`, which seem to not be in the library search path. This has nothing to do with this issue, but I am curious if `User32.lib` would need to be defined somewhere? Or some functions are found and others … not?

> [@straight-shoota](#):
>
> Actually, choosing which library function to call based on runtime properties isn’t trivial. Because when you do it like this:
> 
> ```cr
> if LibC.IsWindows8OrGreater
> LibC.GetSystemTimePreciseAsFileTime
> else
> LibC.GetSystemTimeAsFileTime
> end
> 
> ```
> 
> The binary is still linked against both functions which fails for Windows 7.

Ah thanks for the hint. I did not consider this yesterday and would have clearly bumped into this problem as soon as the version check works. So it’s no use of reimplementing the version helper functions now …

My Windows7-only compilation already works, I just wanted to implement the version check the best way possible. Is it ok using the simple check via compiler flag and then file a pull request on the issue?

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 16, 2021, 10:54am UTC](https://forum.crystal-lang.org/t/will-there-be-cross-compile-support-for-windows-7/3168/12 "2021-04-16T10:54:33Z")

</div>

> [@qwertfisch](#):
>
> on the other hand using `NtCurrentTeb()` compiles fine with referencing as library binding, despite it is an inline function in `winnt.h` . I am a bit confused here.

Huh, that seems… unlikely. Maybe some lib has this symbol though for whatever reason. It’s hard to say without seeing the thing happen. It looks a bit weird, but I’m sure there’s a reasonable explanation. But there’s no way this could miraculously appear out of a header file in Crysta land.

> [@qwertfisch](#):
>
> This has nothing to do with this issue, but I am curious if `User32.lib` would need to be defined somewhere?

Yeah it seems you would need to add information for the linker to know it has to link `User32.lib`. It seems, until now we don’t use any function from that library.  
An example for this would be in `ntsecapi.cr` which defines a function `RtlGenRandom` provided by `Advapi32.dll`. That’s indicated by the linker annotation `@[Link("advapi32")]`.

> [@qwertfisch](#):
>
> Is it ok using the simple check via compiler flag and then file a pull request on the issue?

Yes, sure. Having the Windows 7 implementation done is already a good progress. Even if it temporarily means we can’t have a single executable.
