Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weird GCC arguments being generated on Windows for includeDirs (cabal 2.4.1.0). #6080

Open
lambdaheart opened this issue Jun 16, 2019 · 5 comments

Comments

@lambdaheart
Copy link

So, I'm trying to get mysql package to build on windows and I'm nearly done, but I'm getting some weird behavior from Cabal.

It generates some unexpected GCC parameters:

Resolving dependencies...
Build profile: -w ghc-8.6.5 -O1
In order, the following will be built (use -v for more details):
 - mysql-0.1.7 (lib:mysql) (first run)
[1 of 1] Compiling Main             ( C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\setup\setup.hs, C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\setup\Main.o )
Linking C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\setup\setup.exe ...
Configuring mysql-0.1.7...
Preprocessing library for mysql-0.1.7..
In file included from C.hsc:73:0:
include/mysql_signals.h:9:10: fatal error: mysql.h: No such file or directory
 #include "mysql.h"
          ^~~~~~~~~
compilation terminated.

C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\Database\MySQL\Base\C_hsc_make.c failed (exit code 1)

command was:
  C:\Users\lh\Haskell\GHC\Versions\ghc-8.6.5\lib\../mingw/bin\gcc.exe
    -c C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\Database\MySQL\Base\C_hsc_make.c
    -o C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\Database\MySQL\Base\C_hsc_make.o
    -fno-stack-protector -D__GLASGOW_HASKELL__=806 -Dmingw32_BUILD_OS=1 -Dx86_64_BUILD_ARCH=1 -Dmingw32_HOST_OS=1 -Dx86_64_HOST_ARCH=1
    -I"C:\Program Files\MySQL\MySQL Server 8.0\include"
    -Iinclude
    -IC:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\"C:\Program Files\MySQL\MySQL Server 8.0\include"
    -IC:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\include
    -IC:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\autogen
    -IC:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\global-autogen
    -include C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\autogen\cabal_macros.h
    -IC:\Users\lh\Haskell\GHC\Versions\ghc-8.6.5\lib\bytestring-0.10.8.2\include
    -IC:\Users\lh\Haskell\GHC\Versions\ghc-8.6.5\lib\base-4.12.0.0\include
    -IC:\Users\lh\Haskell\GHC\Versions\ghc-8.6.5\lib\integer-gmp-1.0.2.0\include
    -IC:\Users\lh\Haskell\GHC\Versions\ghc-8.6.5\lib/include
    -IC:\Users\lh\Haskell\GHC\Link/lib/include/

Basically, in the includeDirs field for my BuildInfo I've added this (hardcoded for testing purposes):

["\"C:\\Program Files\\MySQL\\MySQL Server 8.0\\include\""]

In the generated gcc command I get the following expected flag:

-I"C:\Program Files\MySQL\MySQL Server 8.0\include"

But I also get this flag which has C:\Program Files\MySQL\MySQL Server 8.0\include tacked on to the end for some reason:

-IC:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\"C:\Program Files\MySQL\MySQL Server 8.0\include"

If I remove this flag and manually execute gcc command the program is built, but I can't figure out why this flag is generated and how to remove it.


Here is the full code of my current Setup.hs, mysql paths are set in mysqlBuildInfo function:

