haskell / math-functions

Special mathematical functions
http://hackage.haskell.org/package/math-functions
BSD 2-Clause "Simplified" License
40 stars 28 forks source link

Linker errors when building with Windows GHC <8.0 #56

Closed RyanGlScott closed 5 years ago

RyanGlScott commented 5 years ago

I recently observed a build failure on Windows GHCs older than 8.0 on this CI build. Here is the relevant excerpt from a Windows GHC 7.10.3 build:

[22 of 46] Compiling Statistics.Types ( Statistics\Types.hs, dist\build\Statistics\Types.o )
ghc.exe: unable to load package `math-functions-0.3.2.0'
ghc.exe: C:\SR\ghc-7.10.3\math-functions-0.3.2.0-948a6b665e43ccbeeaf83d9263903789e679718c\lib\libHSmath-functions-0.3.2.0-948a6b665e43ccbeeaf83d9263903789e679718c.a: unknown symbol `expm1'
cabal.exe: Failed to build statistics-0.15.0.0 (which is required by
bench:bench from text-show-3.8.2).

This is likely due to an old GHC bug (https://gitlab.haskell.org/ghc/ghc/issues/11223) that was fixed in GHC 8.0.

This error goes away if I downgrade to math-functions-0.3.1.0. I also tried compiling math-functions-0.3.2.0 with -f-system-expm1, but that simply caused build failures:

$ cabal build -w C:\Users\RyanGlScott\Software\ghc-7.10.3\bin\ghc --constraint="math-functions -system-expm1"
Resolving dependencies...
Build profile: -w ghc-7.10.3 -O1
In order, the following will be built (use -v for more details):
 - math-functions-0.3.2.0 (lib) (requires build)
 - mwc-random-0.14.0.0 (lib) (requires build)
 - dense-linear-algebra-0.1.0.0 (lib) (requires build)
 - monad-par-0.3.4.8 (lib) (requires build)
 - statistics-0.15.0.0 (lib) (configuration changed)
Starting     math-functions-0.3.2.0 (lib)
Building     math-functions-0.3.2.0 (lib)

Failed to build math-functions-0.3.2.0.
Build log (
C:\Users\RyanGlScott\AppData\Roaming\cabal\logs\ghc-7.10.3\math-functions-0.3.2.0-f8cafa47f02921354906148e4d4f75cd423f7fe6.log
):
Preprocessing library for math-functions-0.3.2.0..
Building library for math-functions-0.3.2.0..
[ 1 of 11] Compiling Numeric.Sum      ( Numeric\Sum.hs, dist\build\Numeric\Sum.o )

Numeric\Sum.hs:56:1: Warning:
    The import of `Data.Monoid' is redundant
      except perhaps to import instances from `Data.Monoid'
    To import instances alone, use: import Data.Monoid()

Numeric\Sum.hs:63:1: Warning:
    The import of `Data.Vector.Generic.Mutable' is redundant
      except perhaps to import instances from `Data.Vector.Generic.Mutable'
    To import instances alone, use: import Data.Vector.Generic.Mutable()
[ 2 of 11] Compiling Numeric.Polynomial.Chebyshev ( Numeric\Polynomial\Chebyshev.hs, dist\build\Numeric\Polynomial\Chebyshev.o )
[ 3 of 11] Compiling Numeric.Polynomial ( Numeric\Polynomial.hs, dist\build\Numeric\Polynomial.o )
[ 4 of 11] Compiling Numeric.MathFunctions.Comparison ( Numeric\MathFunctions\Comparison.hs, dist\build\Numeric\MathFunctions\Comparison.o )
[ 5 of 11] Compiling Numeric.MathFunctions.Constants ( Numeric\MathFunctions\Constants.hs, dist\build\Numeric\MathFunctions\Constants.o )
[ 6 of 11] Compiling Numeric.RootFinding ( Numeric\RootFinding.hs, dist\build\Numeric\RootFinding.o )

Numeric\RootFinding.hs:43:1: Warning:
    The import of `Applicative'
    from module `Control.Applicative' is redundant

Numeric\RootFinding.hs:47:1: Warning:
    The import of `Data.Monoid' is redundant
      except perhaps to import instances from `Data.Monoid'
    To import instances alone, use: import Data.Monoid()

Numeric\RootFinding.hs:48:1: Warning:
    The import of `Data.Foldable' is redundant
      except perhaps to import instances from `Data.Foldable'
    To import instances alone, use: import Data.Foldable()

Numeric\RootFinding.hs:49:1: Warning:
    The import of `Data.Traversable' is redundant
      except perhaps to import instances from `Data.Traversable'
    To import instances alone, use: import Data.Traversable()
[ 7 of 11] Compiling Numeric.Series   ( Numeric\Series.hs, dist\build\Numeric\Series.o )
[ 8 of 11] Compiling Numeric.SpecFunctions.Compat ( Numeric\SpecFunctions\Compat.hs, dist\build\Numeric\SpecFunctions\Compat.o )

Numeric\SpecFunctions\Compat.hs:104:32: Not in scope: `sumSeries'

Numeric\SpecFunctions\Compat.hs:104:44: Not in scope: `liftA2'

Numeric\SpecFunctions\Compat.hs:104:56:
    Not in scope: `scanSequence'

Numeric\SpecFunctions\Compat.hs:105:60:
    Not in scope: `scanSequence'

Numeric\SpecFunctions\Compat.hs:105:80:
    Not in scope: `enumSequenceFrom'
Shimuuar commented 5 years ago

I just screwed up some CPP. I'll upload fix tomorrow. Thanks for the report!

Shimuuar commented 5 years ago

@RyanGlScott I think I fixed bug in current master. Could you check that it's indeed fixed? I don't have any windows box at hand

RyanGlScott commented 5 years ago

While bos/math-functions@84ea92943a7e5cff6681b5b0f032e64b76fafa4d does work around the issue, it's overly conservative in that it prevents any version of Windows from linking against the system expm1. The issue observed in https://github.com/bos/math-functions/issues/56#issue-490642288 (namely, GHC #11223) only occurs with Windows GHC 7.10.3 or earlier, so Windows GHC 8.0 and later can use the system expm1 just fine. I believe the conditional logic in the .cabal file should be closer to this:

diff --git a/math-functions.cabal b/math-functions.cabal
index 375a892..86f6c15 100644
--- a/math-functions.cabal
+++ b/math-functions.cabal
@@ -58,7 +58,7 @@ library
                       , vector              >= 0.7
                       , primitive
                       , vector-th-unbox     >= 0.2.1.6
-  if flag(system-expm1) && !os(windows)
+  if flag(system-expm1) && !(os(windows) && !impl(ghc >= 8.0))
     cpp-options: -DUSE_SYSTEM_EXPM1
   if flag(system-erf)   && !impl(ghcjs)
     cpp-options: -DUSE_SYSTEM_ERF

(For comparison, this is basically identical to how the log-domain library does things, as it has to work around the same issue.)

After applying this change, I can successfully build statistics-0.15.0.0 with both GHC 7.10.3 and 8.6.5, with or without the system-expm1 flag enabled in math-functions.

Shimuuar commented 5 years ago

With GHC>=8.0 math-functions just use GHC.Float.expm1 :: Floating a => a -> a unconditionally and flag value is ignored. In fact we have to juggle 3 implementations: one provided by GHC, one coming from C and pure haskell.

RyanGlScott commented 5 years ago

My apologies, I did not realize that USE_SYSTEM_EXPM1 was only used on GHC <8.0. In that case, my suggested conditional logic is unnecessary, so 84ea92943a7e5cff6681b5b0f032e64b76fafa4d looks good to me.

Shimuuar commented 5 years ago

0.3.2.1 with fix is on hackage