From a6874e546294173c166859769dd8054887a6ded7 Mon Sep 17 00:00:00 2001 From: Simon Marlow <marlowsd@gmail.com> Date: Thu, 2 Mar 2017 16:17:12 -0500 Subject: Add -fwhole-archive-hs-libs We're building a demo to show how to hot-swap Haskell code in a running process, and unfortunately it wasn't possible to convince GHC to generate the correct linker command line without this extra knob. Test Plan: Tested it on a hot-swapping demo (which is not released yet, but will be shortly) Reviewers: niteria, austin, erikd, JonCoens, bgamari Reviewed By: bgamari Subscribers: Phyx, rwbarton, thomie Differential Revision: https://phabricator.haskell.org/D3136 --- testsuite/tests/driver/linkwhole/Handles.hs | 18 +++++++++ testsuite/tests/driver/linkwhole/Main.hs | 46 +++++++++++++++++++++++ testsuite/tests/driver/linkwhole/Makefile | 20 ++++++++++ testsuite/tests/driver/linkwhole/MyCode.hs | 6 +++ testsuite/tests/driver/linkwhole/Types.hs | 13 +++++++ testsuite/tests/driver/linkwhole/all.T | 2 + testsuite/tests/driver/linkwhole/linkwhole.stdout | 2 + 7 files changed, 107 insertions(+) create mode 100644 testsuite/tests/driver/linkwhole/Handles.hs create mode 100644 testsuite/tests/driver/linkwhole/Main.hs create mode 100644 testsuite/tests/driver/linkwhole/Makefile create mode 100644 testsuite/tests/driver/linkwhole/MyCode.hs create mode 100644 testsuite/tests/driver/linkwhole/Types.hs create mode 100644 testsuite/tests/driver/linkwhole/all.T create mode 100644 testsuite/tests/driver/linkwhole/linkwhole.stdout (limited to 'testsuite/tests/driver') diff --git a/testsuite/tests/driver/linkwhole/Handles.hs b/testsuite/tests/driver/linkwhole/Handles.hs new file mode 100644 index 0000000000..6e8d22715d --- /dev/null +++ b/testsuite/tests/driver/linkwhole/Handles.hs @@ -0,0 +1,18 @@ +module Handles + ( hsNewSOHandle + ) where + +import Foreign + +import Types + +import MyCode + +foreign export ccall "hs_soHandles" + hsNewSOHandle :: SOHandleExport + +hsNewSOHandle :: SOHandleExport +hsNewSOHandle = newStablePtr SOHandles + { someData = "I'm a shared object" + , someFn = myFunction + } diff --git a/testsuite/tests/driver/linkwhole/Main.hs b/testsuite/tests/driver/linkwhole/Main.hs new file mode 100644 index 0000000000..46e287ba65 --- /dev/null +++ b/testsuite/tests/driver/linkwhole/Main.hs @@ -0,0 +1,46 @@ +{-# LANGUAGE RecordWildCards #-} + +module Main (main) where + +import Control.Exception +import Control.Monad + +import Foreign + +import Types + +import System.Environment +import System.Posix.DynamicLinker +import GHCi.ObjLink + +rotateSO + :: (FunPtr (IO (StablePtr a)) -> (IO (StablePtr a))) + -> String + -> (Maybe FilePath, FilePath) + -> IO a +rotateSO dynamicCall symName (old, newDLL) = do + -- initObjLinker is idempotent + initObjLinker DontRetainCAFs + + loadObj newDLL + resolved <- resolveObjs + unless resolved $ + throwIO (ErrorCall $ "Unable to resolve objects for " ++ newDLL) + c_sym <- lookupSymbol symName + h <- case c_sym of + Nothing -> throwIO (ErrorCall "Could not find symbol") + Just p_sym -> + bracket (dynamicCall $ castPtrToFunPtr p_sym) freeStablePtr deRefStablePtr + purgeObj newDLL + forM_ old unloadObj + return h + +foreign import ccall "dynamic" + mkCallable :: FunPtr SOHandleExport -> SOHandleExport + +main :: IO () +main = do + [file] <- getArgs + SOHandles{..} <- rotateSO mkCallable "hs_soHandles" (Nothing, file) + someFn 7 + putStrLn $ "someData = " ++ show someData diff --git a/testsuite/tests/driver/linkwhole/Makefile b/testsuite/tests/driver/linkwhole/Makefile new file mode 100644 index 0000000000..6f4086f50c --- /dev/null +++ b/testsuite/tests/driver/linkwhole/Makefile @@ -0,0 +1,20 @@ +TOP=../../.. +include $(TOP)/mk/boilerplate.mk +include $(TOP)/mk/test.mk + +# Test for -fwhole-archive-hs-libs + +ifeq "$(HostOS)" "darwin" +NO_GC_SECTIONS= +else +NO_GC_SECTIONS=-optl-Wl,--no-gc-sections +endif + +linkwhole: + "$(TEST_HC)" $(TEST_HC_OPTS) -c Types.hs + "$(TEST_HC)" $(TEST_HC_OPTS) -c Main.hs + "$(TEST_HC)" $(TEST_HC_OPTS) -o host Main.o Types.o -fwhole-archive-hs-libs -package ghci -rdynamic $(NO_GC_SECTIONS) + "$(TEST_HC)" $(TEST_HC_OPTS) -c MyCode.hs + "$(TEST_HC)" $(TEST_HC_OPTS) -c Handles.hs + ld -r -o lib.so MyCode.o Handles.o + ./host lib.so diff --git a/testsuite/tests/driver/linkwhole/MyCode.hs b/testsuite/tests/driver/linkwhole/MyCode.hs new file mode 100644 index 0000000000..fbf6a63012 --- /dev/null +++ b/testsuite/tests/driver/linkwhole/MyCode.hs @@ -0,0 +1,6 @@ +module MyCode + ( myFunction + ) where + +myFunction :: Int -> IO () +myFunction i = putStrLn $ "Adding to 20: " ++ show (i + 20) diff --git a/testsuite/tests/driver/linkwhole/Types.hs b/testsuite/tests/driver/linkwhole/Types.hs new file mode 100644 index 0000000000..bccf25d957 --- /dev/null +++ b/testsuite/tests/driver/linkwhole/Types.hs @@ -0,0 +1,13 @@ +module Types + ( SOHandles(..) + , SOHandleExport + ) where + +import Foreign + +data SOHandles = SOHandles + { someData :: String + , someFn :: Int -> IO () + } + +type SOHandleExport = IO (StablePtr SOHandles) diff --git a/testsuite/tests/driver/linkwhole/all.T b/testsuite/tests/driver/linkwhole/all.T new file mode 100644 index 0000000000..dcef32b9c1 --- /dev/null +++ b/testsuite/tests/driver/linkwhole/all.T @@ -0,0 +1,2 @@ +test('linkwhole', [extra_files(['Types.hs','Main.hs','MyCode.hs','Handles.hs'])], + run_command, ['$MAKE -s --no-print-directory linkwhole']) diff --git a/testsuite/tests/driver/linkwhole/linkwhole.stdout b/testsuite/tests/driver/linkwhole/linkwhole.stdout new file mode 100644 index 0000000000..906827f497 --- /dev/null +++ b/testsuite/tests/driver/linkwhole/linkwhole.stdout @@ -0,0 +1,2 @@ +Adding to 20: 27 +someData = "I'm a shared object" -- cgit v1.2.1