{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE CPP                   #-}
{-# LANGUAGE OverloadedStrings     #-}
{- OPTIONS_GHC -Wall #-}

#ifndef MIN_VERSION_Cabal
#define MIN_VERSION_Cabal(x,y,z) 0
#endif

import Control.Monad (liftM, msum, sequence)
import Data.Text ( Text, pack, unpack, splitOn, replace)
import qualified Data.Text as Text
import Data.List (isPrefixOf, nub)
import Distribution.PackageDescription
import Distribution.Simple
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Program
import Distribution.Verbosity

-- A Cabal 1.16 vs 1.18 compatibility hack, as in 1.18
-- findProgramLocation has a new (unused in this case) parameter.
-- ConstOrId adds this parameter when types say it is mandatory.
class ConstOrId a b where
    constOrId :: a -> b

instance ConstOrId a a where
    constOrId = id

instance ConstOrId a (b -> a) where
    constOrId = const


main :: IO ()
main = defaultMainWithHooks simpleUserHooks
  { hookedPrograms = [mysqlConfigProgram]
  , confHook = \pkg flags -> do
    lbi <- confHook simpleUserHooks pkg flags
    bi  <- mysqlBuildInfo lbi
    return lbi
      { localPkgDescr = updatePackageDescription (Just bi, []) (localPkgDescr lbi)
      }
  }

#if defined (mingw32_HOST_OS)

mysqlConfigProgram = simpleProgram "perl"

#else

mysqlConfigProgram = (simpleProgram "mysql_config") {
    programFindLocation = \verbosity -> constOrId $ liftM msum $ sequence
#if MIN_VERSION_Cabal(1,24,0)
      [ (findProgramOnSearchPath verbosity [ProgramSearchPathDefault] "mysql_config")
      , (findProgramOnSearchPath verbosity [ProgramSearchPathDefault] "mysql_config5")
      , (findProgramOnSearchPath verbosity [ProgramSearchPathDefault] "mariadb_config")
      ]
#else
      [ (findProgramLocation verbosity "mysql_config")
      , (findProgramLocation verbosity "mysql_config5")
      , (findProgramLocation verbosity "mariadb_config")
      ]
#endif
  }

#endif


mysqlBuildInfo :: LocalBuildInfo -> IO BuildInfo
mysqlBuildInfo lbi = do
#if MIN_VERSION_Cabal(2,0,0)
  let mysqlConfig = wordfix . getDbProgramOutput normal
                    mysqlConfigProgram (withPrograms lbi)
#else
  let mysqlConfig = wordfix . rawSystemProgramStdoutConf normal
                    mysqlConfigProgram (withPrograms lbi)
#endif

#if defined (mingw32_HOST_OS)
  let cfg = mysqlConfig . (\args -> ["-S", "mysql_config.pl"] <> args )
#else
  let cfg = mysqlConfig
#endif

  include <- cfg ["--include"]
  libs    <- cfg ["--libs"]
  libsR   <- cfg ["--libs_r"]

#if defined ( mingw32_HOST_OS)
  -- let include = ["-I\"C:\\Program Files\\MySQL\\MySQL Server 8.0\\include\""]
  -- let libs    = ["-L\"C:\\Program Files\\MySQL\\MySQL Server 8.0\\lib\\\"","ws2_32","crypt32","Secur32"]
  -- let libsR   = ["-L\"C:\\Program Files\\MySQL\\MySQL Server 8.0\\lib\\\"","ws2_32","crypt32","Secur32"]
#endif

  return emptyBuildInfo
    { extraLibDirs
      = map (drop 2)
      . filter ("-L" `isPrefixOf`)
      $ libs
    , extraLibs
      = map (drop 2) . filter ("-l" `isPrefixOf`)
      . filter (/= "-lmygcc")
      $ filter (/= "-lmysqlclient_r")
      $ nub (libs ++ libsR)
    , includeDirs
      = map (drop 2) include
    }

#if defined (mingw32_HOST_OS)
  where wordfix = fmap $ fmap fixword . filter (/="-lLIBMYSQL_OS_OUTPUT_NAME-NOTFOUND") . fmap unpack . splitOn "\" \"" . pack . reverse . dropWhile (=='"') . reverse . dropWhile (=='"') . takeWhile (/='\n')
#else
  where wordfix = fmap words
#endif


fixword :: String -> String
fixword path = unpack $ if lori txt then fixupPath txt else txt
  where txt = pack path

lori :: Text -> Bool
lori txt = ( "-L/c/" `Text.isPrefixOf` txt ) || ( "-I/c/" `Text.isPrefixOf` txt )

fixupPath :: Text -> Text
fixupPath pth = pfx <> pth'
  where pfx = Text.take 2 pth
        pth' = "\"C:\\" <> (replace "/" "\\" $ Text.drop 5 pth) <> "\""
@geekosaur
Copy link
Collaborator

geekosaur commented Jun 16, 2019

ghc on Windows expects things like mysql to come from mingw32, not Windows native. If you get past this, you'll have link errors because your mysql wants a native CRT, not the mingw32 one that it will be supplied.

And this problem is because in mingw-think, a path beginning with "C:\" is a relative pathname (it uses Unix-style paths, not Windows native).

@reygoch
Copy link

reygoch commented Jun 16, 2019

@geekosaur well, all other paths which were not provided by me use windows style path.

Also, if I remove that one flag and manually run the reported command then gcc can build this with no problem.

What I'm trying to say is that this looks like problem with generating the flags, and also I don't see mysql or mariadb dev package in msys.

Mysql_config script does return unix style path (which I've converted to win style) but problem is still the same, it appeares separately and than it is once more tacked onto this other path for some reason.

@Mistuke
Copy link
Collaborator

Mistuke commented Jun 16, 2019

ghc on Windows expects things like mysql to come from mingw32, not Windows native.

This is not entirely correct, GHC expects a native Windows library yes, but both mingw and mingw-w64 are just normal native libraries. The MySQL one should work fine as the CRT it requires would only be used by it. This would be no different from a normal C application compiled with GCC or MSVCRT which would likely have a different CRT than the MySQL anyway. This is why Windows applications allocate and de-allocate on the same side for instance.

And this problem is because in mingw-think, a path beginning with "C:" is a relative pathname (it uses Unix-style paths, not Windows native).

I suspect you mean msys(2) here and not mingw. Mingw uses only native Windows paths. Which is why using msys pkg-config returns unix paths and mingw pkg-config return Windows path. In any case, the MSYS2 runtime will always convert unix paths to Windows ones when it detects the callee is a native application. This is controlled by the MSYS_NO_PATHCONV variable and documented http://www.mingw.org/wiki/Posix_path_conversion

@reygoch you say you get the same issue when you just hardcode the path no? What happens when you have includeDirs = []?

I'm rather suspicious about the -Iinclude as well.

@lambdaheart
Copy link
Author

@Mistuke I'm @reygoch, accidentally switched accounts here. -Iinclude is refering to include folder local to the mysql project.

If I set includeDirs to [] then I simply don't get those two lines. What I'm not getting is, if search path is already set with:

-I"C:\Program Files\MySQL\MySQL Server 8.0\include"

Why do something else with it? This seems like a bug to me the more I look at it. This works fine if we assume we are only working with relative paths within the project, like it is the case with -Iinclude (local include folder), but not if we need to include something from a far away folder.

It seems like cabal is copying those include folders into dist-newstyle folder? Like we can see with this:

-IC:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\include

Here is also my output when I set includeDirs = []:

PS C:\Users\lh\Desktop\mysql> cabal new-build                                                       Resolving dependencies...
Build profile: -w ghc-8.6.5 -O1
In order, the following will be built (use -v for more details):
 - mysql-0.1.7 (lib:mysql) (first run)
[1 of 1] Compiling Main             ( C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\setup\setup.hs, C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\setup\Main.o )
Linking C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\setup\setup.exe ...
Configuring mysql-0.1.7...
Preprocessing library for mysql-0.1.7..
In file included from C.hsc:73:0:
include/mysql_signals.h:9:10: fatal error: mysql.h: No such file or directory
 #include "mysql.h"
          ^~~~~~~~~
compilation terminated.
compiling C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\Database\MySQL\Base\C_hsc_make.c failed (exit code 1)

command was:
  C:\Users\lh\Haskell\GHC\Versions\ghc-8.6.5\lib\../mingw/bin\gcc.exe
    -c C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\Database\MySQL\Base\C_hsc_make.c
    -o C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\Database\MySQL\Base\C_hsc_make.o
    -fno-stack-protector -D__GLASGOW_HASKELL__=806 -Dmingw32_BUILD_OS=1 -Dx86_64_BUILD_ARCH=1 -Dmingw32_HOST_OS=1 -Dx86_64_HOST_ARCH=1
    -Iinclude
    -IC:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\include
    -IC:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\autogen
    -IC:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\global-autogen
    -include C:\Users\lh\Desktop\mysql\dist-newstyle\build\x86_64-windows\ghc-8.6.5\mysql-0.1.7\build\autogen\cabal_macros.h
    -IC:\Users\lh\Haskell\GHC\Versions\ghc-8.6.5\lib\bytestring-0.10.8.2\include
    -IC:\Users\lh\Haskell\GHC\Versions\ghc-8.6.5\lib\base-4.12.0.0\include
    -IC:\Users\lh\Haskell\GHC\Versions\ghc-8.6.5\lib\integer-gmp-1.0.2.0\include
    -IC:\Users\lh\Haskell\GHC\Versions\ghc-8.6.5\lib/include
    -IC:\Users\lh\Haskell\GHC\Link/lib/include/

@Mistuke
Copy link
Collaborator

Mistuke commented Jun 16, 2019

Ahh right, so it seems cabal is expecting a relative path not an absolute one.. That does indeed seem like a bug.

Does the same happen if you have an absolute path set in a cabal file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants