fpco / inline-c

284 stars 50 forks source link

Can't use function pointers in C++11 code #64

Closed stephenpascoe closed 6 years ago

stephenpascoe commented 6 years ago

I can't get inline-c-cpp to compile if I use the funCtx to try and call Haskell from C++. The problem seems to be I can't specify exactly when to use the "-std=c++11" switch in Cabal.

Below is a minimal file which exposes the problem. My system is:

src/Lib.hs

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ForeignFunctionInterface #-}
module Lib
    ( someFunc
    , someFunc2
    ) where

import qualified Language.C.Inline.Cpp as C
import Data.Monoid
import Foreign.C.Types (CDouble)

C.context $ C.cppCtx <> C.funCtx

C.include "<iostream>"

-- This snippet will only compile WITH "ghc-options: -optc-std=c++11"
-- Simulate including a header file with a C++ enum
C.verbatim "enum class MyEnum : char { OK = 0, FAIL = 1 };"

-- This function will only compile WITHOUT "ghc-options: -optc-std=c++11"
someFunc :: CDouble -> CDouble
someFunc x = let f x = x + (fromRational 42.0) in
  [C.pure| double { $fun:(double (*f)(double))($(double x)) } |]

-- This function compiles regardless of whether "ghc-options: -optc-std=c++11" is set
someFunc2 :: IO ()
someFunc2 = [C.block| void { std::cout << "Hello World!" << std::endl; } |]

package.yaml

library:
  source-dirs: src
  extra-libraries: stdc++
  ghc-options:   -optc-std=c++11

If I compile without -std=c++11 I get error: warning: scoped enumerations are a C++11 extension [-Wc++11-extensions] If I compile with -std=c++11 I get

Building library for inline-cpp-eg-0.1.0.0..
[2 of 2] Compiling Lib              ( src/Lib.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.1/build/Lib.o )
error: invalid argument '-std=c++11' not allowed with 'C/ObjC'
`gcc' failed in phase `C Compiler'. (Exit code: 1)

Strangely someFunc2 will compile in either case.

stephenpascoe commented 6 years ago

I realise -std=c++11 is needed to compile the enum class statement because enum classes are a C++11 feature. So the question really is why does -std=c++11 cause compiling to fail when we use the $fun anti-quoter in someFunc but not when we compile someFunc2?

stephenpascoe commented 6 years ago

After finding these related issues:

I tried building the source inside a docker container and it worked. The OSX compiler is more picky about what it allows.

stephenpascoe commented 6 years ago

I can work around this with the custom Setup.hs below. Unfortunately stack ghci doesn't work but once you've built it you can comment out ghc-options and run stack ghci successfully.

import Distribution.Simple
import Distribution.Simple.Setup
import Distribution.Types.HookedBuildInfo
import Distribution.PackageDescription
import Distribution.Simple.LocalBuildInfo
import Data.List (dropWhile)

main = defaultMainWithHooks simpleUserHooks { buildHook = myBuildHook
                                            }

BuildHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO ()
myBuildHook desc info hooks flags = (buildHook simpleUserHooks) (fixDescription desc) info hooks flags

-- Fix a PackageDescription to remove the -optc-std=c++11 option
fixDescription desc = desc { library = fmap fixLibrary (library desc) } where
  fixLibrary lib = lib { libBuildInfo = fixBuildInfo (libBuildInfo lib) }
  fixBuildInfo info = info { options = fixOptions (options info) }
  fixOptions options = fmap fixOption options
  fixOption (flavor, args) = (flavor, dropWhile ((==) "-optc-std=c++11") args)
domenkozar commented 5 years ago

It's going to be a bit easier in GHC 8.8: https://gitlab.haskell.org/ghc/ghc/issues/16477