diff --git a/.github/workflows/mingw-w64.yml b/.github/workflows/mingw-w64.yml index 10841a325bf5..13ef48a3148b 100644 --- a/.github/workflows/mingw-w64.yml +++ b/.github/workflows/mingw-w64.yml @@ -80,7 +80,7 @@ jobs: shell: msys2 {0} run: | mkdir bin - cc crystal.obj -o bin/crystal.exe \ + cc crystal.obj -o bin/crystal.exe -municode \ $(pkg-config bdw-gc libpcre2-8 iconv zlib libffi --libs) \ $(llvm-config --libs --system-libs --ldflags) \ -lDbgHelp -lole32 -lWS2_32 -Wl,--stack,0x800000 diff --git a/src/compiler/crystal/loader/mingw.cr b/src/compiler/crystal/loader/mingw.cr index 677f564cec16..2c557a893640 100644 --- a/src/compiler/crystal/loader/mingw.cr +++ b/src/compiler/crystal/loader/mingw.cr @@ -7,6 +7,8 @@ require "crystal/system/win32/library_archive" # The core implementation is derived from the MSVC loader. Main deviations are: # # - `.parse` follows GNU `ld`'s style, rather than MSVC `link`'s; +# - `.parse` automatically inserts a C runtime library if `-mcrtdll` isn't +# supplied; # - `#library_filename` follows the usual naming of the MinGW linker: `.dll.a` # for DLL import libraries, `.a` for other libraries; # - `.default_search_paths` relies solely on `.cc_each_library_path`. @@ -28,6 +30,11 @@ class Crystal::Loader file_paths = [] of String extra_search_paths = [] of String + # note that `msvcrt` is a default runtime chosen at MinGW-w64 build time, + # `ucrt` is always UCRT (even in a MINGW64 environment), and + # `msvcrt-os` is always MSVCRT (even in a UCRT64 environment) + crt_dll = "msvcrt" + OptionParser.parse(args.dup) do |parser| parser.on("-L DIRECTORY", "--library-path DIRECTORY", "Add DIRECTORY to library search path") do |directory| extra_search_paths << directory @@ -39,17 +46,21 @@ class Crystal::Loader raise LoadError.new "static libraries are not supported by Crystal's runtime loader" end parser.unknown_args do |args, after_dash| - file_paths.concat args + file_paths.concat args.reject(&.starts_with?("-mcrtdll=")) end parser.invalid_option do |arg| - unless arg.starts_with?("-Wl,") + if crt_dll_arg = arg.lchop?("-mcrtdll=") + # the GCC spec is `%{!mcrtdll=*:-lmsvcrt} %{mcrtdll=*:-l%*}` + crt_dll = crt_dll_arg + elsif !arg.starts_with?("-Wl,") raise LoadError.new "Not a recognized linker flag: #{arg}" end end end search_paths = extra_search_paths + search_paths + libnames << crt_dll begin loader = new(search_paths) diff --git a/src/crystal/system/win32/wmain.cr b/src/crystal/system/win32/wmain.cr index caad6748229f..2120bfc06bfc 100644 --- a/src/crystal/system/win32/wmain.cr +++ b/src/crystal/system/win32/wmain.cr @@ -2,14 +2,12 @@ require "c/stringapiset" require "c/winnls" require "c/stdlib" -{% begin %} - # we have both `main` and `wmain`, so we must choose an unambiguous entry point +# we have both `main` and `wmain`, so we must choose an unambiguous entry point +{% if flag?(:msvc) %} @[Link({{ flag?(:static) ? "libcmt" : "msvcrt" }})] - {% if flag?(:msvc) %} - @[Link(ldflags: "/ENTRY:wmainCRTStartup")] - {% elsif flag?(:gnu) && !flag?(:interpreted) %} - @[Link(ldflags: "-municode")] - {% end %} + @[Link(ldflags: "/ENTRY:wmainCRTStartup")] +{% elsif flag?(:gnu) && !flag?(:interpreted) %} + @[Link(ldflags: "-municode")] {% end %} lib LibCrystalMain end diff --git a/src/empty.cr b/src/empty.cr index 204e30da48c0..cb79610a5be3 100644 --- a/src/empty.cr +++ b/src/empty.cr @@ -1,6 +1,6 @@ require "primitives" -{% if flag?(:win32) %} +{% if flag?(:msvc) %} @[Link({{ flag?(:static) ? "libcmt" : "msvcrt" }})] # For `mainCRTStartup` {% end %} lib LibCrystalMain diff --git a/src/lib_c.cr b/src/lib_c.cr index 0bd8d2c2cc35..7bc94a34f53e 100644 --- a/src/lib_c.cr +++ b/src/lib_c.cr @@ -1,4 +1,4 @@ -{% if flag?(:win32) %} +{% if flag?(:msvc) %} @[Link({{ flag?(:static) ? "libucrt" : "ucrt" }})] {% end %} lib LibC