由于链接器问题,似乎无法将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似乎并不完全简单。 最佳答案
darcs哈希输出只是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.h和sha2.c,在两个文件中都将
hashed_storage_
替换为darcs_
,然后将darcs中src/Crypt/SHA256.hs中的FFI导入更改为:foreign import ccall unsafe "sha2.h darcs_sha256" c_sha256
:: Ptr CChar -> CSize -> Ptr Word8 -> IO ()
如果此更改对您有所帮助,我很乐意发布darcs 2.8.3。对于2.10,我将如上所述切换到使用cryptohash,因为我看不到有任何理由继续使用本地C版本,并且通常在darcs中,我们正在尝试摆脱通用代码的私有(private)实现。
编辑:我原本以为散列存储将有同样的问题,但我错了(回想起来,很明显,如果不进行重命名,它将与darcs发生冲突)。