summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Sandberg Ericsson <adam@sandbergericsson.se>2020-05-03 11:49:46 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-07-07 13:56:02 -0400
commitf496c9550098ffaa3bf25a3447c138626d79bae0 (patch)
treea0be56bcc35f868f33b60bede633707065aec782
parentcdfeb3f24f76e8fd30452016676e56fbc827789a (diff)
downloadhaskell-f496c9550098ffaa3bf25a3447c138626d79bae0.tar.gz
add -flink-rts flag to link the rts when linking a shared or static library #18072
By default we don't link the RTS when linking shared libraries because in the most usual mode a shared library is an intermediary product, for example a Haskell library, that will be linked into some executable in the end. So we wish to defer the RTS flavour to link to the final link. However sometimes the final product is the shared library, for example when writing a plugin for some other system, so we do wish the shared library to link the RTS. For consistency we also make -staticlib honor this flag and its inversion. -staticlib currently implies -flink-shared.
-rw-r--r--compiler/GHC/Driver/Flags.hs1
-rw-r--r--compiler/GHC/Driver/Pipeline.hs9
-rw-r--r--compiler/GHC/Driver/Session.hs5
-rw-r--r--compiler/GHC/SysTools.hs4
-rw-r--r--docs/users_guide/8.12.1-notes.rst3
-rw-r--r--docs/users_guide/phases.rst19
-rw-r--r--docs/users_guide/shared_libs.rst21
-rw-r--r--testsuite/tests/dynlibs/Makefile32
-rw-r--r--testsuite/tests/dynlibs/T18072.hs10
-rw-r--r--testsuite/tests/dynlibs/all.T9
10 files changed, 101 insertions, 12 deletions
diff --git a/compiler/GHC/Driver/Flags.hs b/compiler/GHC/Driver/Flags.hs
index 93748bbc06..a827ffe315 100644
--- a/compiler/GHC/Driver/Flags.hs
+++ b/compiler/GHC/Driver/Flags.hs
@@ -274,6 +274,7 @@ data GeneralFlag
| Opt_KeepCAFs
| Opt_KeepGoing
| Opt_ByteCode
+ | Opt_LinkRts
-- output style opts
| Opt_ErrorSpans -- Include full span info in error messages,
diff --git a/compiler/GHC/Driver/Pipeline.hs b/compiler/GHC/Driver/Pipeline.hs
index 15cce2f11d..83e637401e 100644
--- a/compiler/GHC/Driver/Pipeline.hs
+++ b/compiler/GHC/Driver/Pipeline.hs
@@ -1937,7 +1937,14 @@ linkStaticLib dflags o_files dep_units = do
output_exists <- doesFileExist full_output_fn
(when output_exists) $ removeFile full_output_fn
- pkg_cfgs <- getPreloadUnitsAnd dflags dep_units
+ pkg_cfgs_init <- getPreloadUnitsAnd dflags dep_units
+
+ let pkg_cfgs
+ | gopt Opt_LinkRts dflags
+ = pkg_cfgs_init
+ | otherwise
+ = filter ((/= rtsUnitId) . unitId) pkg_cfgs_init
+
archives <- concatMapM (collectArchives dflags) pkg_cfgs
ar <- foldl mappend
diff --git a/compiler/GHC/Driver/Session.hs b/compiler/GHC/Driver/Session.hs
index 85eca17aed..a558ceae96 100644
--- a/compiler/GHC/Driver/Session.hs
+++ b/compiler/GHC/Driver/Session.hs
@@ -2435,7 +2435,7 @@ dynamic_flags_deps = [
, make_ord_flag defGhcFlag "shared"
(noArg (\d -> d { ghcLink=LinkDynLib }))
, make_ord_flag defGhcFlag "staticlib"
- (noArg (\d -> d { ghcLink=LinkStaticLib }))
+ (noArg (\d -> setGeneralFlag' Opt_LinkRts (d { ghcLink=LinkStaticLib })))
, make_ord_flag defGhcFlag "dynload" (hasArg parseDynLibLoaderMode)
, make_ord_flag defGhcFlag "dylib-install-name" (hasArg setDylibInstallName)
@@ -3599,7 +3599,8 @@ fFlagsDeps = [
flagSpec "hide-source-paths" Opt_HideSourcePaths,
flagSpec "show-loaded-modules" Opt_ShowLoadedModules,
flagSpec "whole-archive-hs-libs" Opt_WholeArchiveHsLibs,
- flagSpec "keep-cafs" Opt_KeepCAFs
+ flagSpec "keep-cafs" Opt_KeepCAFs,
+ flagSpec "link-rts" Opt_LinkRts
]
++ fHoleFlags
diff --git a/compiler/GHC/SysTools.hs b/compiler/GHC/SysTools.hs
index ab83b3bf2a..0b71e8ccde 100644
--- a/compiler/GHC/SysTools.hs
+++ b/compiler/GHC/SysTools.hs
@@ -274,7 +274,9 @@ linkDynLib dflags0 o_files dep_packages
pkgs_no_rts = case os of
OSMinGW32 ->
pkgs
- _ ->
+ _ | gopt Opt_LinkRts dflags ->
+ pkgs
+ | otherwise ->
filter ((/= rtsUnitId) . unitId) pkgs
let pkg_link_opts = let (package_hs_libs, extra_libs, other_flags) = collectLinkOpts dflags pkgs_no_rts
in package_hs_libs ++ extra_libs ++ other_flags
diff --git a/docs/users_guide/8.12.1-notes.rst b/docs/users_guide/8.12.1-notes.rst
index 1eb577c36e..b7f0444d69 100644
--- a/docs/users_guide/8.12.1-notes.rst
+++ b/docs/users_guide/8.12.1-notes.rst
@@ -216,6 +216,9 @@ Language
Compiler
~~~~~~~~
+- A new flag :ghc-flag:`-flink-rts` to enable linking the RTS when linking
+ shared libraries.
+
GHCi
~~~~
diff --git a/docs/users_guide/phases.rst b/docs/users_guide/phases.rst
index 5975962370..c7a17f6475 100644
--- a/docs/users_guide/phases.rst
+++ b/docs/users_guide/phases.rst
@@ -735,6 +735,8 @@ for example).
:type: dynamic
:category: linking
+ :implies: :ghc-flag:`-flink-rts`
+
Link all passed files into a static library suitable for linking.
To control the name, use the :ghc-flag:`-o ⟨file⟩` option
as usual. The default name is ``liba.a``.
@@ -826,6 +828,23 @@ for example).
libraries at runtime. See :ref:`finding-shared-libs` for a
description of each mode.
+.. ghc-flag:: -flink-rts
+ :shortdesc: Link the runtime when generating a shared or static library
+ :type: dynamic
+ :category: linking
+
+ When linking shared libraries (:ghc-flag:`-shared`) GHC does not
+ automatically link the RTS. This is to allow choosing the RTS flavour
+ (:ghc-flag:`-threaded`, :ghc-flag:`-eventlog`, etc) when linking an
+ executable.
+ However when the shared library is the intended product it is useful to be
+ able to reverse this default. See :ref:`shared-libraries-c-api` for an
+ usage example.
+
+ When linking a static library (:ghc-flag:`-staticlib`) GHC links the RTS
+ automatically, you can reverse this behaviour by reversing this flag:
+ ``-fno-link-rts``.
+
.. ghc-flag:: -main-is ⟨thing⟩
:shortdesc: Set main module and function
:type: dynamic
diff --git a/docs/users_guide/shared_libs.rst b/docs/users_guide/shared_libs.rst
index 7e525019ca..4c9ad621f7 100644
--- a/docs/users_guide/shared_libs.rst
+++ b/docs/users_guide/shared_libs.rst
@@ -92,6 +92,8 @@ files to use the extension ``.dyn_hi``. The other requirements are the
same as for C libraries and are described below, in particular the use
of the flags :ghc-flag:`-dynamic`, :ghc-flag:`-fPIC` and :ghc-flag:`-shared`.
+.. _shared-libraries-c-api:
+
Shared libraries that export a C API
------------------------------------
@@ -115,19 +117,24 @@ the :ghc-flag:`-dynamic`, :ghc-flag:`-fPIC` and :ghc-flag:`-shared` flags:
.. code-block:: none
- ghc --make -dynamic -shared -fPIC Foo.hs -o libfoo.so
+ ghc --make -dynamic -shared -fPIC -flink-rts Foo.hs -o libfoo.so
As before, the :ghc-flag:`-dynamic` flag specifies that this library links
-against the shared library versions of the ``rts`` and ``base`` package. The
-:ghc-flag:`-fPIC` flag is required for all code that will end up in a shared
-library. The :ghc-flag:`-shared` flag specifies to make a shared library rather
-than a program. To make this clearer we can break this down into separate
-compilation and link steps:
+against the shared library versions of the ``base`` package.
+:ghc-flag:`-flink-rts` additionally links against the shared library version of
+the ``rts`` package (linking against the ``rts`` package is not enabled by
+default when building shared libraries). You may also omit ``-flink-rts``
+and link the RTS library into your final executable.
+
+The :ghc-flag:`-fPIC` flag is required for all code that will end up in a
+shared library. The :ghc-flag:`-shared` flag specifies to make a shared library
+rather than a program. To make this clearer we can break this down into
+separate compilation and link steps:
.. code-block:: none
ghc -dynamic -fPIC -c Foo.hs
- ghc -dynamic -shared Foo.o -o libfoo.so
+ ghc -dynamic -shared -flink-rts Foo.o -o libfoo.so
In principle you can use :ghc-flag:`-shared` without :ghc-flag:`-dynamic` in the
link step. That means to statically link the runtime system and all of the base
diff --git a/testsuite/tests/dynlibs/Makefile b/testsuite/tests/dynlibs/Makefile
index 2a530a5aeb..19009605ea 100644
--- a/testsuite/tests/dynlibs/Makefile
+++ b/testsuite/tests/dynlibs/Makefile
@@ -14,7 +14,7 @@ T3807:
# libraries. This is done to allow the RTS flavour to be chosen later (i.e.
# when linking an executable).
# Hence we must explicitly linking with the RTS here.
- '$(TEST_HC)' $(filter-out -rtsopts,$(TEST_HC_OPTS)) -v0 --make -dynamic -fPIC -shared T3807Export.hs T3807-export.c -o T3807test.so -lHSrts-ghc`'$(TEST_HC)' $(TEST_HC_OPTS) --numeric-version`
+ '$(TEST_HC)' $(filter-out -rtsopts,$(TEST_HC_OPTS)) -v0 --make -dynamic -fPIC -shared T3807Export.hs T3807-export.c -o T3807test.so -flink-rts
'$(TEST_HC)' $(filter-out -rtsopts,$(TEST_HC_OPTS)) -no-auto-link-packages -no-hs-main T3807-load.c -o T3807-load -ldl
./T3807-load
@@ -61,3 +61,33 @@ T5373:
T13702:
'$(TEST_HC)' -v0 -dynamic -rdynamic -fPIC -pie T13702.hs
./T13702
+
+.PHONY: T18072
+T18072:
+ $(RM) -rf T18072/
+ mkdir T18072
+ '$(TEST_HC)' $(filter-out -rtsopts,$(TEST_HC_OPTS)) -v0 -outputdir T18072 \
+ -dynamic -fPIC -c T18072.hs
+ '$(TEST_HC)' $(filter-out -rtsopts,$(TEST_HC_OPTS)) -v0 -outputdir T18072 \
+ -dynamic -shared -flink-rts T18072/T18072.o -o T18072/T18072.so
+ ldd T18072/T18072.so | grep libHSrts >/dev/null
+
+.PHONY: T18072debug
+T18072debug:
+ $(RM) -rf T18072debug/
+ mkdir T18072debug
+ '$(TEST_HC)' $(filter-out -rtsopts,$(TEST_HC_OPTS)) -v0 -outputdir T18072debug \
+ -dynamic -fPIC -c T18072.hs
+ '$(TEST_HC)' $(filter-out -rtsopts,$(TEST_HC_OPTS)) -v0 -outputdir T18072debug \
+ -dynamic -shared -flink-rts -debug T18072debug/T18072.o -o T18072debug/T18072.so
+ ldd T18072debug/T18072.so | grep libHSrts | grep _debug >/dev/null
+
+.PHONY: T18072static
+T18072static:
+ $(RM) -rf T18072static/
+ mkdir T18072static
+ '$(TEST_HC)' $(filter-out -rtsopts,$(TEST_HC_OPTS)) -v0 -outputdir T18072static \
+ -c T18072.hs
+ '$(TEST_HC)' $(filter-out -rtsopts,$(TEST_HC_OPTS)) -v0 -outputdir T18072static \
+ -staticlib -fno-link-rts T18072static/T18072.o -o T18072static/T18072.a
+ ar t T18072static/T18072.a | grep RtsSymbols.o > /dev/null && exit 1 || exit 0
diff --git a/testsuite/tests/dynlibs/T18072.hs b/testsuite/tests/dynlibs/T18072.hs
new file mode 100644
index 0000000000..39a174f2ae
--- /dev/null
+++ b/testsuite/tests/dynlibs/T18072.hs
@@ -0,0 +1,10 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+module T18072 where
+
+import Foreign.C
+
+foo :: IO CInt
+foo = return 3
+
+foreign export ccall foo :: IO CInt
diff --git a/testsuite/tests/dynlibs/all.T b/testsuite/tests/dynlibs/all.T
index aaa7a62774..b7272d4bac 100644
--- a/testsuite/tests/dynlibs/all.T
+++ b/testsuite/tests/dynlibs/all.T
@@ -7,3 +7,12 @@ test('T5373', [req_shared_libs], makefile_test, [])
# It's not clear exactly what platforms we can expect this to succeed on.
test('T13702', unless(opsys('linux'), skip), makefile_test, [])
+
+# test that -shared and -flink-rts actually links the rts
+test('T18072', [req_shared_libs, unless(opsys('linux'), skip)], makefile_test, [])
+
+# test that -shared and -flink-rts respects alternative RTS flavours
+test('T18072debug', [extra_files(['T18072.hs']), req_shared_libs, unless(opsys('linux'), skip)], makefile_test, [])
+
+# check that -staticlib and -fno-link-rts results in an archive without the RTR libary
+test('T18072static', [extra_files(['T18072.hs']), unless(opsys('linux'), skip)], makefile_test, [])