-prof -fexternal-interpreter is inconsistent about loading C dependencies as static or dynamic libraries for template Haskell
Summary
As documented in the user guide it is possible to compile template
Haskell in profiling mode using only the profiling versions of dependencies
with -fexternal-interpreter
. In this case GHC is inconsistent about whether
it will load static or require dynamic versions of C library dependencies
depending on whether they are direct or indirect dependencies.
If a C library is an indirect dependency, i.e. defined in the extra-libraries
field of a package dependency, then GHC will look for the library in the search
paths defined in library-dirs
and will accept a static archive. If a C
library is a direct dependency instead, i.e. a corresponding -l
flag is
passed to GHC, then GHC will not accept a static archive and instead require a
shared object.
Steps to reproduce
I've attached a bash script that reproduces the issue with GHC 8.10.1 on Linux. The issue was also observed with GHC 8.8.3.
The script presents both cases, the indirect C library dependency and the
direct C library dependency. In either case the C library is called
libfoo.a
. And contains
int foo() { return 1; }
Indirect dependency
The script creates a package A that contains the module LibA
that defines
a template Haskell expression that uses a symbol provided by the C library.
{-# LANGUAGE TemplateHaskell #-}
module LibA where
import Language.Haskell.TH
foreign import ccall "foo" c_foo :: Int
value :: Q Exp
value = [| c_foo |]
It then compiles a binary in package B that depends on package A and uses
value
in a template Haskell splice. I.e. package B indirectly depends on
the C library.
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Language.Haskell.TH
import LibA
main :: IO ()
main = print $value
This example succeeds and uses the static C library libfoo.a
.
Direct dependency
In this case the same code as in the indirect dependency example is compiled in one go. I.e. the C library is a direct dependency. In this case compilation fails with the error.
<command line>: User-specified static library could not be loaded (clib/static/libfoo.a)
Loading static libraries is not supported in this configuration.
Try using a dynamic library instead.
The script contains commented out code that uses a dynamic library
libfoo.so
instead and succeeds.
Expected behavior
GHC should behave the same whether the C library is a direct or an indirect
dependency. Compilation of the provided example of a direct C library
dependency should succeed when using the static library libfoo.a
.
Additional context
The issue was discovered in rules_haskell. In that case build actions are sandboxed and only the required inputs are visible in the sandbox. That GHC is inconsistent about which version of a C library (static or dynamic) is required causes build errors when only one version of the library is provided in the sandbox.
Environment
- GHC version used: 8.10.1
Optional:
- Operating System: Ubuntu 19.10
- System Architecture: x86_64