diff options
78 files changed, 685 insertions, 566 deletions
diff --git a/compiler/GHC/CmmToAsm/X86/CodeGen.hs b/compiler/GHC/CmmToAsm/X86/CodeGen.hs index 1fefe3a346..3d2a83c984 100644 --- a/compiler/GHC/CmmToAsm/X86/CodeGen.hs +++ b/compiler/GHC/CmmToAsm/X86/CodeGen.hs @@ -437,6 +437,25 @@ temporary, then do the other computation, and then use the temporary: ... (tmp) ... -} +{- +Note [%rip-relative addressing on x86-64] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +On x86-64 GHC produces code for use in the "small" or, when `-fPIC` is set, +"small PIC" code models defined by the x86-64 System V ABI (section 3.5.1 of +specification version 0.99). + +In general the small code model would allow us to assume that code is located +between 0 and 2^31 - 1. However, this is not true on Windows which, due to +high-entropy ASLR, may place the executable image anywhere in 64-bit address +space. This is problematic since immediate operands in x86-64 are generally +32-bit sign-extended values (with the exception of the 64-bit MOVABS encoding). +Consequently, to avoid overflowing we use %rip-relative addressing universally. +Since %rip-relative addressing comes essentially for free and makes linking far +easier, we use it even on non-Windows platforms. + +See also: the documentation for GCC's `-mcmodel=small` flag. +-} + -- | Check whether an integer will fit in 32 bits. -- A CmmInt is intended to be truncated to the appropriate @@ -1139,6 +1158,22 @@ getRegister' _ is32Bit (CmmLit (CmmInt 0 width)) in return (Any format code) +-- Handle symbol references with LEA and %rip-relative addressing. +-- See Note [%rip-relative addressing on x86-64]. +getRegister' platform is32Bit (CmmLit lit) + | is_label lit + , not is32Bit + = do let format = cmmTypeFormat (cmmLitType platform lit) + imm = litToImm lit + op = OpAddr (AddrBaseIndex EABaseRip EAIndexNone imm) + code dst = unitOL (LEA format op (OpReg dst)) + return (Any format code) + where + is_label (CmmLabel {}) = True + is_label (CmmLabelOff {}) = True + is_label (CmmLabelDiffOff {}) = True + is_label _ = False + -- optimisation for loading small literals on x86_64: take advantage -- of the automatic zero-extension from 32 to 64 bits, because the 32-bit -- instruction forms are shorter. @@ -1156,7 +1191,7 @@ getRegister' platform is32Bit (CmmLit lit) -- signed literals that fit in 32 bits, but we want unsigned -- literals here. -- note2: all labels are small, because we're assuming the - -- small memory model (see gcc docs, -mcmodel=small). + -- small memory model. See Note [%rip-relative addressing on x86-64]. getRegister' platform _ (CmmLit lit) = do let format = cmmTypeFormat (cmmLitType platform lit) @@ -1253,7 +1288,7 @@ getAmode e = do -- This is all just ridiculous, since it carefully undoes -- what mangleIndexTree has just done. CmmMachOp (MO_Sub _rep) [x, CmmLit lit@(CmmInt i _)] - | is32BitLit is32Bit lit + | is32BitLit platform lit -- assert (rep == II32)??? -> do (x_reg, x_code) <- getSomeReg x @@ -1261,7 +1296,7 @@ getAmode e = do return (Amode (AddrBaseIndex (EABaseReg x_reg) EAIndexNone off) x_code) CmmMachOp (MO_Add _rep) [x, CmmLit lit] - | is32BitLit is32Bit lit + | is32BitLit platform lit -- assert (rep == II32)??? -> do (x_reg, x_code) <- getSomeReg x @@ -1292,8 +1327,16 @@ getAmode e = do | not (isLit y) -- we already handle valid literals above. -> x86_complex_amode x y 0 0 + -- Handle labels with %rip-relative addressing since in general the image + -- may be loaded anywhere in the 64-bit address space (e.g. on Windows + -- with high-entropy ASLR). See Note [%rip-relative addressing on x86-64]. + CmmLit lit + | not is32Bit + , is_label lit + -> return (Amode (AddrBaseIndex EABaseRip EAIndexNone (litToImm lit)) nilOL) + CmmLit lit - | is32BitLit is32Bit lit + | is32BitLit platform lit -> return (Amode (ImmAddr (litToImm lit) 0) nilOL) -- Literal with offsets too big (> 32 bits) fails during the linking phase @@ -1313,7 +1356,11 @@ getAmode e = do _ -> do (reg,code) <- getSomeReg e return (Amode (AddrBaseIndex (EABaseReg reg) EAIndexNone (ImmInt 0)) code) - + where + is_label (CmmLabel{}) = True + is_label (CmmLabelOff{}) = True + is_label (CmmLabelDiffOff{}) = True + is_label _ = False -- | Like 'getAmode', but on 32-bit use simple register addressing @@ -1362,9 +1409,8 @@ getNonClobberedOperand (CmmLit lit) = Amode addr code <- memConstant (mkAlignment $ widthInBytes w) lit return (OpAddr addr, code) else do - is32Bit <- is32BitPlatform platform <- getPlatform - if is32BitLit is32Bit lit && not (isFloatType (cmmLitType platform lit)) + if is32BitLit platform lit && not (isFloatType (cmmLitType platform lit)) then return (OpImm (litToImm lit), nilOL) else getNonClobberedOperand_generic (CmmLit lit) @@ -1421,9 +1467,8 @@ getOperand (CmmLit lit) = do return (OpAddr addr, code) else do - is32Bit <- is32BitPlatform platform <- getPlatform - if is32BitLit is32Bit lit && not (isFloatType (cmmLitType platform lit)) + if is32BitLit platform lit && not (isFloatType (cmmLitType platform lit)) then return (OpImm (litToImm lit), nilOL) else getOperand_generic (CmmLit lit) @@ -1444,9 +1489,10 @@ getOperand_generic e = do (reg, code) <- getSomeReg e return (OpReg reg, code) -isOperand :: Bool -> CmmExpr -> Bool +isOperand :: Platform -> CmmExpr -> Bool isOperand _ (CmmLoad _ _ _) = True -isOperand is32Bit (CmmLit lit) = is32BitLit is32Bit lit +isOperand platform (CmmLit lit) + = is32BitLit platform lit || isSuitableFloatingPointLit lit isOperand _ _ = False @@ -1517,21 +1563,28 @@ getRegOrMem e = do (reg, code) <- getNonClobberedReg e return (OpReg reg, code) -is32BitLit :: Bool -> CmmLit -> Bool -is32BitLit is32Bit lit - | not is32Bit = case lit of +is32BitLit :: Platform -> CmmLit -> Bool +is32BitLit platform _lit + | target32Bit platform = True +is32BitLit platform lit = + case lit of CmmInt i W64 -> is32BitInteger i - -- assume that labels are in the range 0-2^31-1: this assumes the - -- small memory model (see gcc docs, -mcmodel=small). - CmmLabel _ -> True + -- Except on Windows, assume that labels are in the range 0-2^31-1: this + -- assumes the small memory model. Note [%rip-relative addressing on + -- x86-64]. + CmmLabel _ -> low_image -- however we can't assume that label offsets are in this range -- (see #15570) - CmmLabelOff _ off -> is32BitInteger (fromIntegral off) - CmmLabelDiffOff _ _ off _ -> is32BitInteger (fromIntegral off) + CmmLabelOff _ off -> low_image && is32BitInteger (fromIntegral off) + CmmLabelDiffOff _ _ off _ -> low_image && is32BitInteger (fromIntegral off) _ -> True -is32BitLit _ _ = True - - + where + -- Is the executable image certain to be located below 4GB? As noted in + -- Note [%rip-relative addressing on x86-64], this is not true on Windows. + low_image = + case platformOS platform of + OSMinGW32 -> False -- See Note [%rip-relative addressing on x86-64] + _ -> True -- Set up a condition code for a conditional branch. @@ -1584,14 +1637,14 @@ machOpToCond mo = case mo of -- passed back up the tree. condIntCode :: Cond -> CmmExpr -> CmmExpr -> NatM CondCode -condIntCode cond x y = do is32Bit <- is32BitPlatform - condIntCode' is32Bit cond x y +condIntCode cond x y = do platform <- getPlatform + condIntCode' platform cond x y -condIntCode' :: Bool -> Cond -> CmmExpr -> CmmExpr -> NatM CondCode +condIntCode' :: Platform -> Cond -> CmmExpr -> CmmExpr -> NatM CondCode -- memory vs immediate -condIntCode' is32Bit cond (CmmLoad x pk _) (CmmLit lit) - | is32BitLit is32Bit lit = do +condIntCode' platform cond (CmmLoad x pk _) (CmmLit lit) + | is32BitLit platform lit = do Amode x_addr x_code <- getAmode x let imm = litToImm lit @@ -1602,8 +1655,8 @@ condIntCode' is32Bit cond (CmmLoad x pk _) (CmmLit lit) -- anything vs zero, using a mask -- TODO: Add some sanity checking!!!! -condIntCode' is32Bit cond (CmmMachOp (MO_And _) [x,o2]) (CmmLit (CmmInt 0 pk)) - | (CmmLit lit@(CmmInt mask _)) <- o2, is32BitLit is32Bit lit +condIntCode' platform cond (CmmMachOp (MO_And _) [x,o2]) (CmmLit (CmmInt 0 pk)) + | (CmmLit lit@(CmmInt mask _)) <- o2, is32BitLit platform lit = do (x_reg, x_code) <- getSomeReg x let @@ -1622,9 +1675,8 @@ condIntCode' _ cond x (CmmLit (CmmInt 0 pk)) = do return (CondCode False cond code) -- anything vs operand -condIntCode' is32Bit cond x y - | isOperand is32Bit y = do - platform <- getPlatform +condIntCode' platform cond x y + | isOperand platform y = do (x_reg, x_code) <- getNonClobberedReg x (y_op, y_code) <- getOperand y let @@ -1633,9 +1685,8 @@ condIntCode' is32Bit cond x y return (CondCode False cond code) -- operand vs. anything: invert the comparison so that we can use a -- single comparison instruction. - | isOperand is32Bit x + | isOperand platform x , Just revcond <- maybeFlipCond cond = do - platform <- getPlatform (y_reg, y_code) <- getNonClobberedReg y (x_op, x_code) <- getOperand x let @@ -1644,8 +1695,7 @@ condIntCode' is32Bit cond x y return (CondCode False revcond code) -- anything vs anything -condIntCode' _ cond x y = do - platform <- getPlatform +condIntCode' platform cond x y = do (y_reg, y_code) <- getNonClobberedReg y (x_op, x_code) <- getRegOrMem x let @@ -1719,9 +1769,9 @@ assignMem_IntCode pk addr (CmmMachOp op [CmmLoad addr2 _ _, -- general case assignMem_IntCode pk addr src = do - is32Bit <- is32BitPlatform + platform <- getPlatform Amode addr code_addr <- getAmode addr - (code_src, op_src) <- get_op_RI is32Bit src + (code_src, op_src) <- get_op_RI platform src let code = code_src `appOL` code_addr `snocOL` @@ -1733,8 +1783,8 @@ assignMem_IntCode pk addr src = do -- return code where - get_op_RI :: Bool -> CmmExpr -> NatM (InstrBlock,Operand) -- code, operator - get_op_RI is32Bit (CmmLit lit) | is32BitLit is32Bit lit + get_op_RI :: Platform -> CmmExpr -> NatM (InstrBlock,Operand) -- code, operator + get_op_RI platform (CmmLit lit) | is32BitLit platform lit = return (nilOL, OpImm (litToImm lit)) get_op_RI _ op = do (reg,code) <- getNonClobberedReg op @@ -2563,12 +2613,12 @@ genCCall64 addr conv dest_regs args = do -- pass the arg into the given register reg_this_arg r -- "operand" args can be directly assigned into r - | isOperand False arg = do + | isOperand platform arg = do arg_code <- getAnyReg arg return (code, (acode `appOL` arg_code r)) -- The last non-operand arg can be directly assigned after its -- computation without going into a temporary register - | all (isOperand False) rest = do + | all (isOperand platform) rest = do arg_code <- getAnyReg arg return (code `appOL` arg_code r,acode) @@ -2864,11 +2914,21 @@ genSwitch expr targets = do else do (reg,e_code) <- getSomeReg indexExpr lbl <- getNewLabelNat - let op = OpAddr (AddrBaseIndex EABaseNone (EAIndex reg (platformWordSizeInBytes platform)) (ImmCLbl lbl)) - code = e_code `appOL` toOL [ - JMP_TBL op ids (Section ReadOnlyData lbl) lbl - ] - return code + let is32bit = target32Bit platform + if is32bit + then let op = OpAddr (AddrBaseIndex EABaseNone (EAIndex reg (platformWordSizeInBytes platform)) (ImmCLbl lbl)) + jmp_code = JMP_TBL op ids (Section ReadOnlyData lbl) lbl + in return $ e_code `appOL` unitOL jmp_code + else do + -- See Note [%rip-relative addressing on x86-64]. + tableReg <- getNewRegNat (intFormat (platformWordWidth platform)) + let op = OpAddr (AddrBaseIndex (EABaseReg tableReg) (EAIndex reg (platformWordSizeInBytes platform)) (ImmInt 0)) + code = e_code `appOL` toOL + [ LEA (archWordFormat is32bit) (OpAddr (AddrBaseIndex EABaseRip EAIndexNone (ImmCLbl lbl))) (OpReg tableReg) + , MOV (archWordFormat is32bit) op (OpReg reg) + , JMP_TBL (OpReg reg) ids (Section ReadOnlyData lbl) lbl + ] + return code where (offset, blockIds) = switchTargetsToTable targets ids = map (fmap DestBlockId) blockIds @@ -3078,14 +3138,14 @@ trivialCode :: Width -> (Operand -> Operand -> Instr) -> Maybe (Operand -> Operand -> Instr) -> CmmExpr -> CmmExpr -> NatM Register trivialCode width instr m a b - = do is32Bit <- is32BitPlatform - trivialCode' is32Bit width instr m a b + = do platform <- getPlatform + trivialCode' platform width instr m a b -trivialCode' :: Bool -> Width -> (Operand -> Operand -> Instr) +trivialCode' :: Platform -> Width -> (Operand -> Operand -> Instr) -> Maybe (Operand -> Operand -> Instr) -> CmmExpr -> CmmExpr -> NatM Register -trivialCode' is32Bit width _ (Just revinstr) (CmmLit lit_a) b - | is32BitLit is32Bit lit_a = do +trivialCode' platform width _ (Just revinstr) (CmmLit lit_a) b + | is32BitLit platform lit_a = do b_code <- getAnyReg b let code dst diff --git a/compiler/GHC/CmmToAsm/X86/Instr.hs b/compiler/GHC/CmmToAsm/X86/Instr.hs index 1f1515b0c9..42b9543204 100644 --- a/compiler/GHC/CmmToAsm/X86/Instr.hs +++ b/compiler/GHC/CmmToAsm/X86/Instr.hs @@ -196,6 +196,10 @@ data Instr -- Moves. | MOV Format Operand Operand + -- ^ N.B. when used with the 'II64' 'Format', the source + -- operand is interpreted to be a 32-bit sign-extended value. + -- True 64-bit operands need to be moved with @MOVABS@, which we + -- currently don't use. | CMOV Cond Format Operand Reg | MOVZxL Format Operand Operand -- ^ The format argument is the size of operand 1 (the number of bits we keep) diff --git a/compiler/GHC/Driver/Pipeline/Execute.hs b/compiler/GHC/Driver/Pipeline/Execute.hs index 61fc86c836..da214cdc20 100644 --- a/compiler/GHC/Driver/Pipeline/Execute.hs +++ b/compiler/GHC/Driver/Pipeline/Execute.hs @@ -1089,12 +1089,15 @@ enabled in the toolchain: suggests, this tells the linker to produce a bigobj-enabled COFF object, no a PE executable. -We must enable bigobj output in a few places: +Previously when we used ld.bfd we had to enable bigobj output in a few places: * When merging object files (GHC.Driver.Pipeline.Execute.joinObjectFiles) * When assembling (GHC.Driver.Pipeline.runPhase (RealPhase As ...)) +However, this is no longer necessary with ld.lld, which detects that the +object is large on its own. + Unfortunately the big object format is not supported on 32-bit targets so none of this can be used in that case. diff --git a/compiler/GHC/SysTools/Info.hs b/compiler/GHC/SysTools/Info.hs index 580e76ab8e..a953b9da21 100644 --- a/compiler/GHC/SysTools/Info.hs +++ b/compiler/GHC/SysTools/Info.hs @@ -68,30 +68,6 @@ The flag is only needed on ELF systems. On Windows (PE) and Mac OS X -} -{- Note [Windows static libGCC] - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The GCC versions being upgraded to in #10726 are configured with -dynamic linking of libgcc supported. This results in libgcc being -linked dynamically when a shared library is created. - -This introduces thus an extra dependency on GCC dll that was not -needed before by shared libraries created with GHC. This is a particular -issue on Windows because you get a non-obvious error due to this missing -dependency. This dependent dll is also not commonly on your path. - -For this reason using the static libgcc is preferred as it preserves -the same behaviour that existed before. There are however some very good -reasons to have the shared version as well as described on page 181 of -https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc.pdf : - -"There are several situations in which an application should use the - shared ‘libgcc’ instead of the static version. The most common of these - is when the application wishes to throw and catch exceptions across different - shared libraries. In that case, each of the libraries as well as the application - itself should use the shared ‘libgcc’. " - --} - neededLinkArgs :: LinkerInfo -> [Option] neededLinkArgs (GnuLD o) = o neededLinkArgs (GnuGold o) = o @@ -166,12 +142,10 @@ getLinkerInfo' logger dflags = do -- Process creation is also fairly expensive on win32, so -- we short-circuit here. return $ GnuLD $ map Option - [ -- Emit gcc stack checks + [ -- Emit stack checks -- See Note [Windows stack allocations] "-fstack-check" - -- Force static linking of libGCC - -- See Note [Windows static libGCC] - , "-static-libgcc" ] + ] _ -> do -- In practice, we use the compiler as the linker here. Pass -- -Wl,--version to get linker version info. diff --git a/compiler/GHC/SysTools/Tasks.hs b/compiler/GHC/SysTools/Tasks.hs index ded526513a..d6532a6234 100644 --- a/compiler/GHC/SysTools/Tasks.hs +++ b/compiler/GHC/SysTools/Tasks.hs @@ -374,25 +374,11 @@ runRanlib logger dflags args = traceToolCommand logger "ranlib" $ do runWindres :: Logger -> DynFlags -> [Option] -> IO () runWindres logger dflags args = traceToolCommand logger "windres" $ do - let cc = pgm_c dflags - cc_args = map Option (sOpt_c (settings dflags)) + let cc_args = map Option (sOpt_c (settings dflags)) windres = pgm_windres dflags opts = map Option (getOpts dflags opt_windres) - quote x = "\"" ++ x ++ "\"" - args' = -- If windres.exe and gcc.exe are in a directory containing - -- spaces then windres fails to run gcc. We therefore need - -- to tell it what command to use... - [ Option ("--preprocessor=" ++ quote cc) ] - ++ map (Option . ("--preprocessor-arg=" ++) . quote) - (map showOpt opts ++ ["-E", "-xc", "-DRC_INVOKED"]) - -- ...but if we do that then if windres calls popen then - -- it can't understand the quoting, so we have to use - -- --use-temp-file so that it interprets it correctly. - -- See #1828. - ++ [ Option "--use-temp-file" ] - ++ args mb_env <- getGccEnv cc_args - runSomethingFiltered logger id "Windres" windres args' Nothing mb_env + runSomethingFiltered logger id "Windres" windres (opts ++ args) Nothing mb_env touch :: Logger -> DynFlags -> String -> String -> IO () touch logger dflags purpose arg = traceToolCommand logger "touch" $ diff --git a/configure.ac b/configure.ac index 95d0043f59..7f2fb42bc6 100644 --- a/configure.ac +++ b/configure.ac @@ -354,111 +354,10 @@ AC_SUBST(TargetHasRTSLinker) # Requires FPTOOLS_SET_PLATFORMS_VARS to be run first. FP_FIND_ROOT - -if test "$HostOS" = "mingw32" -then - # Find the mingw-w64 7z file to extract. - # NB. If you update the tarballs to a new version of gcc, don't - # forget to tweak the paths in driver/gcc/gcc.c. - if test "$HostArch" = "i386" - then - mingw_arch="i686" - tarball_dest_dir="mingw-w64/i686" - tarball_mingw_dir="mingw32" - else - mingw_arch="x86_64" - tarball_dest_dir="mingw-w64/x86_64" - tarball_mingw_dir="mingw64" - fi -fi - -set_up_tarballs() { - AC_MSG_NOTICE([Checking for Windows toolchain tarballs...]) - local action - if test "$TarballsAutodownload" = "NO" - then - action="verify" - else - action="download" - fi - $PYTHON mk/get-win32-tarballs.py $action $mingw_arch > missing-win32-tarballs - case $? in - 0) - rm missing-win32-tarballs - ;; - 2) - echo - echo "Error:" - echo "Needed msys2 tarballs are missing. You have a few options to get them," - echo - echo " * run configure with the --enable-tarballs-autodownload option" - echo - echo " * run mk/get-win32-tarballs.py download $mingw_arch" - echo - echo " * manually download the files listed in ./missing-win32-tarballs and place" - echo " them in the ghc-tarballs directory." - echo - exit 1 - ;; - *) - echo - echo "Error fetching msys2 tarballs; see errors above." - exit 1 - ;; - esac - - # Extract all the tarballs in one go - if ! test -d inplace/mingw - then - AC_MSG_NOTICE([Extracting Windows toolchain from archives (may take a while)...]) - rm -rf inplace/mingw - local base_dir="../ghc-tarballs/${tarball_dest_dir}" - ( cd inplace && - find "${base_dir}" -name "*.tar.xz" -exec tar --xz -xf {} \; && - find "${base_dir}" -name "*.tar.zst" -exec tar --zstd -xf {} \; && - rm ".MTREE" && - rm ".PKGINFO" && - cd .. ) || AC_MSG_ERROR([Could not extract Windows toolchains.]) - - mv "inplace/${tarball_mingw_dir}" inplace/mingw && - touch inplace/mingw - - # NB. Now since the GCC is hardcoded to use /mingw32 we need to - # make a wrapper around it to give it the proper paths - mv inplace/mingw/bin/gcc.exe inplace/mingw/bin/realgcc.exe - PATH=`pwd`/inplace/mingw/bin:$PATH - inplace/mingw/bin/realgcc.exe driver/gcc/gcc.c driver/utils/cwrapper.c driver/utils/getLocation.c -Idriver/utils -o inplace/mingw/bin/gcc.exe - - AC_MSG_NOTICE([In-tree MingW-w64 tree created]) - fi -} - -# See Note [tooldir: How GHC finds mingw on Windows] -if test "$HostOS" = "mingw32" -a "$EnableDistroToolchain" = "NO" -then - test -d inplace || mkdir inplace - - # NB. Download and extract the MingW-w64 distribution if required - set_up_tarballs - - mingwbin="$hardtop/inplace/mingw/bin/" - CC="${mingwbin}gcc.exe" - LD="${mingwbin}ld.exe" - NM="${mingwbin}nm.exe" - RANLIB="${mingwbin}ranlib.exe" - OBJDUMP="${mingwbin}objdump.exe" - MergeObjsCmd="$LD" - MergeObjsArgs="-r --oformat=pe-bigobj-x86-64" - fp_prog_ar="${mingwbin}ar.exe" - - AC_PATH_PROG([Genlib],[genlib]) -fi - -# We don't want to bundle a MinGW-w64 toolchain -# So we have to find these individual tools. -# See Note [tooldir: How GHC finds mingw on Windows] -if test "$EnableDistroToolchain" = "YES" -then +# Extract and configure the Windows toolchain +if test "$HostOS" = "mingw32" -a "$EnableDistroToolchain" = "NO"; then + FP_SETUP_WINDOWS_TOOLCHAIN +else # Ideally should use AC_CHECK_TARGET_TOOL but our triples # are screwed up. Configure doesn't think they're ever equal and # so never tried without the prefix. @@ -471,28 +370,28 @@ then AC_PATH_PROG([DllWrap],[dllwrap]) AC_PATH_PROG([Windres],[windres]) AC_PATH_PROG([Genlib],[genlib]) -else - AC_CHECK_TARGET_TOOL([Windres],[windres]) - AC_CHECK_TARGET_TOOL([DllWrap],[dllwrap]) - AC_CHECK_TARGET_TOOL([OBJDUMP],[objdump]) -fi -DllWrapCmd="$DllWrap" -WindresCmd="$Windres" + HAVE_GENLIB=False + if test "$HostOS" = "mingw32"; then + AC_CHECK_TARGET_TOOL([Windres],[windres]) + AC_CHECK_TARGET_TOOL([DllWrap],[dllwrap]) + AC_CHECK_TARGET_TOOL([OBJDUMP],[objdump]) -HAVE_GENLIB=False -if test "$HostOS" = "mingw32" -then - if test "$Genlib" != ""; then - GenlibCmd="$(cygpath -m $Genlib)" - HAVE_GENLIB=True + if test "$Genlib" != ""; then + GenlibCmd="$(cygpath -m $Genlib)" + HAVE_GENLIB=True + fi fi fi -AC_SUBST([DllWrapCmd]) -AC_SUBST([WindresCmd]) -AC_SUBST([GenlibCmd]) -AC_SUBST([HAVE_GENLIB]) +if test "$HostOS" = "mingw32"; then + DllWrapCmd="$DllWrap" + WindresCmd="$Windres" + AC_SUBST([DllWrapCmd]) + AC_SUBST([WindresCmd]) + AC_SUBST([GenlibCmd]) + AC_SUBST([HAVE_GENLIB]) +fi FP_ICONV FP_GMP diff --git a/driver/gcc/gcc.c b/driver/gcc/gcc.c deleted file mode 100644 index aa63bb0498..0000000000 --- a/driver/gcc/gcc.c +++ /dev/null @@ -1,66 +0,0 @@ - -/* gcc on mingw is hardcoded to use /mingw (which is c:/mingw) to - find various files. If this is a different version of mingw to the - one that we have in the GHC tree then things can go wrong. We - therefore need to add various -B flags to the gcc commandline, - so that it uses our in-tree mingw. Hence this wrapper. */ - -#include "cwrapper.h" -#include "getLocation.h" - -#include <stdio.h> -#include <stdlib.h> - -int main(int argc, char** argv) { - char *binDir; - char *exePath; - char *preArgv[4]; - char *oldPath; - char *newPath; - char *base; - char *version; - int n; - - binDir = getExecutablePath(); - exePath = mkString("%s/realgcc.exe", binDir); - - /* We need programs like - inplace/mingw/libexec/gcc/mingw32/4.5.0/cc1.exe - to be able to find the DLLs in inplace/mingw/bin, so we need to - add it to $PATH */ - oldPath = getenv("PATH"); - if (!oldPath) { - die("Couldn't read PATH\n"); - } - n = snprintf(NULL, 0, "PATH=%s;%s", binDir, oldPath); - n++; - newPath = malloc(n); - if (!newPath) { - die("Couldn't allocate space for PATH\n"); - } - snprintf(newPath, n, "PATH=%s;%s", binDir, oldPath); - n = putenv(newPath); - if (n) { - die("putenv failed\n"); - } - - /* GCC Version. */ - version = mkString("%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); - - /* Without these -B args, gcc will still work. However, if you - have a mingw installation in c:/mingw then it will use files - from that in preference to the in-tree files. */ - preArgv[0] = mkString("-B%s", binDir); - preArgv[1] = mkString("-B%s/../lib", binDir); -#if defined(__MINGW64__) - base = mkString("x86_64-w64-mingw32"); -#else - base = mkString("i686-w64-mingw32"); -#endif - - preArgv[2] = mkString("-B%s/../lib/gcc/%s/%s" , binDir, base, version); - preArgv[3] = mkString("-B%s/../libexec/gcc/%s/%s", binDir, base, version); - - run(exePath, 4, preArgv, argc - 1, argv + 1, NULL); -} - diff --git a/hadrian/src/Oracles/Flag.hs b/hadrian/src/Oracles/Flag.hs index 40ae3e8f9b..7c05be5a68 100644 --- a/hadrian/src/Oracles/Flag.hs +++ b/hadrian/src/Oracles/Flag.hs @@ -1,8 +1,11 @@ {-# LANGUAGE MultiWayIf #-} module Oracles.Flag ( - Flag (..), flag, getFlag, platformSupportsSharedLibs, - targetSupportsSMP, useLibffiForAdjustors + Flag (..), flag, getFlag, + platformSupportsSharedLibs, + platformSupportsGhciObjects, + targetSupportsSMP, + useLibffiForAdjustors ) where import Hadrian.Oracles.TextFile @@ -60,6 +63,12 @@ flag f = do getFlag :: Flag -> Expr c b Bool getFlag = expr . flag +-- | Does the platform support object merging (and therefore we can build GHCi objects +-- when appropriate). +platformSupportsGhciObjects :: Action Bool +platformSupportsGhciObjects = + not . null <$> settingsFileSetting SettingsFileSetting_MergeObjectsCommand + platformSupportsSharedLibs :: Action Bool platformSupportsSharedLibs = do windows <- isWinTarget diff --git a/hadrian/src/Rules/BinaryDist.hs b/hadrian/src/Rules/BinaryDist.hs index b47eff4eec..3b5dbca5a6 100644 --- a/hadrian/src/Rules/BinaryDist.hs +++ b/hadrian/src/Rules/BinaryDist.hs @@ -466,12 +466,12 @@ iservBins = do -- | Create a wrapper script calls the executable given as first argument createVersionWrapper :: String -> FilePath -> Action () createVersionWrapper versioned_exe install_path = do - ccPath <- builderPath (Cc CompileC Stage2) + ghcPath <- builderPath (Ghc CompileCWithGhc Stage2) top <- topDirectory let version_wrapper_dir = top -/- "hadrian" -/- "bindist" -/- "cwrappers" wrapper_files = [ version_wrapper_dir -/- file | file <- ["version-wrapper.c", "getLocation.c", "cwrapper.c"]] - cmd ccPath (["-o", install_path, "-I", version_wrapper_dir + cmd ghcPath (["-no-hs-main", "-o", install_path, "-I"++version_wrapper_dir , "-DEXE_PATH=\"" ++ versioned_exe ++ "\"" ] ++ wrapper_files) diff --git a/hadrian/src/Rules/Register.hs b/hadrian/src/Rules/Register.hs index cefdf04cb7..c510e96c02 100644 --- a/hadrian/src/Rules/Register.hs +++ b/hadrian/src/Rules/Register.hs @@ -9,6 +9,7 @@ import Expression ( getContextData ) import Hadrian.BuildPath import Hadrian.Expression import Hadrian.Haskell.Cabal +import Oracles.Flag (platformSupportsGhciObjects) import Packages import Rules.Rts import {-# SOURCE #-} Rules.Library (needLibrary) @@ -206,12 +207,14 @@ extraTargets context -- | Given a library 'Package' this action computes all of its targets. Needing -- all the targets should build the library such that it is ready to be -- registered into the package database. --- See 'packageTargets' for the explanation of the @includeGhciLib@ parameter. +-- See 'Rules.packageTargets' for the explanation of the @includeGhciLib@ +-- parameter. libraryTargets :: Bool -> Context -> Action [FilePath] libraryTargets includeGhciLib context@Context {..} = do libFile <- pkgLibraryFile context ghciLib <- pkgGhciLibraryFile context - ghci <- if includeGhciLib && not (wayUnit Dynamic way) + ghciObjsSupported <- platformSupportsGhciObjects + ghci <- if ghciObjsSupported && includeGhciLib && not (wayUnit Dynamic way) then interpretInContext context $ getContextData buildGhciLib else return False extra <- extraTargets context diff --git a/hadrian/src/Settings/Builders/Cabal.hs b/hadrian/src/Settings/Builders/Cabal.hs index 1ef20147ae..c6a83ce12b 100644 --- a/hadrian/src/Settings/Builders/Cabal.hs +++ b/hadrian/src/Settings/Builders/Cabal.hs @@ -139,6 +139,7 @@ libraryArgs = do package <- getPackage withGhci <- expr ghcWithInterpreter dynPrograms <- expr (flavour >>= dynamicGhcPrograms) + ghciObjsSupported <- expr platformSupportsGhciObjects let ways = flavourWays ++ [contextWay] hasVanilla = vanilla `elem` ways hasProfiling = any (wayUnit Profiling) ways @@ -149,7 +150,8 @@ libraryArgs = do , if hasProfiling then "--enable-library-profiling" else "--disable-library-profiling" - , if (hasVanilla || hasProfiling) && + , if ghciObjsSupported && + (hasVanilla || hasProfiling) && package /= rts && withGhci && not dynPrograms then "--enable-library-for-ghci" else "--disable-library-for-ghci" diff --git a/libraries/Cabal b/libraries/Cabal -Subproject d638e33dbc056048b393964286c7fe394b2730d +Subproject 9eda67ca9a069dce44c627ca5a297b95f4155a6 diff --git a/libraries/base/aclocal.m4 b/libraries/base/aclocal.m4 index 3a028dda16..0336a092a8 100644 --- a/libraries/base/aclocal.m4 +++ b/libraries/base/aclocal.m4 @@ -253,3 +253,19 @@ AS_IF([test "$ac_res" != no], [$6])dnl AS_VAR_POPDEF([ac_Search])dnl ]) + +AC_DEFUN([FP_CHECK_ENVIRON], +[ + dnl-------------------------------------------------------------------- + dnl * Check whether the libc headers provide a declaration for the + dnl environ symbol. If not then we will provide one in RtsSymbols.c. + dnl See #20512, #20577, #20861. + dnl + dnl N.B. Windows declares environ in <stdlib.h>; most others declare it + dnl in <unistd.h>. + dnl-------------------------------------------------------------------- + AC_CHECK_DECLS([environ], [], [], [ + #include <stdlib.h> + #include <unistd.h> + ]) +]) diff --git a/libraries/base/configure.ac b/libraries/base/configure.ac index e034549476..6fc96d92f4 100644 --- a/libraries/base/configure.ac +++ b/libraries/base/configure.ac @@ -189,6 +189,8 @@ FP_CHECK_CONSTS([SIGINT], [ dnl ** can we open files in binary mode? FP_CHECK_CONST([O_BINARY], [#include <fcntl.h>], [0]) +FP_CHECK_ENVIRON + # We don't use iconv or libcharset on Windows, but if configure finds # them then it can cause problems. So we don't even try looking if # we are on Windows. diff --git a/libraries/base/include/HsBase.h b/libraries/base/include/HsBase.h index d5884473ca..243d9698ee 100644 --- a/libraries/base/include/HsBase.h +++ b/libraries/base/include/HsBase.h @@ -552,9 +552,9 @@ INLINE int __hscore_open(char *file, int how, mode_t mode) { #include <crt_externs.h> INLINE char **__hscore_environ(void) { return *(_NSGetEnviron()); } #else -/* ToDo: write a feature test that doesn't assume 'environ' to - * be in scope at link-time. */ +#if !HAVE_DECL_ENVIRON extern char** environ; +#endif INLINE char **__hscore_environ(void) { return environ; } #endif diff --git a/libraries/bytestring b/libraries/bytestring -Subproject e84481a06ae4b50984469a79f2c1af4b2f02029 +Subproject a44600feac0d6461964f10f505f8318a4b6aa71 diff --git a/libraries/ghc-prim/ghc-prim.cabal b/libraries/ghc-prim/ghc-prim.cabal index dbe5d18667..4be29843ae 100644 --- a/libraries/ghc-prim/ghc-prim.cabal +++ b/libraries/ghc-prim/ghc-prim.cabal @@ -68,7 +68,7 @@ Library -- mingw32 which is required by mingwex. -- user32: provides access to apis to modify user components (UI etc) -- on Windows. Required because of mingw32. - extra-libraries: user32, mingw32, mingwex + extra-libraries: user32, mingw32, mingwex, ucrt if os(linux) -- we need libm, but for musl and other's we might need libc, as libm diff --git a/libraries/process b/libraries/process -Subproject 7fd28338c82c89deb3e5db117e87633898046d7 +Subproject 1785cf0314854e4023cd35d05c4e01a9b40a77e diff --git a/libraries/text b/libraries/text -Subproject 7b13f15ded23953d5b52b9e74bfe7e2cbc8bb69 +Subproject 5a43fecb62e9769c4cf8b456c7b273901048ea7 diff --git a/m4/fp_check_environ.m4 b/m4/fp_check_environ.m4 index 88bf0a52de..f0daedc9c0 100644 --- a/m4/fp_check_environ.m4 +++ b/m4/fp_check_environ.m4 @@ -4,11 +4,14 @@ AC_DEFUN([FP_CHECK_ENVIRON], [ dnl-------------------------------------------------------------------- dnl * Check whether the libc headers provide a declaration for the - dnl environ symbol. If not then we will provide one in RtsSymbols.c. + dnl environ symbol. If not then we will provide one in RtsSymbols.c. dnl See #20512, #20577, #20861. + dnl + dnl N.B. Windows declares environ in <stdlib.h>; most others declare it + dnl in <unistd.h>. dnl-------------------------------------------------------------------- AC_CHECK_DECLS([environ], [], [], [ + #include <stdlib.h> #include <unistd.h> ]) ]) - diff --git a/m4/fp_settings.m4 b/m4/fp_settings.m4 index 09a24f33e1..4db7cd46af 100644 --- a/m4/fp_settings.m4 +++ b/m4/fp_settings.m4 @@ -1,104 +1,113 @@ # FP_SETTINGS # ---------------------------------- # Set the variables used in the settings file -# See Note [tooldir: How GHC finds mingw on Windows] AC_DEFUN([FP_SETTINGS], [ - if test "$windows" = YES -a "$EnableDistroToolchain" = "NO" - then + SettingsUseDistroMINGW="$EnableDistroToolchain" + + if test "$windows" = YES -a "$EnableDistroToolchain" = "NO"; then + # Handle the Windows toolchain installed in FP_SETUP_WINDOWS_TOOLCHAIN. + # See Note [tooldir: How GHC finds mingw on Windows] mingw_bin_prefix='$$tooldir/mingw/bin/' - SettingsCCompilerCommand="${mingw_bin_prefix}gcc.exe" - SettingsHaskellCPPCommand="${mingw_bin_prefix}gcc.exe" - SettingsHaskellCPPFlags="$HaskellCPPArgs" - SettingsLdCommand="${mingw_bin_prefix}ld.exe" - # Overrides FIND_MERGE_OBJECTS in order to avoid hard-coding linker - # path on Windows (#18550). - SettingsMergeObjectsCommand="${SettingsLdCommand}" - SettingsMergeObjectsFlags="-r --oformat=pe-bigobj-x86-64" - SettingsArCommand="${mingw_bin_prefix}ar.exe" - SettingsRanlibCommand="${mingw_bin_prefix}ranlib.exe" - SettingsDllWrapCommand="${mingw_bin_prefix}dllwrap.exe" - SettingsWindresCommand="${mingw_bin_prefix}windres.exe" - SettingsTouchCommand='$$topdir/bin/touchy.exe' - elif test "$EnableDistroToolchain" = "YES" - then - SettingsCCompilerCommand="$(basename $CC)" + SettingsCCompilerCommand="${mingw_bin_prefix}clang.exe" SettingsCCompilerFlags="$CONF_CC_OPTS_STAGE2" SettingsCxxCompilerFlags="$CONF_CXX_OPTS_STAGE2" - SettingsHaskellCPPCommand="$(basename $HaskellCPPCmd)" + SettingsCCompilerLinkFlags="$CONF_GCC_LINKER_OPTS_STAGE2" + SettingsHaskellCPPCommand="${mingw_bin_prefix}clang.exe" SettingsHaskellCPPFlags="$HaskellCPPArgs" - SettingsLdCommand="$(basename $LdCmd)" - SettingsMergeObjectsCommand="$(basename $MergeObjsCmd)" - SettingsMergeObjectsFlags="$MergeObjsArgs" - SettingsArCommand="$(basename $ArCmd)" - SettingsDllWrapCommand="$(basename $DllWrapCmd)" - SettingsWindresCommand="$(basename $WindresCmd)" + SettingsLdCommand="${mingw_bin_prefix}ld.lld.exe" + SettingsLdFlags="" + # LLD does not support object merging (#21068) + SettingsMergeObjectsCommand="" + SettingsMergeObjectsFlags="" + SettingsArCommand="${mingw_bin_prefix}llvm-ar.exe" + SettingsRanlibCommand="${mingw_bin_prefix}llvm-ranlib.exe" + SettingsDllWrapCommand="${mingw_bin_prefix}llvm-dllwrap.exe" + SettingsWindresCommand="${mingw_bin_prefix}llvm-windres.exe" SettingsTouchCommand='$$topdir/bin/touchy.exe' + else + # This case handles the "normal" platforms (e.g. not Windows) where we + # don't provide the toolchain. + SettingsCCompilerCommand="$CC" + SettingsCCompilerFlags="$CONF_CC_OPTS_STAGE2" + SettingsCxxCompilerFlags="$CONF_CXX_OPTS_STAGE2" SettingsHaskellCPPCommand="$HaskellCPPCmd" SettingsHaskellCPPFlags="$HaskellCPPArgs" + SettingsCCompilerLinkFlags="$CONF_GCC_LINKER_OPTS_STAGE2" SettingsLdCommand="$LdCmd" - SettingsMergeObjectsCommand="$MergeObjsCmd" - SettingsMergeObjectsFlags="$MergeObjsArgs" + SettingsLdFlags="$CONF_LD_LINKER_OPTS_STAGE2" SettingsArCommand="$ArCmd" SettingsRanlibCommand="$RanlibCmd" - if test -z "$DllWrapCmd" - then + SettingsMergeObjectsCommand="$MergeObjsCmd" + SettingsMergeObjectsFlags="$MergeObjsArgs" + + if test -z "$DllWrapCmd"; then SettingsDllWrapCommand="/bin/false" else SettingsDllWrapCommand="$DllWrapCmd" fi - if test -z "$WindresCmd" - then + if test -z "$WindresCmd"; then SettingsWindresCommand="/bin/false" else SettingsWindresCommand="$WindresCmd" fi - SettingsTouchCommand='touch' + + if test "$HostOS" = "mingw32"; then + SettingsTouchCommand='$$topdir/bin/touchy.exe' + else + SettingsTouchCommand='touch' + fi + + if test "$EnableDistroToolchain" = "YES"; then + # If the user specified --enable-distro-toolchain then we just use the + # executable names, not paths. + SettingsCCompilerCommand="$(basename $SettingsCCompilerCommand)" + SettingsHaskellCPPCommand="$(basename $SettingsHaskellCPPCommand)" + SettingsLdCommand="$(basename $SettingsLdCommand)" + SettingsMergeObjectsCommand="$(basename $SettingsMergeObjectsCommand)" + SettingsArCommand="$(basename $SettingsArCommand)" + SettingsDllWrapCommand="$(basename $SettingsDllWrapCommand)" + SettingsWindresCommand="$(basename $SettingsWindresCommand)" + fi fi - if test -z "$LibtoolCmd" - then - SettingsLibtoolCommand="libtool" - else - SettingsLibtoolCommand="$LibtoolCmd" + + # Platform-agnostic tools + if test -z "$LibtoolCmd"; then + LibtoolCmd="libtool" fi - if test -z "$ClangCmd" - then - SettingsClangCommand="clang" - else - SettingsClangCommand="$ClangCmd" + SettingsLibtoolCommand="$LibtoolCmd" + + if test -z "$ClangCmd"; then + ClangCmd="clang" fi - if test -z "$LlcCmd" - then - SettingsLlcCommand="llc" - else - SettingsLlcCommand="$LlcCmd" + SettingsClangCommand="$ClangCmd" + + # LLVM backend tools + if test -z "$LlcCmd"; then + LlcCmd="llc" fi - if test -z "$OptCmd" - then - SettingsOptCommand="opt" - else - SettingsOptCommand="$OptCmd" + SettingsLlcCommand="$LlcCmd" + + if test -z "$OptCmd"; then + OptCmd="opt" fi - if test -z "$OtoolCmd" - then - SettingsOtoolCommand="otool" - else - SettingsOtoolCommand="$OtoolCmd" + SettingsOptCommand="$OptCmd" + + # Mac-only tools + if test -z "$OtoolCmd"; then + OtoolCmd="otool" fi - if test -z "$InstallNameToolCmd" - then - SettingsInstallNameToolCommand="install_name_tool" - else - SettingsInstallNameToolCommand="$InstallNameToolCmd" + SettingsOtoolCommand="$OtoolCmd" + + if test -z "$InstallNameToolCmd"; then + InstallNameToolCmd="install_name_tool" fi - SettingsCCompilerFlags="$CONF_CC_OPTS_STAGE2" - SettingsCxxCompilerFlags="$CONF_CXX_OPTS_STAGE2" - SettingsCCompilerLinkFlags="$CONF_GCC_LINKER_OPTS_STAGE2" + SettingsInstallNameToolCommand="$InstallNameToolCmd" + SettingsCCompilerSupportsNoPie="$CONF_GCC_SUPPORTS_NO_PIE" - SettingsLdFlags="$CONF_LD_LINKER_OPTS_STAGE2" - SettingsUseDistroMINGW="$EnableDistroToolchain" + AC_SUBST(SettingsCCompilerCommand) AC_SUBST(SettingsHaskellCPPCommand) AC_SUBST(SettingsHaskellCPPFlags) diff --git a/m4/fp_setup_windows_toolchain.m4 b/m4/fp_setup_windows_toolchain.m4 new file mode 100644 index 0000000000..35e322c8a0 --- /dev/null +++ b/m4/fp_setup_windows_toolchain.m4 @@ -0,0 +1,107 @@ +AC_DEFUN([FP_SETUP_WINDOWS_TOOLCHAIN],[ + # Find the mingw-w64 archive file to extract. + if test "$HostArch" = "i386" + then + mingw_arch="i686" + tarball_dest_dir="mingw-w64/i686" + tarball_mingw_dir="clang32" + else + mingw_arch="x86_64" + tarball_dest_dir="mingw-w64/x86_64" + tarball_mingw_dir="clang64" + fi + + set_up_tarballs() { + AC_MSG_NOTICE([Checking for Windows toolchain tarballs...]) + local action + if test "$TarballsAutodownload" = "NO" + then + action="verify" + else + action="download" + fi + $PYTHON mk/get-win32-tarballs.py $action $mingw_arch > missing-win32-tarballs + case $? in + 0) + rm missing-win32-tarballs + ;; + 2) + echo + echo "Error:" + echo "Needed msys2 tarballs are missing. You have a few options to get them," + echo + echo " * run configure with the --enable-tarballs-autodownload option" + echo + echo " * run mk/get-win32-tarballs.py download $mingw_arch" + echo + echo " * manually download the files listed in ./missing-win32-tarballs and place" + echo " them in the ghc-tarballs directory." + echo + exit 1 + ;; + *) + echo + echo "Error fetching msys2 tarballs; see errors above." + exit 1 + ;; + esac + + # Extract all the tarballs in one go + if ! test -d inplace/mingw + then + AC_MSG_NOTICE([Extracting Windows toolchain from archives (may take a while)...]) + rm -rf inplace/mingw + local base_dir="../ghc-tarballs/${tarball_dest_dir}" + ( cd inplace && + find "${base_dir}" -name "*.tar.xz" -exec tar --xz -xf {} \; && + find "${base_dir}" -name "*.tar.zst" -exec tar --zstd -xf {} \; && + rm ".MTREE" && + rm ".PKGINFO" && + cd .. ) || AC_MSG_ERROR([Could not extract Windows toolchains.]) + + mv "inplace/${tarball_mingw_dir}" inplace/mingw && + touch inplace/mingw + AC_MSG_NOTICE([In-tree MingW-w64 tree created]) + fi + } + + # See Note [tooldir: How GHC finds mingw on Windows] + test -d inplace || mkdir inplace + + # NB. Download and extract the MingW-w64 distribution if required + set_up_tarballs + + # N.B. The parameters which get plopped in the `settings` file used by the + # resulting compiler are computed in `FP_SETTINGS`. + + # Our Windows toolchain is based around Clang and LLD. We use compiler-rt + # for the runtime, libc++ and libc++abi for the C++ standard library + # implementation, and libunwind for C++ unwinding. + mingwbin="$hardtop/inplace/mingw/bin/" + + CC="${mingwbin}clang.exe" + cflags="--rtlib=compiler-rt" + CFLAGS="$cflags" + CONF_CC_OPTS_STAGE1="$cflags" + CONF_CC_OPTS_STAGE2="$cflags" + + cxxflags="--rtlib=compiler-rt --unwindlib=libunwind --stdlib=libc++" + CXXFLAGS="$cxxflags" + CONF_CXX_OPTS_STAGE1="$cxxflags" + CONF_CXX_OPTS_STAGE2="$cxxflags" + + CONF_GCC_LINKER_OPTS_STAGE1="-fuse-ld=lld $cflags" + CONF_GCC_LINKER_OPTS_STAGE2="-fuse-ld=lld $cflags" + + LD="${mingwbin}ld.lld.exe" + NM="${mingwbin}llvm-nm.exe" + AR="${mingwbin}llvm-ar.exe" + RANLIB="${mingwbin}llvm-ranlib.exe" + OBJDUMP="${mingwbin}llvm-objdump.exe" + DLLTOOL="${mingwbin}llvm-dlltool.exe" + + # N.B. LLD does not support -r + MergeObjsCmd="" + MergeObjsArgs="" + AC_PATH_PROG([Genlib],[genlib]) +]) diff --git a/mk/config.mk.in b/mk/config.mk.in index 06e1dabd96..e1474a34a3 100644 --- a/mk/config.mk.in +++ b/mk/config.mk.in @@ -655,11 +655,7 @@ SRC_HSC2HS_OPTS_STAGE0 += --cflag=-D$(HostArch_CPP)_HOST_ARCH --cflag=-D$(HostOS SRC_HSC2HS_OPTS_STAGE1 += --cflag=-D$(TargetArch_CPP)_HOST_ARCH --cflag=-D$(TargetOS_CPP)_HOST_OS SRC_HSC2HS_OPTS_STAGE2 += --cflag=-D$(TargetArch_CPP)_HOST_ARCH --cflag=-D$(TargetOS_CPP)_HOST_OS -ifeq "$(TARGETPLATFORM)" "i386-unknown-mingw32" -WINDRES = $(INPLACE_MINGW)/bin/windres -else ifeq "$(TARGETPLATFORM)" "x86_64-unknown-mingw32" -WINDRES = $(INPLACE_MINGW)/bin/windres -endif +WINDRES=@WindresCmd@ #----------------------------------------------------------------------------- # Python for testsuite driver and code generators @@ -670,11 +666,7 @@ PYTHON=@PythonCmd@ # Mingwex Library # HaveLibMingwEx = @HaveLibMingwEx@ -ifeq "$(TARGETPLATFORM)" "i386-unknown-mingw32" -DLLTOOL = inplace/mingw/bin/dlltool.exe -else ifeq "$(TARGETPLATFORM)" "x86_64-unknown-mingw32" -DLLTOOL = inplace/mingw/bin/dlltool.exe -endif +DLLTOOL = @DlltoolCmd@ #----------------------------------------------------------------------------- # Other standard (ha!) Unix utilities diff --git a/mk/get-win32-tarballs.py b/mk/get-win32-tarballs.py index f1ada96b48..351212ba71 100755 --- a/mk/get-win32-tarballs.py +++ b/mk/get-win32-tarballs.py @@ -8,7 +8,7 @@ import argparse import sys from sys import stderr -TARBALL_VERSION = '0.3' +TARBALL_VERSION = '0.7' BASE_URL = "https://downloads.haskell.org/ghc/mingw/{}".format(TARBALL_VERSION) DEST = Path('ghc-tarballs/mingw-w64') ARCHS = ['i686', 'x86_64', 'sources'] diff --git a/rts/CheckUnload.h b/rts/CheckUnload.h index de07aef1c3..5471544433 100644 --- a/rts/CheckUnload.h +++ b/rts/CheckUnload.h @@ -10,10 +10,10 @@ #pragma once -#include "BeginPrivate.h" - #include "LinkerInternals.h" +#include "BeginPrivate.h" + // Currently live objects extern ObjectCode *objects; diff --git a/rts/HsFFI.c b/rts/HsFFI.c index 58651b81e9..0b9f3f0063 100644 --- a/rts/HsFFI.c +++ b/rts/HsFFI.c @@ -7,8 +7,8 @@ * ---------------------------------------------------------------------------*/ #include "rts/PosixSource.h" -#include "HsFFI.h" #include "Rts.h" +#include "HsFFI.h" #include "StablePtr.h" #include "Task.h" diff --git a/rts/LibdwPool.h b/rts/LibdwPool.h index b1c333eebc..563934c7a9 100644 --- a/rts/LibdwPool.h +++ b/rts/LibdwPool.h @@ -8,11 +8,11 @@ #pragma once -#include "BeginPrivate.h" - #include "Rts.h" #include "Libdw.h" +#include "BeginPrivate.h" + #if USE_LIBDW /* Initialize the pool */ diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h index 8a71179932..5711b16526 100644 --- a/rts/LinkerInternals.h +++ b/rts/LinkerInternals.h @@ -18,8 +18,6 @@ void printLoadedObjects(void); -#include "BeginPrivate.h" - /* Which object file format are we targeting? */ #if defined(linux_HOST_OS) || defined(solaris2_HOST_OS) \ || defined(linux_android_HOST_OS) \ @@ -403,6 +401,8 @@ typedef struct _RtsSymbolInfo { SymType type; } RtsSymbolInfo; +#include "BeginPrivate.h" + void exitLinker( void ); void freeObjectCode (ObjectCode *oc); diff --git a/rts/Messages.h b/rts/Messages.h index 8cefcafd97..ecae7e6365 100644 --- a/rts/Messages.h +++ b/rts/Messages.h @@ -8,6 +8,10 @@ #pragma once +#include "Capability.h" +#include "Updates.h" // for DEBUG_FILL_SLOP +#include "SMPClosureOps.h" + #include "BeginPrivate.h" uint32_t messageBlackHole(Capability *cap, MessageBlackHole *msg); @@ -18,10 +22,6 @@ void executeMessage (Capability *cap, Message *m); void sendMessage (Capability *from_cap, Capability *to_cap, Message *msg); #endif -#include "Capability.h" -#include "Updates.h" // for DEBUG_FILL_SLOP -#include "SMPClosureOps.h" - INLINE_HEADER void doneWithMsgThrowTo (Capability *cap, MessageThrowTo *m) { diff --git a/rts/PathUtils.h b/rts/PathUtils.h index d30b515f93..df4ab3fefe 100644 --- a/rts/PathUtils.h +++ b/rts/PathUtils.h @@ -8,8 +8,6 @@ #pragma once -#include "BeginPrivate.h" - // Use wchar_t for pathnames on Windows (#5697) #if defined(mingw32_HOST_OS) #include "fs_rts.h" @@ -37,6 +35,8 @@ #define pathcopy strcpy #endif +#include "BeginPrivate.h" + pathchar* pathdup(pathchar *path); pathchar* pathdir(pathchar *path); pathchar* mkPath(char* path); diff --git a/rts/Profiling.h b/rts/Profiling.h index abb731217a..b3724c3c88 100644 --- a/rts/Profiling.h +++ b/rts/Profiling.h @@ -10,13 +10,13 @@ #include <stdio.h> -#include "BeginPrivate.h" #include "Rts.h" - #if defined(DEBUG) #include "Arena.h" #endif +#include "BeginPrivate.h" + #if defined(PROFILING) #define PROFILING_ONLY(s) s #else diff --git a/rts/RtsFlags.h b/rts/RtsFlags.h index bfcc43af42..6c81081d4d 100644 --- a/rts/RtsFlags.h +++ b/rts/RtsFlags.h @@ -9,9 +9,10 @@ #pragma once -#include "BeginPrivate.h" #include <stdbool.h> +#include "BeginPrivate.h" + /* Routines that operate-on/to-do-with RTS flags: */ #if defined(mingw32_HOST_OS) diff --git a/rts/RtsSymbolInfo.c b/rts/RtsSymbolInfo.c index 1110d582d6..f1f65bd6b6 100644 --- a/rts/RtsSymbolInfo.c +++ b/rts/RtsSymbolInfo.c @@ -7,9 +7,8 @@ * ---------------------------------------------------------------------------*/ #include "ghcplatform.h" -#include "RtsSymbolInfo.h" - #include "Rts.h" +#include "RtsSymbolInfo.h" #include "HsFFI.h" #include "Hash.h" diff --git a/rts/RtsSymbols.c b/rts/RtsSymbols.c index f4b3aa3953..2818df6ff3 100644 --- a/rts/RtsSymbols.c +++ b/rts/RtsSymbols.c @@ -7,9 +7,8 @@ * ---------------------------------------------------------------------------*/ #include "ghcplatform.h" -#include "RtsSymbols.h" - #include "Rts.h" +#include "RtsSymbols.h" #include "TopHandler.h" #include "HsFFI.h" #include "CloneStack.h" @@ -162,12 +161,12 @@ extern char **environ; SymI_HasProto(stg_asyncDoProczh) \ SymI_HasProto(rts_InstallConsoleEvent) \ SymI_HasProto(rts_ConsoleHandlerDone) \ + SymI_NeedsProto(__mingw_module_is_dll) \ RTS_WIN32_ONLY(SymI_NeedsProto(___chkstk_ms)) \ RTS_WIN64_ONLY(SymI_NeedsProto(___chkstk_ms)) \ - RTS_WIN32_ONLY(SymI_HasProto(_imp___environ)) \ - RTS_WIN64_ONLY(SymI_HasProto(__imp__environ)) \ - RTS_WIN32_ONLY(SymI_HasProto(_imp___iob)) \ - RTS_WIN64_ONLY(SymI_HasProto(__iob_func)) \ + RTS_WIN64_ONLY(SymI_HasProto(__stdio_common_vswprintf_s)) \ + RTS_WIN64_ONLY(SymI_HasProto(__stdio_common_vswprintf)) \ + RTS_WIN64_ONLY(SymI_HasProto(_errno)) \ /* see Note [Symbols for MinGW's printf] */ \ SymI_HasProto(_lock_file) \ SymI_HasProto(_unlock_file) \ diff --git a/rts/StaticPtrTable.c b/rts/StaticPtrTable.c index 9754cfad41..282d9b7899 100644 --- a/rts/StaticPtrTable.c +++ b/rts/StaticPtrTable.c @@ -8,8 +8,8 @@ * */ -#include "StaticPtrTable.h" #include "Rts.h" +#include "StaticPtrTable.h" #include "RtsUtils.h" #include "Hash.h" #include "StablePtr.h" diff --git a/rts/Stats.c b/rts/Stats.c index 16875ce5d2..8d020d53d6 100644 --- a/rts/Stats.c +++ b/rts/Stats.c @@ -26,16 +26,6 @@ #include <string.h> // for memset -#if defined(mingw32_HOST_OS) -/* On Win64, if we say "printf" then gcc thinks we are going to use - MS format specifiers like %I64d rather than %llu */ -#define PRINTF gnu_printf -#else -/* However, on OS X, "gnu_printf" isn't recognised */ -#define PRINTF printf -#endif - - #if defined(THREADED_RTS) // Protects all statistics below Mutex stats_mutex; @@ -79,7 +69,7 @@ static Time *GC_coll_cpu = NULL; static Time *GC_coll_elapsed = NULL; static Time *GC_coll_max_pause = NULL; -static int statsPrintf( char *s, ... ) GNUC3_ATTRIBUTE(format (PRINTF, 1, 2)); +static int statsPrintf( char *s, ... ) STG_PRINTF_ATTR(1, 2); static void statsFlush( void ); static void statsClose( void ); diff --git a/rts/include/Stg.h b/rts/include/Stg.h index be0995445b..209db1b0f5 100644 --- a/rts/include/Stg.h +++ b/rts/include/Stg.h @@ -231,6 +231,16 @@ #define STG_NO_OPTIMIZE /* nothing */ #endif +// Mark a function as accepting a printf-like format string. +#if !defined(__GNUC__) && defined(mingw32_HOST_OS) +/* On Win64, if we say "printf" then gcc thinks we are going to use + MS format specifiers like %I64d rather than %llu */ +#define STG_PRINTF_ATTR(fmt_arg, rest) GNUC3_ATTRIBUTE(format(gnu_printf, fmt_arg, rest)) +#else +/* However, on OS X, "gnu_printf" isn't recognised */ +#define STG_PRINTF_ATTR(fmt_arg, rest) GNUC3_ATTRIBUTE(format(printf, fmt_arg, rest)) +#endif + /* ----------------------------------------------------------------------------- Global type definitions -------------------------------------------------------------------------- */ diff --git a/rts/include/rts/Messages.h b/rts/include/rts/Messages.h index f9b3009c20..7d4727486e 100644 --- a/rts/include/rts/Messages.h +++ b/rts/include/rts/Messages.h @@ -18,15 +18,6 @@ #include <stdarg.h> -#if defined(mingw32_HOST_OS) && !defined(__clang__) -/* On Win64, if we say "printf" then gcc thinks we are going to use - MS format specifiers like %I64d rather than %llu */ -#define PRINTF gnu_printf -#else -/* However, on OS X, "gnu_printf" isn't recognised */ -#define PRINTF printf -#endif - /* ----------------------------------------------------------------------------- * Message generation * -------------------------------------------------------------------------- */ @@ -41,7 +32,7 @@ */ void barf(const char *s, ...) GNUC3_ATTRIBUTE(__noreturn__) - GNUC3_ATTRIBUTE(format(PRINTF, 1, 2)); + STG_PRINTF_ATTR(1, 2); void vbarf(const char *s, va_list ap) GNUC3_ATTRIBUTE(__noreturn__); @@ -57,7 +48,7 @@ void vbarf(const char *s, va_list ap) * errorBelch() invokes (*errorMsgFn)(). */ void errorBelch(const char *s, ...) - GNUC3_ATTRIBUTE(format (PRINTF, 1, 2)); + STG_PRINTF_ATTR(1, 2); void verrorBelch(const char *s, va_list ap); @@ -71,7 +62,7 @@ void verrorBelch(const char *s, va_list ap); * sysErrorBelch() invokes (*sysErrorMsgFn)(). */ void sysErrorBelch(const char *s, ...) - GNUC3_ATTRIBUTE(format (PRINTF, 1, 2)); + STG_PRINTF_ATTR(1, 2); void vsysErrorBelch(const char *s, va_list ap); @@ -83,7 +74,7 @@ void vsysErrorBelch(const char *s, va_list ap); * debugBelch() invokes (*debugMsgFn)(). */ void debugBelch(const char *s, ...) - GNUC3_ATTRIBUTE(format (PRINTF, 1, 2)); + STG_PRINTF_ATTR(1, 2); int vdebugBelch(const char *s, va_list ap); @@ -103,5 +94,3 @@ extern RtsMsgFunction rtsFatalInternalErrorFn; extern RtsMsgFunctionRetLen rtsDebugMsgFn; extern RtsMsgFunction rtsErrorMsgFn; extern RtsMsgFunction rtsSysErrorMsgFn; - -#undef PRINTF diff --git a/rts/include/rts/PosixSource.h b/rts/include/rts/PosixSource.h index 13fd7b0ff5..be6c8ecca1 100644 --- a/rts/include/rts/PosixSource.h +++ b/rts/include/rts/PosixSource.h @@ -36,3 +36,15 @@ #define _POSIX_C_SOURCE 200809L #define _XOPEN_SOURCE 700 #endif + +#if defined(mingw32_HOST_OS) +# if defined(__USE_MINGW_ANSI_STDIO) +# if __USE_MINGW_ANSI_STDIO != 1 +# warning "Mismatch between __USE_MINGW_ANSI_STDIO definitions. \ +If using PosixSource.h make sure it is the first header included." +# endif +# else +/* Inform mingw we want the ISO rather than Windows printf format specifiers. */ +# define __USE_MINGW_ANSI_STDIO 1 +#endif +#endif diff --git a/rts/include/stg/Types.h b/rts/include/stg/Types.h index 05dec27f0c..1a9b1685fa 100644 --- a/rts/include/stg/Types.h +++ b/rts/include/stg/Types.h @@ -20,18 +20,6 @@ #pragma once -#if defined(mingw32_HOST_OS) -# if defined(__USE_MINGW_ANSI_STDIO) -# if __USE_MINGW_ANSI_STDIO != 1 -# warning "Mismatch between __USE_MINGW_ANSI_STDIO definitions. \ -If using Rts.h make sure it is the first header included." -# endif -# else -/* Inform mingw we want the ISO rather than Windows printf format specifiers. */ -# define __USE_MINGW_ANSI_STDIO 1 -#endif -#endif - /* ISO C 99 says: * "C++ implementations should define these macros only when * __STDC_LIMIT_MACROS is defined before <stdint.h> is included." diff --git a/rts/linker/Elf.h b/rts/linker/Elf.h index a16255abba..12bf1772f7 100644 --- a/rts/linker/Elf.h +++ b/rts/linker/Elf.h @@ -2,11 +2,10 @@ #include "Rts.h" #include "LinkerInternals.h" +#include "linker/ElfTypes.h" #include "BeginPrivate.h" -#include <linker/ElfTypes.h> - void ocInit_ELF ( ObjectCode* oc ); void ocDeinit_ELF ( ObjectCode* oc ); int ocVerifyImage_ELF ( ObjectCode* oc ); diff --git a/rts/linker/MachO.h b/rts/linker/MachO.h index 518c2ce569..f55f68ddc8 100644 --- a/rts/linker/MachO.h +++ b/rts/linker/MachO.h @@ -1,11 +1,10 @@ #pragma once #include "Rts.h" +#include "MachOTypes.h" #include "BeginPrivate.h" -#include "MachOTypes.h" - void ocInit_MachO ( ObjectCode* oc ); void ocDeinit_MachO ( ObjectCode* oc ); int ocVerifyImage_MachO ( ObjectCode* oc ); diff --git a/rts/linker/PEi386.c b/rts/linker/PEi386.c index 3a9caf1b80..420a50feae 100644 --- a/rts/linker/PEi386.c +++ b/rts/linker/PEi386.c @@ -495,7 +495,7 @@ void freePreloadObjectFile_PEi386(ObjectCode *oc) See Note [Exception Unwinding]. */ if (oc->info->xdata) { if (!RtlDeleteFunctionTable (oc->info->xdata->start)) - debugBelch ("Unable to remove Exception handlers for %" PATH_FMT, + debugBelch ("Unable to remove Exception handlers for %" PATH_FMT "\n", oc->fileName); oc->info->xdata = NULL; oc->info->pdata = NULL; @@ -591,7 +591,7 @@ COFF_OBJ_TYPE getObjectType ( char* image, pathchar* fileName ) *************/ COFF_HEADER_INFO* getHeaderInfo ( ObjectCode* oc ) { - COFF_OBJ_TYPE coff_type = getObjectType (oc->image, oc->fileName); + COFF_OBJ_TYPE coff_type = getObjectType (oc->image, OC_INFORMATIVE_FILENAME(oc)); COFF_HEADER_INFO* info = stgMallocBytes (sizeof(COFF_HEADER_INFO), "getHeaderInfo"); @@ -2199,6 +2199,17 @@ SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl, ObjectCode *dependent, SymType * Debugging operations. */ +typedef struct _SymX { SymbolName* name; uintptr_t loc; } SymX; + +static int comp (const void * elem1, const void * elem2) +{ + SymX f = *((SymX*)elem1); + SymX s = *((SymX*)elem2); + if (f.loc > s.loc) return 1; + if (f.loc < s.loc) return -1; + return 0; +} + pathchar* resolveSymbolAddr_PEi386 (pathchar* buffer, int size, SymbolAddr* symbol, uintptr_t* top ){ @@ -2324,7 +2335,6 @@ resolveSymbolAddr_PEi386 (pathchar* buffer, int size, else if (obj) { /* Try to calculate from information inside the rts. */ - typedef struct _SymX { SymbolName* name; uintptr_t loc; } SymX; SymX* locs = stgCallocBytes (sizeof(SymX), obj->n_symbols, "resolveSymbolAddr"); int blanks = 0; @@ -2344,14 +2354,6 @@ resolveSymbolAddr_PEi386 (pathchar* buffer, int size, locs[i] = sx; } } - int comp (const void * elem1, const void * elem2) - { - SymX f = *((SymX*)elem1); - SymX s = *((SymX*)elem2); - if (f.loc > s.loc) return 1; - if (f.loc < s.loc) return -1; - return 0; - } qsort (locs, obj->n_symbols, sizeof (SymX), comp); uintptr_t key = (uintptr_t)symbol; SymX* res = NULL; diff --git a/rts/sm/GC.h b/rts/sm/GC.h index da90c61302..25de588534 100644 --- a/rts/sm/GC.h +++ b/rts/sm/GC.h @@ -13,10 +13,10 @@ #pragma once -#include "BeginPrivate.h" - #include "HeapAlloc.h" +#include "BeginPrivate.h" + void GarbageCollect (uint32_t collect_gen, bool do_heap_census, bool is_overflow_gc, diff --git a/rts/sm/GCUtils.h b/rts/sm/GCUtils.h index 798a795deb..dec81e1755 100644 --- a/rts/sm/GCUtils.h +++ b/rts/sm/GCUtils.h @@ -13,10 +13,10 @@ #pragma once -#include "BeginPrivate.h" - #include "GCTDecl.h" +#include "BeginPrivate.h" + bdescr* allocGroup_sync(uint32_t n); bdescr* allocGroupOnNode_sync(uint32_t node, uint32_t n); diff --git a/rts/sm/MarkStack.h b/rts/sm/MarkStack.h index ca519f871f..8ea47a1865 100644 --- a/rts/sm/MarkStack.h +++ b/rts/sm/MarkStack.h @@ -13,9 +13,10 @@ #pragma once -#include "BeginPrivate.h" #include "GCUtils.h" +#include "BeginPrivate.h" + INLINE_HEADER void push_mark_stack(StgPtr p) { diff --git a/testsuite/config/ghc b/testsuite/config/ghc index 632db8fc57..d33101fef8 100644 --- a/testsuite/config/ghc +++ b/testsuite/config/ghc @@ -58,6 +58,7 @@ if ghc_with_dynamic_rts: if windows: config.supports_dynamic_hs = False + config.stdcxx_impl = 'c++' if (config.have_profiling and ghc_with_threaded_rts): config.run_ways.append('profthreaded') diff --git a/testsuite/driver/runtests.py b/testsuite/driver/runtests.py index d2e25eaa19..0d458924d0 100644 --- a/testsuite/driver/runtests.py +++ b/testsuite/driver/runtests.py @@ -232,6 +232,8 @@ else: print('WARNING: No UTF8 locale found.') print('You may get some spurious test failures.') +ghc_env['LIBCXX'] = config.stdcxx_impl + # https://stackoverflow.com/a/22254892/1308058 def supports_colors(): """ diff --git a/testsuite/driver/testglobals.py b/testsuite/driver/testglobals.py index 6847cece68..b85a14e17a 100644 --- a/testsuite/driver/testglobals.py +++ b/testsuite/driver/testglobals.py @@ -217,6 +217,8 @@ class TestConfig: # The path specifies the file in which to write the dependencies self.only_report_hadrian_deps = None # type: Optional[Path] + # C++ standard library implementation + self.stdcxx_impl = 'stdc++' # or c++ for LLVM/libc++ based platforms def validate(self) -> None: """ Check the TestConfig for self-consistency """ diff --git a/testsuite/driver/testlib.py b/testsuite/driver/testlib.py index 7ee179b837..9c9a1760a2 100644 --- a/testsuite/driver/testlib.py +++ b/testsuite/driver/testlib.py @@ -1303,7 +1303,9 @@ def framework_fail(name: Optional[TestName], way: Optional[WayName], reason: str if_verbose(1, '*** framework failure for %s %s ' % (full_name, reason)) name2 = name if name is not None else TestName('none') way2 = way if way is not None else WayName('none') - t.framework_failures.append(TestResult(directory, name2, reason, way2)) + if way not in opts.fragile_ways: + # If the test is fragile then we rather report this as a fragile test failure + t.framework_failures.append(TestResult(directory, name2, reason, way2)) def framework_warn(name: TestName, way: WayName, reason: str) -> None: opts = getTestOpts() diff --git a/testsuite/mk/boilerplate.mk b/testsuite/mk/boilerplate.mk index 03c281f76d..df1b835b0c 100644 --- a/testsuite/mk/boilerplate.mk +++ b/testsuite/mk/boilerplate.mk @@ -308,6 +308,8 @@ ifeq "$(HostOS)" "freebsd" LIBCXX_PLATFORM = YES else ifeq "$(HostOS)" "openbsd" LIBCXX_PLATFORM = YES +else ifeq "$(HostOS)" "mingw32" +LIBCXX_PLATFORM = YES else LIBCXX_PLATFORM = NO endif diff --git a/testsuite/tests/codeGen/should_compile/all.T b/testsuite/tests/codeGen/should_compile/all.T index 9985580e78..a18451b98e 100644 --- a/testsuite/tests/codeGen/should_compile/all.T +++ b/testsuite/tests/codeGen/should_compile/all.T @@ -104,3 +104,6 @@ test('T15570', # warning: integer constant is so large that it is unsigned test('T18614', normal, compile, ['']) +test('mk-big-obj', + [unless(opsys('mingw32'), skip), pre_cmd('$PYTHON mk-big-obj.py > mk-big-obj.c')], + multimod_compile, ['mk-big-obj.c', '-c -v0 -no-hs-main']) diff --git a/testsuite/tests/codeGen/should_compile/mk-big-obj.py b/testsuite/tests/codeGen/should_compile/mk-big-obj.py new file mode 100644 index 0000000000..c03fdbf380 --- /dev/null +++ b/testsuite/tests/codeGen/should_compile/mk-big-obj.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 + +for i in range(70000): + print(f''' + int __attribute__((section("text.test{i}"))) + test{i}(void) + {{ return {i}; }} + ''') + diff --git a/testsuite/tests/codeGen/should_fail/all.T b/testsuite/tests/codeGen/should_fail/all.T index e23fa03f82..3f2dacee46 100644 --- a/testsuite/tests/codeGen/should_fail/all.T +++ b/testsuite/tests/codeGen/should_fail/all.T @@ -7,7 +7,7 @@ test('T8131', [cmm_src, only_ways(llvm_ways)], compile_fail, ['-no-hs-main']) def check_bounds_test(name): """ A -fcheck-prim-bounds test that is expected to fail. """ test(name, - [ignore_stderr, exit_code(3 if opsys('mingw32') else 134)], + [ignore_stderr, exit_code(127 if opsys('mingw32') else 134)], compile_and_run, ['-fcheck-prim-bounds']) check_bounds_test('CheckBoundsWriteArray') diff --git a/testsuite/tests/ghci/linking/Makefile b/testsuite/tests/ghci/linking/Makefile index 78d13c6e8a..7b77e91c09 100644 --- a/testsuite/tests/ghci/linking/Makefile +++ b/testsuite/tests/ghci/linking/Makefile @@ -24,12 +24,6 @@ else DLL = lib$1.so endif -ifeq "$(LIBCXX_PLATFORM)" "YES" -LIBCXX=c++ -else -LIBCXX=stdc++ -endif - .PHONY: ghcilink002 ghcilink002 : $(RM) -rf dir002 @@ -118,11 +112,7 @@ ghcilink006 : echo "version: 1.0" >>$(PKG006) echo "id: test-XXX" >>$(PKG006) echo "key: test-XXX" >>$(PKG006) -ifeq "$(WINDOWS)" "YES" - echo "extra-libraries: stdc++-6" >>$(PKG006) -else echo "extra-libraries: $(LIBCXX)" >>$(PKG006) -endif '$(GHC_PKG)' init $(LOCAL_PKGCONF006) '$(GHC_PKG)' --no-user-package-db -f $(LOCAL_PKGCONF006) register $(PKG006) -v0 # diff --git a/testsuite/tests/ghci/linking/all.T b/testsuite/tests/ghci/linking/all.T index 40d79cbc09..b4564f0237 100644 --- a/testsuite/tests/ghci/linking/all.T +++ b/testsuite/tests/ghci/linking/all.T @@ -12,8 +12,6 @@ test('ghcilink002', [extra_files(['TestLink.hs', 'f.c']), test('ghcilink003', [ unless(doing_ghci, skip), - # libstdc++ is GCC-specific on FreeBSD. FreeBSD has libc++ though. - when(opsys('freebsd'), fragile(17739)), # from Big Sur onwards, we can't dlopen libstdc++.dylib # anymore. Will produce: # dlopen(libstdc++.dylib, 5): image not found @@ -36,8 +34,6 @@ test('ghcilink005', test('ghcilink006', [ unless(doing_ghci, skip), - # libstdc++ is GCC-specific on FreeBSD. FreeBSD has libc++ though. - when(opsys('freebsd'), fragile(17739)), # from Big Sur onwards, we can't dlopen libstdc++.dylib # anymore. Will produce: # dlopen(libstdc++.dylib, 5): image not found diff --git a/testsuite/tests/ghci/linking/dyn/A.def b/testsuite/tests/ghci/linking/dyn/A.def new file mode 100644 index 0000000000..5198ddd028 --- /dev/null +++ b/testsuite/tests/ghci/linking/dyn/A.def @@ -0,0 +1,3 @@ +LIBRARY libA +EXPORTS +foo
\ No newline at end of file diff --git a/testsuite/tests/ghci/linking/dyn/B.def b/testsuite/tests/ghci/linking/dyn/B.def new file mode 100644 index 0000000000..bdfc2cbfbb --- /dev/null +++ b/testsuite/tests/ghci/linking/dyn/B.def @@ -0,0 +1,3 @@ +LIBRARY libB +EXPORTS +bar diff --git a/testsuite/tests/ghci/linking/dyn/Makefile b/testsuite/tests/ghci/linking/dyn/Makefile index 7f14f7d08a..da8ee20790 100644 --- a/testsuite/tests/ghci/linking/dyn/Makefile +++ b/testsuite/tests/ghci/linking/dyn/Makefile @@ -2,6 +2,16 @@ TOP=../../../.. include $(TOP)/mk/boilerplate.mk include $(TOP)/mk/test.mk +# On Windows we must provide module definitions (.def files) +# for shared libraries, lest the linker exports *everything*, including RTS +# symbols. This would mean that we couldn't link against multiple dynamic +# objects simultaneously as the RTS symbols would be defined multiple times. +ifeq "$(WINDOWS)" "YES" +DEF = "$1.def" +else +DEF = +endif + ifeq "$(WINDOWS)" "YES" DLL = lib$1.dll else ifeq "$(DARWIN)" "YES" @@ -62,16 +72,16 @@ compile_libT10458: compile_libAB_dep: rm -rf bin_dep mkdir bin_dep - '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dep" -shared A.c -o "bin_dep/$(call DLL,A)" - '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dep" -shared B.c -o "bin_dep/$(call DLL,B)" -lA -L"./bin_dep" + '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dep" -shared A.c -o "bin_dep/$(call DLL,A)" $(call DEF,A) + '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dep" -shared B.c -o "bin_dep/$(call DLL,B)" $(call DEF,B) -lA -L"./bin_dep" rm -f bin_dep/*.a .PHONY: compile_libAB_dyn compile_libAB_dyn: rm -rf bin_dyn mkdir bin_dyn - '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dyn" -shared A.c -o "bin_dyn/$(call DLL,A)" - '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dyn" -shared B.c -o "bin_dyn/$(call DLL,B)" -lA -L"./bin_dyn" + '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dyn" -shared A.c -o "bin_dyn/$(call DLL,A)" $(call DEF,A) + '$(TEST_HC)' $(MY_TEST_HC_OPTS) -odir "bin_dyn" -shared B.c -o "bin_dyn/$(call DLL,B)" $(call DEF,B) -lA -L"./bin_dyn" rm -f bin_dyn/*.a '$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -v0 -o "bin_dyn/$(call EXE,T10955dyn)" -L./bin_dyn -lB -lA T10955dyn.hs -v0 LD_LIBRARY_PATH=./bin_dyn ./bin_dyn/$(call EXE,T10955dyn) @@ -99,6 +109,7 @@ T1407: .PHONY: T3242 echo ":q" | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) -lm +# We use gdi32 as library with an import library. .PHONY: T13606 T13606: - echo ":q" | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) -lgcc_s + echo ":q" | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) -lgdi32.a diff --git a/testsuite/tests/ghci/linking/dyn/all.T b/testsuite/tests/ghci/linking/dyn/all.T index 0092f7febe..9b05ed5fc3 100644 --- a/testsuite/tests/ghci/linking/dyn/all.T +++ b/testsuite/tests/ghci/linking/dyn/all.T @@ -16,13 +16,15 @@ test('T3242', makefile_test, ['T3242']) test('T10955', - [extra_files(['A.c', 'B.c']), - unless(doing_ghci, skip), unless(opsys('mingw32'), skip), + [extra_files(['A.c', 'B.c', 'A.def', 'B.def']), + unless(doing_ghci, skip), + unless(opsys('mingw32'), skip), pre_cmd('$MAKE -s --no-print-directory compile_libAB_dep'), extra_hc_opts('-L. -L./bin_dep')], ghci_script, ['T10955.script']) -test('T10955dyn', [extra_files(['A.c', 'B.c'])], makefile_test, ['compile_libAB_dyn']) +test('T10955dyn', [extra_files(['A.c', 'B.c', 'A.def', 'B.def'])], + makefile_test, ['compile_libAB_dyn']) test('T10458', [extra_files(['A.c']), diff --git a/testsuite/tests/linters/Makefile b/testsuite/tests/linters/Makefile index 54ef4db132..2b4c2ad2c3 100644 --- a/testsuite/tests/linters/Makefile +++ b/testsuite/tests/linters/Makefile @@ -20,6 +20,9 @@ version-number: cpp: (cd $(TOP)/tests/linters/ && python3 regex-linters/check-cpp.py tracked) +rts-includes: + (cd $(TOP)/tests/linters/ && python3 regex-linters/check-rts-includes.py tracked) + changelogs: regex-linters/check-changelogs.sh $(TOP)/.. diff --git a/testsuite/tests/linters/all.T b/testsuite/tests/linters/all.T index 16700869a4..0e06df6d50 100644 --- a/testsuite/tests/linters/all.T +++ b/testsuite/tests/linters/all.T @@ -23,7 +23,11 @@ test('changelogs', [ no_deps if has_ls_files() else skip test('cpp', [ no_deps if has_ls_files() else skip , extra_files(["regex-linters"]) ] - , makefile_test, ['cpp']) + , makefile_test, ['cpp']) + +test('rts-includes', [ no_deps if has_ls_files() else skip + , extra_files(["regex-linters"]) ] + , makefile_test, ['rts-includes']) test('version-number', [ no_deps if has_ls_files() else skip , extra_files(["regex-linters"]) ] diff --git a/testsuite/tests/linters/regex-linters/check-rts-includes.py b/testsuite/tests/linters/regex-linters/check-rts-includes.py new file mode 100755 index 0000000000..14f22995b6 --- /dev/null +++ b/testsuite/tests/linters/regex-linters/check-rts-includes.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 + +# A linter to warn for ASSERT macros which are separated from their argument +# list by a space, which Clang's CPP barfs on + +from pathlib import Path +from linter import run_linters, Linter, Warning + +from typing import List, Tuple +import re + +INCLUDE_RE = re.compile('# *include ([<"][^">]+[>"])') + +def get_includes(file: Path) -> List[Tuple[int, str]]: + txt = file.read_text() + return [ (line_no+1, m.group(1) ) + for (line_no, line) in enumerate(txt.split('\n')) + for m in [INCLUDE_RE.match(line)] + if m is not None + if m.group(1) != "rts/PosixSource.h"] + +def in_rts_dir(path: Path) -> bool: + return len(path.parts) > 0 and path.parts[0] == 'rts' + +class RtsHIncludeOrderLinter(Linter): + """ + Verify that "PosixSource.h" is always the first #include in source files to + ensure __USE_MINGW_ANSI_STDIO is defined before system headers are + #include'd. + """ + def __init__(self): + Linter.__init__(self) + self.add_path_filter(in_rts_dir) + self.add_path_filter(lambda path: path.suffix == '.c') + + def lint(self, path: Path): + # We do allow a few small headers to precede Rts.h + ALLOWED_HEADERS = { + '"ghcconfig.h"', + '"ghcplatform.h"', + } + + includes = get_includes(path) + headers = [x[1] for x in includes] + lines = path.read_text().split('\n') + + if '"PosixSource.h"' in headers: + for line_no, header in includes: + if header == '"PosixSource.h"': + break + elif header in ALLOWED_HEADERS: + continue + + self.add_warning(Warning( + path=path, + line_no=line_no, + line_content=lines[line_no-1], + message="PosixSource.h must be first header included in each file")) + +class PrivateIncludeLinter(Linter): + """ + Verify that system headers are not #include'd in <BeginPrivate.h> blocks as this + can result in very hard-to-diagnose linking errors due to hidden library functions. + """ + def __init__(self): + Linter.__init__(self) + self.add_path_filter(in_rts_dir) + self.add_path_filter(lambda path: path.suffix == '.h') + + def lint(self, path: Path): + private = False + lines = path.read_text().split('\n') + for line_no, include in get_includes(path): + if include == '"BeginPrivate.h"': + private = True + elif include == '"EndPrivate.h"': + private = False + elif private: + self.add_warning(Warning( + path=path, + line_no=line_no, + line_content=lines[line_no-1], + message='System header %s found inside of <BeginPrivate.h> block' % include)) + +linters = [ + RtsHIncludeOrderLinter(), + PrivateIncludeLinter(), +] + +if __name__ == '__main__': + run_linters(linters) diff --git a/testsuite/tests/numeric/should_run/all.T b/testsuite/tests/numeric/should_run/all.T index b0580c7e2c..68888545f8 100644 --- a/testsuite/tests/numeric/should_run/all.T +++ b/testsuite/tests/numeric/should_run/all.T @@ -41,8 +41,7 @@ test('arith018', normal, compile_and_run, ['']) test('arith019', normal, compile_and_run, ['']) test('expfloat', normal, compile_and_run, ['']) -test('FloatFnInverses', [when(opsys('mingw32'), expect_broken(15670))], - compile_and_run, ['']) +test('FloatFnInverses', normal, compile_and_run, ['']) test('T1603', skip, compile_and_run, ['']) test('T3676', expect_broken(3676), compile_and_run, ['']) diff --git a/testsuite/tests/plugins/all.T b/testsuite/tests/plugins/all.T index 4e8663c73b..dca05d885c 100644 --- a/testsuite/tests/plugins/all.T +++ b/testsuite/tests/plugins/all.T @@ -99,7 +99,7 @@ test('plugins15', test('T10420', [extra_files(['rule-defining-plugin/']), - + when(opsys('mingw32'), expect_broken(21322)), pre_cmd('$MAKE -s --no-print-directory -C rule-defining-plugin package.T10420 TOP={top}')], makefile_test, []) @@ -258,11 +258,13 @@ test('T20218b', test('test-defaulting-plugin', [extra_files(['defaulting-plugin/']), + when(opsys('mingw32'), fragile(21293)), pre_cmd('$MAKE -s --no-print-directory -C defaulting-plugin package.test-defaulting-plugin TOP={top}')], makefile_test, []) test('test-defaulting-plugin-fail', [extra_files(['defaulting-plugin/']), + when(opsys('mingw32'), fragile(21293)), pre_cmd('$MAKE -s --no-print-directory -C defaulting-plugin package.test-defaulting-plugin-fail TOP={top}')], makefile_test, []) diff --git a/testsuite/tests/rts/T10672/Makefile b/testsuite/tests/rts/T10672/Makefile index 5fc458857e..bcc9a5c22b 100644 --- a/testsuite/tests/rts/T10672/Makefile +++ b/testsuite/tests/rts/T10672/Makefile @@ -3,9 +3,9 @@ include $(TOP)/mk/boilerplate.mk include $(TOP)/mk/test.mk T10672_x64: - '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -rtsopts=none -fforce-recomp -lgcc_s_seh-1 -lstdc++-6 \ + '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -rtsopts=none -fforce-recomp -lgcc_s_seh-1 -l${LIBCXX} \ Main.hs Printf.hs cxxy.cpp T10672_x86: - '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -rtsopts=none -fforce-recomp -lgcc_s_dw2-1 -lstdc++-6 \ + '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -rtsopts=none -fforce-recomp -lgcc_s_dw2-1 -${LIBCXX} \ Main.hs Printf.hs cxxy.cpp diff --git a/testsuite/tests/rts/T16514_c.c b/testsuite/tests/rts/T16514_c.c new file mode 100644 index 0000000000..9acb7d7d1f --- /dev/null +++ b/testsuite/tests/rts/T16514_c.c @@ -0,0 +1,31 @@ +#include <stdio.h> + +void fn_hs(); +void fn() { + fn_hs(); +} + +void check(double sqrt2, double sqrt3, double sqrt5, + double sqrt8, double sqrt13, double sqrt21) +{ + printf("%f %f %f %f %f %f\n", sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21); + if (sqrt2 != 1.41421 || sqrt3 != 1.73205 || sqrt5 != 2.23607 || + sqrt8 != 2.82843 || sqrt13 != 3.60555 || sqrt21 != 4.58258) { + fprintf(stderr, "xmm registers have been scratched\n"); + } +} + +int test() { + double sqrt2 = 1.41421; + double sqrt3 = 1.73205; + double sqrt5 = 2.23607; + double sqrt8 = 2.82843; + double sqrt13 = 3.60555; + double sqrt21 = 4.58258; + check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21); + fn(); + check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21); + fn(); + check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21); + return 0; +}
\ No newline at end of file diff --git a/testsuite/tests/rts/T16514_c.cpp b/testsuite/tests/rts/T16514_c.cpp deleted file mode 100644 index 1474741ec0..0000000000 --- a/testsuite/tests/rts/T16514_c.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include <iostream> -#include <stdexcept> - -extern "C" { - -void fn_hs(); -void fn() { - fn_hs(); -} - -void check(double sqrt2, double sqrt3, double sqrt5, - double sqrt8, double sqrt13, double sqrt21) { - std::cout << std::fixed << sqrt2 << " " << sqrt3 << " " << sqrt5 << " " - << sqrt8 << " " << sqrt13 << " " << sqrt21 << std::endl; - if (sqrt2 != 1.41421 || sqrt3 != 1.73205 || sqrt5 != 2.23607 || - sqrt8 != 2.82843 || sqrt13 != 3.60555 || sqrt21 != 4.58258) { - throw std::runtime_error("xmm registers have been scratched"); - } -} - -int test() { - try { - double sqrt2 = 1.41421; - double sqrt3 = 1.73205; - double sqrt5 = 2.23607; - double sqrt8 = 2.82843; - double sqrt13 = 3.60555; - double sqrt21 = 4.58258; - check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21); - fn(); - check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21); - try { - fn(); - } catch (const std::exception &) { - } - check(sqrt2, sqrt3, sqrt5, sqrt8, sqrt13, sqrt21); - } catch (const std::exception &e) { - std::cerr << e.what() << std::endl; - return 1; - } - return 0; -} - -} // extern "C" - diff --git a/testsuite/tests/rts/all.T b/testsuite/tests/rts/all.T index c13f1aa0ea..75dcf5ac58 100644 --- a/testsuite/tests/rts/all.T +++ b/testsuite/tests/rts/all.T @@ -387,7 +387,7 @@ test('T10904', [ omit_ways(['ghci']), extra_run_opts('20000') ], test('T10728', [extra_run_opts('+RTS -maxN3 -RTS'), only_ways(['threaded2'])], compile_and_run, ['']) -test('T9405', [when(msys(), expect_broken(12714))], makefile_test, ['T9405']) +test('T9405', [when(opsys('mingw32'), expect_broken(21361))], makefile_test, ['T9405']) test('T11788', when(ghc_dynamic(), skip), makefile_test, ['T11788']) @@ -474,9 +474,10 @@ test('keep-cafs', # Test proper functioning of C++ exceptions within a C++ program. # On darwin, this requires -fcompact-unwind. # When -fcompact-unwind becomes default, generalize test to all platforms. -test('T11829', unless(opsys('darwin'), skip), compile_and_run, ['T11829_c.cpp -lstdc++ -fcompact-unwind']) +test('T11829', unless(opsys('darwin'), skip), compile_and_run, + ['T11829_c.cpp -l{} -fcompact-unwind'.format(config.stdcxx_impl)]) -test('T16514', unless(opsys('mingw32'), skip), compile_and_run, ['T16514_c.cpp -lstdc++']) +test('T16514', normal, compile_and_run, ['T16514_c.c']) test('test-zeroongc', extra_run_opts('-DZ'), compile_and_run, ['-debug']) test('T13676', diff --git a/testsuite/tests/rts/linker/T5435_v_asm_a.stdout-mingw32 b/testsuite/tests/rts/linker/T5435_v_asm_a.stdout-mingw32 index 293bd12fb0..f5f0ff1284 100644 --- a/testsuite/tests/rts/linker/T5435_v_asm_a.stdout-mingw32 +++ b/testsuite/tests/rts/linker/T5435_v_asm_a.stdout-mingw32 @@ -1,3 +1,3 @@ +success ctors1 ctors2 -success diff --git a/testsuite/tests/rts/linker/T5435_v_gcc.stdout-mingw32 b/testsuite/tests/rts/linker/T5435_v_gcc.stdout-mingw32 new file mode 100644 index 0000000000..ebe1f4f250 --- /dev/null +++ b/testsuite/tests/rts/linker/T5435_v_gcc.stdout-mingw32 @@ -0,0 +1,2 @@ +success +initializer run diff --git a/testsuite/tests/rts/linker/all.T b/testsuite/tests/rts/linker/all.T index e42db98922..0cb93370aa 100644 --- a/testsuite/tests/rts/linker/all.T +++ b/testsuite/tests/rts/linker/all.T @@ -82,6 +82,7 @@ test('T5435_dyn_gcc', extra_files(['T5435.hs', 'T5435_gcc.c']) , makefile_test, ###################################### test('linker_unload', [extra_files(['LinkerUnload.hs', 'Test.hs']), + when(opsys('mingw32'), expect_broken(21354)), req_rts_linker], makefile_test, ['linker_unload']) @@ -119,8 +120,9 @@ test('T7072', test('T20918', - [extra_files(['T20918_v.cc']), - unless(opsys('mingw32'), skip), - req_rts_linker], - makefile_test, ['T20918']) + [extra_files(['T20918_v.cc']), + unless(opsys('mingw32'), skip), + when(opsys('mingw32'), expect_broken(2)), + req_rts_linker], + makefile_test, ['T20918']) diff --git a/testsuite/tests/rts/linker/unload_multiple_objs/all.T b/testsuite/tests/rts/linker/unload_multiple_objs/all.T index 52f35b4e26..85548af491 100644 --- a/testsuite/tests/rts/linker/unload_multiple_objs/all.T +++ b/testsuite/tests/rts/linker/unload_multiple_objs/all.T @@ -1,4 +1,5 @@ test('linker_unload_multiple_objs', [extra_files(['../LinkerUnload.hs', 'A.hs', 'B.hs', 'C.hs', 'D.hs',]), + when(opsys('mingw32'), expect_broken(21354)), req_rts_linker], run_command, ['$MAKE -s --no-print-directory linker_unload_multiple_objs']) diff --git a/testsuite/tests/th/T13366C.hs b/testsuite/tests/th/T13366C.hs new file mode 100644 index 0000000000..246687dcf0 --- /dev/null +++ b/testsuite/tests/th/T13366C.hs @@ -0,0 +1,23 @@ +{-# LANGUAGE ForeignFunctionInterface #-} +{-# LANGUAGE TemplateHaskell #-} +{-# OPTIONS_GHC -optc-DA_MACRO=1 -optcxx-DA_MACRO=1 #-} + +import Language.Haskell.TH.Syntax +import System.IO (hFlush, stdout) + +foreign import ccall fc :: Int -> IO Int + +do addForeignSource LangC $ unlines + [ "#include <stdio.h>" + , "int fc(int x) {" + , " printf(\"calling f(%d)\\n\",x);" + , " fflush(stdout);" + , " return A_MACRO + x;" + , "}" + ] + return [] + +main :: IO () +main = do + fc 2 >>= print + hFlush stdout diff --git a/testsuite/tests/th/T13366C.stdout b/testsuite/tests/th/T13366C.stdout new file mode 100644 index 0000000000..2ab79e85b8 --- /dev/null +++ b/testsuite/tests/th/T13366C.stdout @@ -0,0 +1,2 @@ +calling f(2) +3 diff --git a/testsuite/tests/th/T13366.hs b/testsuite/tests/th/T13366Cxx.hs index 7d998f2ae8..37ab25a4d1 100644 --- a/testsuite/tests/th/T13366.hs +++ b/testsuite/tests/th/T13366Cxx.hs @@ -5,18 +5,6 @@ import Language.Haskell.TH.Syntax import System.IO (hFlush, stdout) -foreign import ccall fc :: Int -> IO Int - -do addForeignSource LangC $ unlines - [ "#include <stdio.h>" - , "int fc(int x) {" - , " printf(\"calling f(%d)\\n\",x);" - , " fflush(stdout);" - , " return A_MACRO + x;" - , "}" - ] - return [] - foreign import ccall fcxx :: Int -> IO Int do addForeignSource LangCxx $ unlines @@ -33,7 +21,5 @@ do addForeignSource LangCxx $ unlines main :: IO () main = do - fc 2 >>= print - hFlush stdout fcxx 5 >>= print hFlush stdout diff --git a/testsuite/tests/th/T13366.stdout b/testsuite/tests/th/T13366Cxx.stdout index 16cfeeb9fa..bdf7a41a33 100644 --- a/testsuite/tests/th/T13366.stdout +++ b/testsuite/tests/th/T13366Cxx.stdout @@ -1,4 +1,2 @@ -calling f(2) -3 calling fcxx(5) 6 diff --git a/testsuite/tests/th/all.T b/testsuite/tests/th/all.T index d04bb08b29..2a003b8141 100644 --- a/testsuite/tests/th/all.T +++ b/testsuite/tests/th/all.T @@ -52,8 +52,7 @@ test('TH_NestedSplices', [], multimod_compile, # normal way first, which is why the work is done by a Makefile rule. test('TH_spliceE5_prof', [req_profiling, only_ways(['normal']), - when(ghc_dynamic(), expect_broken(11495)), - when(opsys('mingw32'), expect_broken(18271))], + when(ghc_dynamic(), expect_broken(11495))], makefile_test, ['TH_spliceE5_prof']) test('TH_spliceE5_prof_ext', [req_profiling, req_rts_linker, only_ways(['normal'])], @@ -395,14 +394,16 @@ test('T13018', normal, compile, ['-v0']) test('T13123', normal, compile, ['-v0']) test('T13098', normal, compile, ['-v0']) test('T11046', normal, multimod_compile, ['T11046','-v0']) -test('T13366', +test('T13366C', + [expect_broken_for(13366, ['ghci'])], + compile_and_run, + ['-v0']) +test('T13366Cxx', [expect_broken_for(13366, ['ghci']), - # libstdc++ is GCC-specific on FreeBSD, the test will - # fail with clang, and pass with GCC. - when(opsys('freebsd'), fragile(17739)), - when(opsys('darwin'), expect_broken(16083))], + when(opsys('darwin'), expect_broken(16083)) + ], compile_and_run, - ['-lstdc++ -v0'] if not opsys('openbsd') else ['-lc++ -lc++abi -v0']) + ['-l{} -v0'.format(config.stdcxx_impl)]) test('T13473', normal, multimod_compile_and_run, ['T13473.hs', '-v0 ' + config.ghc_th_way_flags]) test('T13587', expect_broken(13587), compile_and_run, ['-v0']) |