使用Yesod和Darcs库时如何解决重复的符号错误?

时间:2012-11-01 22:23:10

标签: haskell yesod darcs

由于链接器问题,似乎无法将Yesod与Darcs库一起使用。我追踪了这个问题,并需要熟悉Darcs内部人员的提示来解决这个问题。

darcs library应用程序中使用Yesod时,出现以下错误:

GHCi runtime linker: fatal error: I found a duplicate definition for symbol
   sha256_init
whilst processing object file
   /home/sebfisch/.cabal/lib/darcs-2.9.5/ghc-7.4.2/libHSdarcs-2.9.5.a
This could be caused by:
   * Loading two different object files which export the same symbol
   * Specifying the same object file twice on the GHCi command line
   * An incorrect `package.conf' entry, causing some object to be
     loaded twice.
GHCi cannot safely continue in this situation.  Exiting now.  Sorry.

它似乎是由darcs和cryptohash库暴露相同的符号引起的,因为搜索相应的目标文件会显示:

# for file in `find ~/.cabal/lib/ -name "*.a"`; do (readelf -s $file | grep -i sha256_init) && (echo $file; echo); done
   293: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND sha256_init
    17: 0000000000000690    94 FUNC    GLOBAL DEFAULT    1 sha256_init
~/.cabal/lib/cryptohash-0.7.5/ghc-7.4.2/libHScryptohash-0.7.5.a

    10: 0000000000000290    45 FUNC    GLOBAL DEFAULT    1 sha256_init
~/.cabal/lib/darcs-2.8.2/ghc-7.4.2/libHSdarcs-2.8.2.a

我写了一个测试程序来确认darcs和cryptohash库存在冲突:

import           Crypt.SHA256          (sha256sum)
import           Crypto.Hash.SHA256    (hash)
import           Data.ByteString       (empty)
import qualified Data.ByteString.Char8 as BS

main :: IO ()
main = do
    BS.putStrLn $ hash empty    -- cryptohash
    putStrLn $ sha256sum empty  -- darcs

无法使用类似错误进行编译:

/home/sebfisch/.cabal/lib/cryptohash-0.7.5/ghc-7.4.2/libHScryptohash-0.7.5.a(sha256.o): In function `sha256_update': sha256.c:(.text+0x4b0): multiple definition of `sha256_update'
/home/sebfisch/.cabal/lib/darcs-2.8.2/ghc-7.4.2/libHSdarcs-2.8.2.a(sha2.o):sha2.c:(.text+0xf90): first defined here
/home/sebfisch/.cabal/lib/cryptohash-0.7.5/ghc-7.4.2/libHScryptohash-0.7.5.a(sha256.o): In function `sha224_update': sha256.c:(.text+0x640): multiple definition of `sha224_update'
/home/sebfisch/.cabal/lib/darcs-2.8.2/ghc-7.4.2/libHSdarcs-2.8.2.a(sha2.o):sha2.c:(.text+0xbb0): first defined here
/home/sebfisch/.cabal/lib/cryptohash-0.7.5/ghc-7.4.2/libHScryptohash-0.7.5.a(sha256.o): In function `sha256_init': sha256.c:(.text+0x690): multiple definition of `sha256_init'
/home/sebfisch/.cabal/lib/darcs-2.8.2/ghc-7.4.2/libHSdarcs-2.8.2.a(sha2.o):sha2.c (.text+0x290): first defined here
/home/sebfisch/.cabal/lib/cryptohash-0.7.5/ghc-7.4.2/libHScryptohash-0.7.5.a(sha256.o): In function `sha224_init': sha256.c:(.text+0x6f0): multiple definition of `sha224_init'
/home/sebfisch/.cabal/lib/darcs-2.8.2/ghc-7.4.2/libHSdarcs-2.8.2.a(sha2.o):sha2.c (.text+0x620): first defined here
collect2: ld returned 1 exit status

yesod-static需要cryptohash库,编写Yesod应用程序时无法轻易避免。如何在同一个应用程序中使用Yesod和Darcs(作为库)?

从一个库中删除重复的符号会有帮助吗?两个程序包都通过FFI访问散列函数,但使用不同的文件。

来自darcs/Crypt.SHA256

foreign import ccall unsafe "sha2.h sha256" c_sha256
    :: Ptr CChar -> CSize -> Ptr Word8 -> IO ()

来自cryptohash/Crypto.Hash.SHA256

foreign import ccall unsafe "sha256.h sha256_init"
    c_sha256_init :: Ptr Ctx -> IO ()

foreign import ccall "sha256.h sha256_update"
    c_sha256_update :: Ptr Ctx -> CString -> Word32 -> IO ()

foreign import ccall unsafe "sha256.h sha256_finalize"
    c_sha256_finalize :: Ptr Ctx -> CString -> IO ()

另一个想法是重写Darcs不使用自己的散列函数。如何重新实现Darcs的SHA256模块以使用cryptohash?我的测试程序的main函数中的两个语句没有给出相同的输出(通过注释掉另一个语句来测试),所以在Darcs中使用cryptohash似乎并不完全是直截了当的。

1 个答案:

答案 0 :(得分:4)

darcs hash输出只是cryptohash输出的base16编码版本。看起来base16-bytestring是弥合这一差距的一种方法。我试过了,Crypt.SHA256变得如此简单:

module Crypt.SHA256 ( sha256sum ) where

import Crypto.Hash.SHA256 ( hash )
import Data.ByteString ( ByteString )
import Data.ByteString.Base16 ( encode )
import Data.ByteString.Char8 ( unpack )

sha256sum :: ByteString -> String
sha256sum = unpack . encode . hash

实际上hashed-storage包还有一个sha2.c的副本,并通过重命名符号来解决问题。因此,对于darcs 2.8最简单的快速修复方法是从散列存储中复制sha2.hsha2.c,在两个文件中替换hashed_storage_darcs_,并更改src中的FFI导入/crypt/SHA256.hs在darcs中:

foreign import ccall unsafe "sha2.h darcs_sha256" c_sha256
    :: Ptr CChar -> CSize -> Ptr Word8 -> IO ()

如果能帮到你,我很乐意发布这个更改的darc 2.8.3。对于2.10,我将切换到如上所述使用cryptohash,因为我没有看到任何理由继续使用本地C版本,并且通常在darc中我们试图摆脱公共代码的私有实现。

编辑:我原本以为哈希存储会有同样的问题,但我错了(回想起来,很明显,如果没有重命名,它会与darc本身发生冲突)。