David Eichmann pushed to branch wip/dcoutts/windows-rts-dll at Glasgow Haskell Compiler / GHC Commits: 3eed75d2 by Duncan Coutts at 2026-05-06T17:58:12+01:00 Add minimal dlltool support into ./configure Find dlltool, and hopefully support finding it within the bundled llvm toolchain on windows. - - - - - 9a074a69 by Duncan Coutts at 2026-05-06T17:58:14+01:00 Update the default host and target files for dlltool support - - - - - 5fdb97fd by Duncan Coutts at 2026-05-06T17:58:14+01:00 Add dlltool as a hadrian builder Optional except on windows. - - - - - 6b7d555f by Duncan Coutts at 2026-05-06T17:58:14+01:00 Update and generate libHSghc-internal.def from .def.in file The only symbol that the rts imports from the ghc-internal package now is init_ghc_hs_iface. So the rts only needs an import lib that defines that one symbol. Also, remove the libHSghc-prim.def because it is redundant. The rts no longer imports anything from ghc-prim. Keep libHSffi.def for now. We may yet need it once it is clear how libffi is going to be built/used for ghc. - - - - - f195d87e by Duncan Coutts at 2026-05-06T17:58:14+01:00 Add rule to build libHSghc-internal.dll.a and link into the rts On windows only, with dynamic linking. This is needed because on windows, all symbols in dlls must be resolved. No dangling symbols allowed. References to external symbols must be explicit. We resolve this with an import library. We create an import library for ghc-internal, a .dll.a file. This is a static archive containing .o files that define the symbols we need, and crucially have ".idata" sections that specifies the symbols the dll imports and from where. Note that we do not install this libHSghc-internal.dll.a, and it does not need to list all the symbols exported by that package. We create a special purpose import lib and only use it when linking the rts dll, so it only has to list the symbols that the rts uses from ghc-internal (which is exactly one symbol: init_ghc_hs_iface). - - - - - 15 changed files: - configure.ac - distrib/configure.ac.in - hadrian/cfg/default.host.target.in - hadrian/cfg/default.target.in - hadrian/src/Builder.hs - hadrian/src/Rules/Generate.hs - hadrian/src/Rules/Library.hs - hadrian/src/Rules/Rts.hs - m4/find_llvm_prog.m4 - m4/fp_setup_windows_toolchain.m4 - m4/ghc_toolchain.m4 - m4/prep_target_file.m4 - rts/.gitignore - + rts/win32/libHSghc-internal.def.in - utils/ghc-toolchain/exe/Main.hs Changes: ===================================== configure.ac ===================================== @@ -314,13 +314,16 @@ else AC_CHECK_TOOL([RANLIB],[ranlib]) AC_CHECK_TOOL([OBJDUMP],[objdump]) AC_CHECK_TOOL([WindresCmd],[windres]) + AC_CHECK_TOOL([DlltoolCmd],[llvm-dlltool]) AC_CHECK_TOOL([Genlib],[genlib]) if test "$HostOS" = "mingw32"; then AC_CHECK_TARGET_TOOL([WindresCmd],[windres]) + AC_CHECK_TARGET_TOOL([DlltoolCmd],[llvm-dlltool]) AC_CHECK_TARGET_TOOL([OBJDUMP],[objdump]) WindresCmd="$(cygpath -m $WindresCmd)" + DlltoolCmd="$(cygpath -m $DlltoolCmd)" if test "$Genlib" != ""; then GenlibCmd="$(cygpath -m $Genlib)" @@ -568,6 +571,11 @@ FIND_LLVM_PROG([OPT], [opt], [$LlvmMinVersion], [$LlvmMaxVersion]) OptCmd="$OPT" AC_SUBST([OptCmd]) +dnl ** Which LLVM llvm-dlltool to use? +dnl -------------------------------------------------------------- +AC_ARG_VAR(DlltoolCmd,[Use as the path to LLVM's llvm-dlltool [default=autodetect]]) +FIND_LLVM_PROG([DlltoolCmd], [llvm-dlltool], [$LlvmMinVersion], [$LlvmMaxVersion]) + dnl ** look to see if we have a C compiler using an llvm back end. dnl FP_CC_LLVM_BACKEND @@ -1080,9 +1088,10 @@ echo "\ libdw : $UseLibdw Using LLVM tools - llc : $LlcCmd - opt : $OptCmd - llvm-as : $LlvmAsCmd" + llc : $LlcCmd + opt : $OptCmd + llvm-as : $LlvmAsCmd + llvm-dlltool : $DlltoolCmd" if test "$HSCOLOUR" = ""; then echo " ===================================== distrib/configure.ac.in ===================================== @@ -229,6 +229,13 @@ FIND_LLVM_PROG([LLVMAS], [clang], [$LlvmMinVersion], [$LlvmMaxVersion]) LlvmAsCmd="$LLVMAS" AC_SUBST([LlvmAsCmd]) +dnl ** Which LLVM llvm-dlltool to use? +dnl -------------------------------------------------------------- +AC_CHECK_TARGET_TOOL([DlltoolCmd],[llvm-dlltool]) +AC_ARG_VAR(DlltoolCmd,[Use as the path to LLVM's llvm-dlltool [default=autodetect]]) +FIND_LLVM_PROG([DlltoolCmd], [llvm-dlltool], [$LlvmMinVersion], [$LlvmMaxVersion]) +AC_SUBST([DlltoolCmd]) + dnl We know that `clang` supports `--target` and it is necessary to pass it dnl lest we see #25793. if test -z "$LlvmAsFlags" && ! test -z "$LlvmTarget"; then ===================================== hadrian/cfg/default.host.target.in ===================================== @@ -45,6 +45,7 @@ Target , tgtOpt = Nothing , tgtLlvmAs = Nothing , tgtWindres = Nothing +, tgtDlltool = Nothing , tgtOtool = Nothing , tgtInstallNameTool = Nothing } ===================================== hadrian/cfg/default.target.in ===================================== @@ -45,6 +45,7 @@ Target , tgtOpt = @OptCmdMaybeProg@ , tgtLlvmAs = @LlvmAsCmdMaybeProg@ , tgtWindres = @WindresCmdMaybeProg@ +, tgtDlltool = @DlltoolCmdMaybeProg@ , tgtOtool = @OtoolCmdMaybeProg@ , tgtInstallNameTool = @InstallNameToolCmdMaybeProg@ } ===================================== hadrian/src/Builder.hs ===================================== @@ -17,7 +17,7 @@ import Development.Shake.Classes import Development.Shake.Command import Development.Shake.FilePath import GHC.Generics -import GHC.Platform.ArchOS (ArchOS(..), Arch(..)) +import GHC.Platform.ArchOS (ArchOS(..), Arch(..), OS(..)) import qualified Hadrian.Builder as H import Hadrian.Builder hiding (Builder) import Hadrian.Builder.Ar @@ -180,6 +180,7 @@ data Builder = Alex | Objdump | Python | Ranlib + | Dlltool | Testsuite TestMode | Sphinx SphinxMode | Tar TarMode @@ -418,6 +419,7 @@ isOptional target = \case Alex -> True -- Most ar implemententions no longer need ranlib, but some still do Ranlib -> not $ Toolchain.arNeedsRanlib (tgtAr target) + Dlltool -> archOS_OS (tgtArchOs target) /= OSMinGW32 JsCpp -> not $ (archOS_arch . tgtArchOs) target == ArchJavaScript -- ArchWasm32 too? _ -> False @@ -442,6 +444,7 @@ systemBuilderPath builder = case builder of Objdump -> fromKey "objdump" Python -> fromKey "python" Ranlib -> fromTargetTC "ranlib" (maybeProg Toolchain.ranlibProgram . tgtRanlib) + Dlltool -> fromTargetTC "dlltool" (maybeProg id . tgtDlltool) Testsuite _ -> fromKey "python" Sphinx _ -> fromKey "sphinx-build" Tar _ -> fromKey "tar" ===================================== hadrian/src/Rules/Generate.hs ===================================== @@ -377,6 +377,7 @@ templateRules = do , interpolateSetting "ProjectPatchLevel1" ProjectPatchLevel1 , interpolateSetting "ProjectPatchLevel2" ProjectPatchLevel2 ] + templateRule "rts/win32/libHSghc-internal.def" projectVersion templateRule "docs/index.html" $ packageUnitIds Stage1 templateRule "docs/users_guide/ghc_config.py" $ mconcat [ projectVersion ===================================== hadrian/src/Rules/Library.hs ===================================== @@ -4,6 +4,8 @@ import Hadrian.BuildPath import Hadrian.Haskell.Cabal import Hadrian.Haskell.Cabal.Type import qualified Text.Parsec as Parsec +import GHC.Platform.ArchOS (ArchOS(archOS_OS), OS(..)) +import GHC.Toolchain.Target (Target(tgtArchOs)) import Base import Context @@ -185,9 +187,13 @@ jsObjects context = do srcs <- interpretInContext context (getContextData jsSrcs) mapM (objectPath context) srcs --- | Return extra object files needed to build the given library context. The --- resulting list is currently non-empty only when the package from the --- 'Context' is @ghc-internal@ built with in-tree GMP backend. +-- | Return extra object files needed to build the given library context. +-- +-- This is non-empty for: +-- +-- * @ghc-internal@ when built with in-tree GMP backend +-- * @rts@ on Windows when linking dynamically +-- extraObjects :: Context -> Action [FilePath] extraObjects context | package context == ghcInternal = do @@ -195,6 +201,13 @@ extraObjects context "gmp" -> gmpObjects (stage context) _ -> return [] + | package context == rts = do + target <- interpretInContext context getStagedTarget + builddir <- buildPath context + return [ builddir -/- "libHSghc-internal.dll.a" + | archOS_OS (tgtArchOs target) == OSMinGW32 + , Dynamic `wayUnit` way context ] + | otherwise = return [] -- | Return all the object files to be put into the library we're building for ===================================== hadrian/src/Rules/Rts.hs ===================================== @@ -24,6 +24,20 @@ rtsRules = priority 3 $ do (addRtsDummyVersion $ takeFileName rtsLibFilePath') rtsLibFilePath' + -- Solve the recursive dependency between the rts and ghc-internal + -- on Windows by creating an import lib for the ghc-internal dll, + -- to be linked into the rts dll. + forM_ [Stage1, Stage2, Stage3 ] $ \ stage -> do + let buildPath = root -/- buildDir (rtsContext stage) + buildPath -/- "libHSghc-internal.dll.a" %> buildGhcInternalImportLib + +buildGhcInternalImportLib :: FilePath -> Action () +buildGhcInternalImportLib target = do + let input = "rts/win32/libHSghc-internal.def" + output = target -- the .dll.a import lib + need [input] + runBuilder Dlltool ["-d", input, "-l", output] [input] [output] + -- Need symlinks generated by rtsRules. needRtsSymLinks :: Stage -> Set.Set Way -> Action () needRtsSymLinks stage rtsWays ===================================== m4/find_llvm_prog.m4 ===================================== @@ -16,9 +16,12 @@ AC_DEFUN([FIND_LLVM_PROG],[ AS_IF([test x"$$1" != x],[ PROG_VERSION=`$$1 --version | sed -n -e 's/.*version \(\([[0-9]][[0-9]]*\.\)\([[0-9]][[0-9]]*\.\)*[[0-9]][[0-9]]*\).*/\1/gp'` AS_IF([test x"$PROG_VERSION" = x], - [AC_MSG_RESULT(no) - $1="" - AC_MSG_NOTICE([We only support llvm $3 upto $4 (non-inclusive) (no version found).])], + [AS_IF( + [test x"$2" = x"llvm-dlltool"], + [AC_MSG_RESULT(yes)], # llvm-dlltool doesn't have a --version + [AC_MSG_RESULT(no) + AC_MSG_NOTICE([We only support llvm $3 upto $4 (non-inclusive) (no version found).])] + )], [AC_MSG_CHECKING([$$1 version ($PROG_VERSION) is between $3 and $4]) AX_COMPARE_VERSION([$PROG_VERSION], [lt], [$3], [AC_MSG_RESULT(no) ===================================== m4/fp_setup_windows_toolchain.m4 ===================================== @@ -131,8 +131,8 @@ AC_DEFUN([FP_SETUP_WINDOWS_TOOLCHAIN],[ AR="${mingwbin}llvm-ar.exe" RANLIB="${mingwbin}llvm-ranlib.exe" OBJDUMP="${mingwbin}llvm-objdump.exe" - DLLTOOL="${mingwbin}llvm-dlltool.exe" WindresCmd="${mingwbin}llvm-windres.exe" + DlltoolCmd="${mingwbin}llvm-dlltool.exe" LLC="${mingwbin}llc.exe" OPT="${mingwbin}opt.exe" LLVMAS="${mingwbin}clang.exe" ===================================== m4/ghc_toolchain.m4 ===================================== @@ -95,6 +95,7 @@ AC_DEFUN([FIND_GHC_TOOLCHAIN], echo "--merge-objs=$MergeObjsCmd" >> acargs echo "--readelf=$READELF" >> acargs echo "--windres=$WindresCmd" >> acargs + echo "--dlltool=$DlltoolCmd" >> acargs echo "--llc=$LlcCmd" >> acargs echo "--opt=$OptCmd" >> acargs echo "--llvm-as=$LlvmAsCmd" >> acargs ===================================== m4/prep_target_file.m4 ===================================== @@ -191,6 +191,7 @@ AC_DEFUN([PREP_TARGET_FILE],[ PREP_MAYBE_SIMPLE_PROGRAM([OptCmd]) PREP_MAYBE_PROGRAM([LlvmAsCmd], [LlvmAsFlags]) PREP_MAYBE_SIMPLE_PROGRAM([WindresCmd]) + PREP_MAYBE_SIMPLE_PROGRAM([DlltoolCmd]) PREP_MAYBE_SIMPLE_PROGRAM([OtoolCmd]) PREP_MAYBE_SIMPLE_PROGRAM([InstallNameToolCmd]) PREP_MAYBE_STRING([TargetVendor_CPP]) ===================================== rts/.gitignore ===================================== @@ -20,3 +20,4 @@ /ghcautoconf.h.autoconf.in /ghcautoconf.h.autoconf /include/ghcautoconf.h +/win32/libHSghc-internal.def ===================================== rts/win32/libHSghc-internal.def.in ===================================== @@ -0,0 +1,4 @@ +LIBRARY libHSghc-internal-@ProjectVersionForLib@.0-ghc@ProjectVersion@.dll + +EXPORTS + init_ghc_hs_iface ===================================== utils/ghc-toolchain/exe/Main.hs ===================================== @@ -486,7 +486,7 @@ mkTarget opts = do -- for windows, also used for cross compiling windres <- optional $ findProgram "windres" (optWindres opts) ["windres"] - dlltool <- optional $ findProgram "dlltool" (optDlltool opts) ["dlltool", "llvm-dlltool"] + dlltool <- optional $ findProgram "dlltool" (optDlltool opts) ["llvm-dlltool"] -- Darwin-specific utilities (otool, installNameTool) <- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/3ea6bb3f3c11c0e300ac2c627d05cf0... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/3ea6bb3f3c11c0e300ac2c627d05cf0... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
David Eichmann (@DavidEichmann)