From e6c803f702e8b09dfd0073b973b8afcd7071db50 Mon Sep 17 00:00:00 2001 From: Rodrigo Mesquita <rodrigo.m.mesquita@gmail.com> Date: Wed, 8 Nov 2023 13:54:54 +0000 Subject: [PATCH] darwin: Fix single_module is obsolete warning In XCode 15's linker, -single_module is the default and otherwise passing it as a flag results in a warning being raised: ld: warning: -single_module is obsolete This patch fixes this warning by, at configure time, determining whether the linker supports -single_module (which is likely false for all non-darwin linkers, and true for darwin linkers in previous versions of macOS), and using that information at runtime to decide to pass or not the flag in the invocation. Fixes #24168 --- compiler/GHC/Linker/Dynamic.hs | 11 ++++-- compiler/GHC/Settings.hs | 1 + compiler/GHC/Settings/IO.hs | 2 ++ configure.ac | 1 + distrib/configure.ac.in | 1 + hadrian/bindist/Makefile | 1 + hadrian/bindist/config.mk.in | 1 + hadrian/cfg/default.host.target.in | 1 + hadrian/cfg/default.target.in | 1 + hadrian/src/Rules/Generate.hs | 2 ++ m4/fp_prog_ld_single_module.m4 | 30 ++++++++++++++++ m4/prep_target_file.m4 | 1 + .../src/GHC/Toolchain/Tools/Link.hs | 34 ++++++++++++++++++- 13 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 m4/fp_prog_ld_single_module.m4 diff --git a/compiler/GHC/Linker/Dynamic.hs b/compiler/GHC/Linker/Dynamic.hs index 7cfd797d6b06..053a2ca89006 100644 --- a/compiler/GHC/Linker/Dynamic.hs +++ b/compiler/GHC/Linker/Dynamic.hs @@ -11,6 +11,7 @@ where import GHC.Prelude import GHC.Platform import GHC.Platform.Ways +import GHC.Settings (ToolSettings(toolSettings_ldSupportsSingleModule)) import GHC.Driver.Config.Linker import GHC.Driver.Session @@ -152,6 +153,9 @@ linkDynLib logger tmpfs dflags0 unit_env o_files dep_packages -- dynamic binding nonsense when referring to symbols from -- within the library. The NCG assumes that this option is -- specified (on i386, at least). + -- In XCode 15, -single_module is the default and passing the + -- flag is now obsolete and raises a warning (#24168). We encode + -- this information into the toolchain field ...SupportsSingleModule. -- -install_name -- Mac OS/X stores the path where a dynamic library is (to -- be) installed in the library itself. It's called the @@ -177,8 +181,11 @@ linkDynLib logger tmpfs dflags0 unit_env o_files dep_packages ] ++ map Option o_files ++ [ Option "-undefined", - Option "dynamic_lookup", - Option "-single_module" ] + Option "dynamic_lookup" + ] + ++ (if toolSettings_ldSupportsSingleModule (toolSettings dflags) + then [ Option "-single_module" ] + else [ ]) ++ (if platformArch platform `elem` [ ArchX86_64, ArchAArch64 ] then [ ] else [ Option "-Wl,-read_only_relocs,suppress" ]) diff --git a/compiler/GHC/Settings.hs b/compiler/GHC/Settings.hs index c1a9d4d788c9..e2fc7338ecdf 100644 --- a/compiler/GHC/Settings.hs +++ b/compiler/GHC/Settings.hs @@ -86,6 +86,7 @@ data Settings = Settings data ToolSettings = ToolSettings { toolSettings_ldSupportsCompactUnwind :: Bool , toolSettings_ldSupportsFilelist :: Bool + , toolSettings_ldSupportsSingleModule :: Bool , toolSettings_mergeObjsSupportsResponseFiles :: Bool , toolSettings_ldIsGnuLd :: Bool , toolSettings_ccSupportsNoPie :: Bool diff --git a/compiler/GHC/Settings/IO.hs b/compiler/GHC/Settings/IO.hs index e765e2e5cfb8..dedd6fb9af12 100644 --- a/compiler/GHC/Settings/IO.hs +++ b/compiler/GHC/Settings/IO.hs @@ -107,6 +107,7 @@ initSettings top_dir = do ldSupportsCompactUnwind <- getBooleanSetting "ld supports compact unwind" ldSupportsFilelist <- getBooleanSetting "ld supports filelist" + ldSupportsSingleModule <- getBooleanSetting "ld supports single module" mergeObjsSupportsResponseFiles <- getBooleanSetting "Merge objects supports response files" ldIsGnuLd <- getBooleanSetting "ld is GNU ld" arSupportsDashL <- getBooleanSetting "ar supports -L" @@ -171,6 +172,7 @@ initSettings top_dir = do , sToolSettings = ToolSettings { toolSettings_ldSupportsCompactUnwind = ldSupportsCompactUnwind , toolSettings_ldSupportsFilelist = ldSupportsFilelist + , toolSettings_ldSupportsSingleModule = ldSupportsSingleModule , toolSettings_mergeObjsSupportsResponseFiles = mergeObjsSupportsResponseFiles , toolSettings_ldIsGnuLd = ldIsGnuLd , toolSettings_ccSupportsNoPie = gccSupportsNoPie diff --git a/configure.ac b/configure.ac index 3a6dfd32da86..36a754d75eea 100644 --- a/configure.ac +++ b/configure.ac @@ -452,6 +452,7 @@ CFLAGS="$CFLAGS $GccUseLdOpt" FP_PROG_LD_IS_GNU FP_PROG_LD_NO_COMPACT_UNWIND FP_PROG_LD_FILELIST +FP_PROG_LD_SINGLE_MODULE dnl ** Which nm to use? diff --git a/distrib/configure.ac.in b/distrib/configure.ac.in index ecbfebef5784..8a2016c1c8fa 100644 --- a/distrib/configure.ac.in +++ b/distrib/configure.ac.in @@ -136,6 +136,7 @@ CFLAGS="$CFLAGS $GccUseLdOpt" FP_PROG_LD_IS_GNU FP_PROG_LD_NO_COMPACT_UNWIND FP_PROG_LD_FILELIST +FP_PROG_LD_SINGLE_MODULE dnl ** which strip to use? dnl -------------------------------------------------------------- diff --git a/hadrian/bindist/Makefile b/hadrian/bindist/Makefile index 31fe94c72b1b..293a0bfdd380 100644 --- a/hadrian/bindist/Makefile +++ b/hadrian/bindist/Makefile @@ -104,6 +104,7 @@ lib/settings : config.mk @echo ',("Haskell CPP flags", "$(SettingsHaskellCPPFlags)")' >> $@ @echo ',("ld supports compact unwind", "$(LdHasNoCompactUnwind)")' >> $@ @echo ',("ld supports filelist", "$(LdHasFilelist)")' >> $@ + @echo ',("ld supports single module", "$(LdHasSingleModule)")' >> $@ @echo ',("ld is GNU ld", "$(LdIsGNULd)")' >> $@ @echo ',("Merge objects command", "$(SettingsMergeObjectsCommand)")' >> $@ @echo ',("Merge objects flags", "$(SettingsMergeObjectsFlags)")' >> $@ diff --git a/hadrian/bindist/config.mk.in b/hadrian/bindist/config.mk.in index 4a21d7d0e437..fd158c411948 100644 --- a/hadrian/bindist/config.mk.in +++ b/hadrian/bindist/config.mk.in @@ -191,6 +191,7 @@ LdHasBuildId = @LdHasBuildId@ LdHasFilelist = @LdHasFilelist@ LdIsGNULd = @LdIsGNULd@ LdHasNoCompactUnwind = @LdHasNoCompactUnwind@ +LdHasSingleModule = @LdHasSingleModule@ ArArgs = @ArArgs@ ArSupportsAtFile = @ArSupportsAtFile@ ArSupportsDashL = @ArSupportsDashL@ diff --git a/hadrian/cfg/default.host.target.in b/hadrian/cfg/default.host.target.in index e38e20cda7a9..eaf01470c887 100644 --- a/hadrian/cfg/default.host.target.in +++ b/hadrian/cfg/default.host.target.in @@ -21,6 +21,7 @@ Target , ccLinkSupportsNoPie = False , ccLinkSupportsCompactUnwind = False , ccLinkSupportsFilelist = False +, ccLinkSupportsSingleModule = True , ccLinkIsGnu = False } diff --git a/hadrian/cfg/default.target.in b/hadrian/cfg/default.target.in index 84da17bc160d..a9888a2df4ac 100644 --- a/hadrian/cfg/default.target.in +++ b/hadrian/cfg/default.target.in @@ -21,6 +21,7 @@ Target , ccLinkSupportsNoPie = @CONF_GCC_SUPPORTS_NO_PIEBool@ , ccLinkSupportsCompactUnwind = @LdHasNoCompactUnwindBool@ , ccLinkSupportsFilelist = @LdHasFilelistBool@ +, ccLinkSupportsSingleModule = @LdHasSingleModuleBool@ , ccLinkIsGnu = @LdIsGNULdBool@ } diff --git a/hadrian/src/Rules/Generate.hs b/hadrian/src/Rules/Generate.hs index 5787e2054e81..bf84da2f9de3 100644 --- a/hadrian/src/Rules/Generate.hs +++ b/hadrian/src/Rules/Generate.hs @@ -373,6 +373,7 @@ generateSettings = do , ("Haskell CPP flags", queryTarget hsCppFlags) , ("ld supports compact unwind", queryTarget linkSupportsCompactUnwind) , ("ld supports filelist", queryTarget linkSupportsFilelist) + , ("ld supports single module", queryTarget linkSupportsSingleModule) , ("ld is GNU ld", queryTarget linkIsGnu) , ("Merge objects command", queryTarget mergeObjsPath) , ("Merge objects flags", queryTarget mergeObjsFlags) @@ -431,6 +432,7 @@ generateSettings = do hsCppFlags = unwords . prgFlags . hsCppProgram . tgtHsCPreprocessor mergeObjsPath = maybe "" (prgPath . mergeObjsProgram) . tgtMergeObjs mergeObjsFlags = maybe "" (unwords . prgFlags . mergeObjsProgram) . tgtMergeObjs + linkSupportsSingleModule = yesNo . ccLinkSupportsSingleModule . tgtCCompilerLink linkSupportsFilelist = yesNo . ccLinkSupportsFilelist . tgtCCompilerLink linkSupportsCompactUnwind = yesNo . ccLinkSupportsCompactUnwind . tgtCCompilerLink linkIsGnu = yesNo . ccLinkIsGnu . tgtCCompilerLink diff --git a/m4/fp_prog_ld_single_module.m4 b/m4/fp_prog_ld_single_module.m4 new file mode 100644 index 000000000000..3e124c81ca3e --- /dev/null +++ b/m4/fp_prog_ld_single_module.m4 @@ -0,0 +1,30 @@ +# FP_PROG_LD_SINGLE_MODULE +# ---------------------------- +# Sets the output variable LdHasSingleModule to YES if the darwin ld supports +# -single_module, or NO otherwise. +# +# In XCode 15, -single_module is a default and passing it as a flag raises a +# warning. +AC_DEFUN([FP_PROG_LD_SINGLE_MODULE], +[ +AC_CACHE_CHECK([whether ld supports -single_module], [fp_cv_ld_single_module], +[ +case $target in + *-darwin) + echo 'int foo(int x) { return x*x; }' > conftest.c + echo 'extern int foo(int); int main() { return foo(5); }' > conftestmain.c + "$CC" -c -o conftestmain.o conftestmain.c + "$CC" -shared -o conftest.dylib conftest.c + if "$CC" -Wl,-single_module -o conftest conftestmain.o conftest.dylib 2>&1 | grep obsolete > /dev/null; then + fp_cv_ld_single_module=no + else + fp_cv_ld_single_module=yes + fi + rm -rf conftest* ;; + *) + fp_cv_ld_single_module=no ;; +esac +]) +FP_CAPITALIZE_YES_NO(["$fp_cv_ld_single_module"], [LdHasSingleModule]) +AC_SUBST([LdHasSingleModule]) +])# FP_PROG_LD_SINGLE_MODULE diff --git a/m4/prep_target_file.m4 b/m4/prep_target_file.m4 index 89e773f75127..2cee899c1620 100644 --- a/m4/prep_target_file.m4 +++ b/m4/prep_target_file.m4 @@ -131,6 +131,7 @@ AC_DEFUN([PREP_TARGET_FILE],[ PREP_BOOLEAN([TargetHasIdentDirective]) PREP_BOOLEAN([CONF_GCC_SUPPORTS_NO_PIE]) PREP_BOOLEAN([LdHasFilelist]) + PREP_BOOLEAN([LdHasSingleModule]) PREP_BOOLEAN([LdIsGNULd]) PREP_BOOLEAN([LdHasNoCompactUnwind]) PREP_BOOLEAN([TargetHasSubsectionsViaSymbols]) diff --git a/utils/ghc-toolchain/src/GHC/Toolchain/Tools/Link.hs b/utils/ghc-toolchain/src/GHC/Toolchain/Tools/Link.hs index 080427c7d634..3dcf24745884 100644 --- a/utils/ghc-toolchain/src/GHC/Toolchain/Tools/Link.hs +++ b/utils/ghc-toolchain/src/GHC/Toolchain/Tools/Link.hs @@ -22,6 +22,7 @@ data CcLink = CcLink { ccLinkProgram :: Program , ccLinkSupportsNoPie :: Bool -- See Note [No PIE when linking] in GHC.Driver.Session , ccLinkSupportsCompactUnwind :: Bool , ccLinkSupportsFilelist :: Bool + , ccLinkSupportsSingleModule :: Bool , ccLinkIsGnu :: Bool } deriving (Read, Eq, Ord) @@ -34,6 +35,7 @@ instance Show CcLink where , ", ccLinkSupportsNoPie = " ++ show ccLinkSupportsNoPie , ", ccLinkSupportsCompactUnwind = " ++ show ccLinkSupportsCompactUnwind , ", ccLinkSupportsFilelist = " ++ show ccLinkSupportsFilelist + , ", ccLinkSupportsSingleModule = " ++ show ccLinkSupportsSingleModule , ", ccLinkIsGnu = " ++ show ccLinkIsGnu , "}" ] @@ -66,12 +68,13 @@ findCcLink target ld progOpt ldOverride archOs cc readelf = checking "for C comp ccLinkSupportsNoPie <- checkSupportsNoPie cc ccLinkProgram ccLinkSupportsCompactUnwind <- checkSupportsCompactUnwind archOs cc ccLinkProgram ccLinkSupportsFilelist <- checkSupportsFilelist cc ccLinkProgram + ccLinkSupportsSingleModule <- checkSupportsSingleModule archOs cc ccLinkProgram ccLinkIsGnu <- checkLinkIsGnu archOs ccLinkProgram checkBfdCopyBug archOs cc readelf ccLinkProgram ccLinkProgram <- addPlatformDepLinkFlags archOs cc ccLinkProgram let ccLink = CcLink {ccLinkProgram, ccLinkSupportsNoPie, ccLinkSupportsCompactUnwind, ccLinkSupportsFilelist, - ccLinkIsGnu} + ccLinkSupportsSingleModule, ccLinkIsGnu} ccLink <- linkRequiresNoFixupChains archOs cc ccLink ccLink <- linkRequiresNoWarnDuplicateLibraries archOs cc ccLink return ccLink @@ -164,6 +167,35 @@ checkSupportsFilelist cc ccLink = checking "whether the cc linker understands -f return (isSuccess exitCode) +-- | Check that the (darwin) linker supports @-single_module@. +-- +-- In XCode 15, the linker warns when @-single_module@ is passed as the flag +-- became the default and is now obsolete to pass. +-- +-- We assume non-darwin linkers don't support this flag. +checkSupportsSingleModule :: ArchOS -> Cc -> Program -> M Bool +checkSupportsSingleModule archOs cc link + | ArchOS _ OSDarwin <- archOs + = checking "whether the darwin linker supports -single_module" $ do + withTempDir $ \dir -> do + let test_dylib = dir </> "test.dylib" + test_c = dir </> "test.c" + testmain_o = dir </> "testmain.o" + testmain = dir </> "testmain" + + -- Main + compileC cc testmain_o "extern int foo(int); int main() { return foo(5); }" + + -- Dynamic library + writeFile test_c "int foo(int x) { return x*x; }" + _ <- runProgram (ccProgram cc) ["-shared", "-o", test_dylib, test_c] + + (_, out, err) <- readProgram link ["-Wl,-single_module", "-o", testmain, test_dylib, testmain_o] + + return $ not $ "obsolete" `isInfixOf` err || "obsolete" `isInfixOf` out + | otherwise + = return False + -- | Check whether linking works. checkLinkWorks :: Cc -> Program -> M () checkLinkWorks cc ccLink = withTempDir $ \dir -> do -- GitLab