Compiling Crystal shared libary on Windows

I can compile a shared library for use in C using an example from stack overflow (questions/32916684) on Linux.

For the life of me I can’t do the same on Windows using the Windows Crystal implementation and MSVC 2022 (cl.exe).

Anyone any ideas if this is possible?

The command on Linux is:

crystal build --single-module --link-flags=“-shared” -o liblogger.so

none of the cl.exe flags work in place of “-shared” though, and the various other approaches I tried.

--link-flags=/DLL -o logger.dll

However, as you might have noticed, the Crystal runtime is not really prepared for use as a shared library yet. Additionally, currently this will build a DLL that links to the Microsoft C runtime statically (i.e. /MT), which is discouraged.

It does produce a DLL, I tried this flag earlier. A dumpbin /EXPORTS liblogger.dll shows no exported functions strangely.

A lib file is also not produced which can be linked against it. There doesn’t seem to be any compiler flags for crystal build to pass “/LD” to get a lib file.

Exactly. If -shared produces a file that exports something on Linux that is also by sheer coincidence rather than by design.

Fixed it. If I use --verbose I can see the command it is running with cl.exe - I can then modify that and add /LD and /DEF:liblogger.def on the end. I had to create a def file manually. I got the functions to use in the def file from nm liblogger.obj | grep crystal_ in WSL.

Complete command is:

C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.36.32532\bin\Hostx64\x64\cl.exe" /nologo /LD liblogger.obj /link “/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.36.32532\atlmfc\lib\x64” “/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.36.32532\lib\x64” “/LIBPATH:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22000.0\ucrt\x64” “/LIBPATH:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22000.0\um\x64” /DEBUG:FULL /PDBALTPATH:%_PDB% /INCREMENTAL:NO /STACK:0x800000 /LIBPATH:C:\Users\jools\scoop\apps\crystal\current\lib pcre2-8.lib gc.lib libcmt.lib iconv.lib advapi32.lib Kernel32.lib shell32.lib ole32.lib WS2_32.lib kernel32.lib legacy_stdio_definitions.lib DbgHelp.lib libucrt.lib /DEF:liblogger.def

Churns out:
Creating library liblogger.lib and object liblogger.exp

Then:
C:\Users\jools\tmp\crystal>main.exe
Hello world!

And for anyone else:

C:\Users\jools\tmp\crystal>more liblogger.def
LIBRARY liblogger
EXPORTS
__crystal_main
__crystal_malloc
__crystal_malloc64
__crystal_malloc_atomic
__crystal_malloc_atomic64
__crystal_once
__crystal_once_init
__crystal_raise
__crystal_raise_overflow
__crystal_raise_string
__crystal_realloc
__crystal_realloc64
crystal_init
crystal_log

C:\Users\jools\tmp\crystal>more logger.cr
fun init = crystal_init : Void

GC.init

LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null)
end

fun log = crystal_log(text: UInt8*): Void
puts String.new(text)
end

C:\Users\jools\tmp\crystal>more logger.h
#ifndef _CRYSTAL_LOGGER_H
#define _CRYSTAL_LOGGER_H

void crystal_init(void);
void crystal_log(char* text);
#endif

C:\Users\jools\tmp\crystal>more main.c
#include “logger.h”

int main(void) {
crystal_init();
crystal_log(“Hello world!”);
}

A complete run:

crystal build logger.cr --single-module --emit obj --verbose

mv logger.obj liblogger.obj

Copy command and remove /ENTRY:wmainCRTStartup ; add /LD and /DEF:liblogger.def ; to get:

“C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.36.32532\bin\Hostx64\x64\cl.exe” /nologo /LD liblogger.obj /link “/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.36.32532\atlmfc\lib\x64” “/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.36.32532\lib\x64” “/LIBPATH:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22000.0\ucrt\x64” “/LIBPATH:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22000.0\um\x64” /DEBUG:FULL /PDBALTPATH:%_PDB% /INCREMENTAL:NO /STACK:0x800000 /LIBPATH:C:\Users\jools\scoop\apps\crystal\current\lib pcre2-8.lib gc.lib libcmt.lib iconv.lib advapi32.lib Kernel32.lib shell32.lib ole32.lib WS2_32.lib kernel32.lib legacy_stdio_definitions.lib DbgHelp.lib libucrt.lib /DEF:liblogger.def

cl main.c /link liblogger.lib

C:\Users\jools\tmp\crystal>main.exe
Hello world!