Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 5,350
    • Issues 5,350
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 575
    • Merge requests 575
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell CompilerGlasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #22159
Closed
Open
Issue created Sep 09, 2022 by Ryan Scott@RyanGlScottMaintainer

GHC 9.4+: Clang on Windows doesn't define _UCRT macro

(Originally spun out of a discussion at https://github.com/Mistuke/CabalChoco/issues/5.)

I discovered recently that hsc2hs-0.68.8 fails to build on Windows with GHC 9.4.2 when /mingw64/include is added to the C_INCLUDE_PATH:

$ cabal install hsc2hs -w ghc-9.4.2
Resolving dependencies...
Build profile: -w ghc-9.4.2 -O1
In order, the following will be built (use -v for more details):
 - hsc2hs-0.68.8 (exe:hsc2hs) (requires build)
Starting     hsc2hs-0.68.8 (exe:hsc2hs)
Building     hsc2hs-0.68.8 (exe:hsc2hs)

Failed to build exe:hsc2hs from hsc2hs-0.68.8.
Build log (
C:\cabal\logs\ghc-9.4.2\hsc2hs-0.68.8-dca6bac3c0afc2e67bbbc32a66df4cfb082b5015.log
):
Preprocessing executable 'hsc2hs' for hsc2hs-0.68.8..
Building executable 'hsc2hs' for hsc2hs-0.68.8..
[ 1 of 12] Compiling ATTParser        ( src\ATTParser.hs, dist\build\hsc2hs\hsc2hs-tmp\ATTParser.o )
[ 2 of 12] Compiling Compat.ResponseFile ( src\Compat\ResponseFile.hs, dist\build\hsc2hs\hsc2hs-tmp\Compat\ResponseFile.o )
[ 3 of 12] Compiling Compat.TempFile  ( src\Compat\TempFile.hs, dist\build\hsc2hs\hsc2hs-tmp\Compat\TempFile.o )
[ 4 of 12] Compiling Common           ( src\Common.hs, dist\build\hsc2hs\hsc2hs-tmp\Common.o )
[ 5 of 12] Compiling Flags            ( src\Flags.hs, dist\build\hsc2hs\hsc2hs-tmp\Flags.o )
[ 6 of 12] Compiling HSCParser        ( src\HSCParser.hs, dist\build\hsc2hs\hsc2hs-tmp\HSCParser.o )
[ 7 of 12] Compiling C                ( src\C.hs, dist\build\hsc2hs\hsc2hs-tmp\C.o )
[ 8 of 12] Compiling CrossCodegen     ( src\CrossCodegen.hs, dist\build\hsc2hs\hsc2hs-tmp\CrossCodegen.o )
[ 9 of 12] Compiling Paths_hsc2hs     ( dist\build\hsc2hs\autogen\Paths_hsc2hs.hs, dist\build\hsc2hs\hsc2hs-tmp\Paths_hsc2hs.o )
[10 of 12] Compiling UtilsCodegen     ( src\UtilsCodegen.hs, dist\build\hsc2hs\hsc2hs-tmp\UtilsCodegen.o )
[11 of 12] Compiling DirectCodegen    ( src\DirectCodegen.hs, dist\build\hsc2hs\hsc2hs-tmp\DirectCodegen.o )
[12 of 12] Compiling Main             ( src\Main.hs, dist\build\hsc2hs\hsc2hs-tmp\Main.o )
[13 of 13] Linking dist\\build\\hsc2hs\\hsc2hs.exe
ld.lld: error: undefined symbol: swprintf_s
>>> referenced by dist\build\hsc2hs\hsc2hs-tmp\cbits\utils.o:(__get_temp_file_name)
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ghc-9.4.2.exe: `clang.exe' failed in phase `Linker'. (Exit code: 1)
Error: cabal-3.8.1.0.exe: Failed to build exe:hsc2hs from hsc2hs-0.68.8. See
the build log above for details.

This is unexpected, since the Clang toolchain that comes bundled with GHC 9.4.2 uses the same header files as MinGW-w64. I minimized the issue down to the following test case:

// hello.c
#include <stdio.h>
#include <wchar.h>

void hello(wchar_t *buf) {
  swprintf_s(buf, 12, L"hello");
}
-- Main.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE ForeignFunctionInterface #-}
module Main (main) where

#if defined(i386_HOST_ARCH)
# define WINDOWS_CCONV stdcall
#elif defined(x86_64_HOST_ARCH)
# define WINDOWS_CCONV ccall
#else
# error Unknown mingw32 arch
#endif

import Foreign.C.String (peekCWString)
import Foreign.C.Types (CWchar)
import Foreign.Marshal.Alloc (allocaBytes)
import Foreign.Ptr (Ptr)

foreign import WINDOWS_CCONV "hello" c_hello :: Ptr CWchar -> IO ()

main :: IO ()
main = allocaBytes 12 $ \buf -> do
  c_hello buf
  str <- peekCWString buf
  putStrLn str

If you compile this without C_INCLUDE_PATH defined, then it succeeds:

$ C_INCLUDE_PATH="" ghc Main.hs hello.c -fforce-recomp -o Main.exe && ./Main.exe
[1 of 2] Compiling Main             ( Main.hs, Main.o )
[2 of 2] Linking Main.exe
hello

On the other hand, if you do define C_INCLUDE_PATH, then it fails to link:

$ C_INCLUDE_PATH=/mingw64/include ghc Main.hs hello.c -fforce-recomp -o Main.exe && ./Main.exe
[1 of 2] Compiling Main             ( Main.hs, Main.o )
[2 of 2] Linking Main.exe [Objects changed]
ld.lld: error: undefined symbol: swprintf_s
>>> referenced by hello.o:(hello)
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ghc-9.4.2.exe: `clang.exe' failed in phase `Linker'. (Exit code: 1)

According to @Phyx, the reason this happens is because GHC is not defining the _UCRT CPP macro, which is crucial for linking against UCRT (as Clang is set up to do). Indeed, if I repeat the last step with -D_UCRT, then it succeeds:

$ C_INCLUDE_PATH=/mingw64/include ghc Main.hs hello.c -fforce-recomp -o Main.exe -D_UCRT && ./Main.exe
[1 of 2] Compiling Main             ( Main.hs, Main.o )
[2 of 2] Linking Main.exe
hello

@Phyx says that GHC should define the _UCRT macro, just like it defines the WINVER macro.

Edited Sep 09, 2022 by Ryan Scott
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking