Skip to content
Daniel Worrall edited this page Feb 27, 2020 · 55 revisions

This page will give some help and rules for working on porting Crystal to windows. Ongoing efforts will be tracked and coordinated in #5430.

To compile Crystal for windows, you need to cross-compile from a supported platform (Ubuntu on Windows Subsystem for Linux or native/virtual machine running Linux or Mac OSX).

When running WSL with Ubuntu, it's recommended to use Ubuntu 16.04.

Install libraries

A script is available to automate building the required libraries to experiment with Crystal on Windows.

  1. Download the script from here and the Build Tools for Visual Studio 2017 installer (Scroll down to Tools for Visual Studio 2017)

  1. Place the downloaded script and build tools installer side-by-side in a new empty folder. Rename the build tools installer to vs_buildtools.exe.

  1. Right-click on the PowerShell script and select "Run with PowerShell".

  1. Accept the execution policy change if required.

  1. Keep the PowerShell window open while you wait for the Visual Studio Installer to complete, then wait for the download and compile steps to complete after the visual studio installer finishes.

  1. After the PowerShell window closes, the pcre.lib and gc.lib should be present in the folder, adjacent to the libraries script.

Hello World

To see if it works run the following on Linux/Mac:

$ echo 'puts "Hello world!"' > hello_world.cr
$ bin/crystal build --cross-compile -Dgc_none --target x86_64-pc-windows-msvc hello_world.cr

The compiler should print a linker command and emit an object file (here called hello_world.o). The object file needs to be copied onto a Windows machine, and put into the same directory that the libraries script was run. After that, the linker command needs to be run in the same directory as the object file on Windows in the Developer Command Prompt for VS 2017 (should be in the start menu if you have installed VS Build Tools).

> cd C:\Crystal\
> cl "hello_world.o" "/Fehello_world"  pcre.lib gc.lib libcmt.lib
> hello_world.exe
Hello world!

Replace C:\Crystal with the directory the libraries script was run in.

VS 2019

With Visual Studio 2019 you need to use the x86_64 Cross Tools Command Prompt for vs 2019 running the following commands:

> cd C:\Crystal\
> cl "hello_world.o" "/Fehello_world" pcre.lib gc.lib advapi32.lib libcmt.lib legacy_stdio_definitions.lib
> hello_world.exe
Hello world!

crystal-windows Script

crystal-windows script for use with a windows-native ssh server:

#!/bin/sh
set -euo pipefail

windows=192.168.122.76

bin/crystal build --progress --cross-compile --target x86_64-unknown-windows-msvc -o .build/cross "${@}"
scp .build/cross.o $windows:'C:\Crystal\cross.obj'

cat <<'EOF' | ssh $windows cmd /S /C "C:\Program^ Files^ ^(x86^)\Microsoft^ Visual^ Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat x64 && powershell -Command -"
cd C:\Crystal
del cross.exe

cl cross.obj /Fecross pcre.lib gc.lib advapi32.lib libcmt.lib # C:\data\programming\crystal-lang\crystal\windows\src\llvm\ext\llvm_ext.obj "$(llvm-config --libs --system-libs --ldflags --link-static)"

echo ""
./cross.exe --verbose
EOF

Replace C:\Crystal with the directory the libraries script was run in.

Bindings

Just match namings 1:1 for types, functions and struct fields as much as possible. If Windows uses UPPERCASE, then use UPPERCASE, if it uses CamelCase then use CamelCase, and so on. The only exception is lowercased type names, which must be transformed. Habit in bindings is to CamelCase them (e.g. size_t -> SizeT).

Binding functions can start with an uppercase letter since some versions back, so LibC.GetTimeZoneInformation or LibC.LLVMDisposeModule work nicely.

How to Build Libs

These are instructions on how to manually build the libraries on Windows (original instructions by @txe). Currently, only pcre.lib and gc.lib are required.

Each lib should be build in a custom build folder (called build_path) and the built lib files need to be in PATH for running the linker on Windows.

LibPCRE

Install cmake Download and unpack libpcre 8.42

mkdir build && cd build
cmake .. -G "Visual Studio 15 2017 Win64" -DBUILD_SHARED_LIBS=OFF -DPCRE_SUPPORT_UNICODE_PROPERTIES=ON ^
         -DPCRE_SUPPORT_JIT=ON -DPCRE_STATIC_RUNTIME=ON
cmake --build . --config release

The lib file is in release/pcre.lib

LibGC

git clone -b v7.6.4 https://github.com/ivmai/bdwgc/
cd bdwgc
git clone -b v7.6.2 https://github.com/ivmai/libatomic_opts

Download win32.mak (Gist win32.mak) and save it as ntwin32.mak in current folder (bwdgc/)

Now you can run nmake. Note that at least this command needs to be run in Visual C++ 2015 x64 Native Build Tools Command Prompt inside bwdgc/ folder:

nmake -f NT_X64_STATIC_THREADS_MAKEFILE nodebug=1 _CL_=-DDONT_USE_USER32_DLL

LLVM

cmake .. -G "Visual Studio 15 2017 Win64" -Thost=x64 ^
         -DCMAKE_INSTALL_PREFIX="C:\Program Files\llvm" ^
         -DLLVM_TARGETS_TO_BUILD="X86" -DLLVM_PARALLEL_LINK_JOBS=1 ^
         -DLLVM_BUILD_LLVM_DYLIB=ON -DLLVM_USE_CRT_RELEASE=MT
cmake --build . --config release
cmake --build . --config release --target install