2015-04-05 12 views
5

Sto seguendo Stephen Diehl's excellent LLVM Haskell tutorial su una macchina Linux Mint (Linux Mint 17 Qiana, GHC 7.8.4, llvm 3.4).JIT Haskell llvm-general: chiama al volo una funzione C. Il tutorial di Stephen Diehl

Ho clonato il repository github del progetto e sono riuscito a creare l'esempio di ogni capitolo utilizzando lo Makefile incluso.

Nel capitolo 4 tutorial ci presenta un compilatore JIT:

import qualified LLVM.General.ExecutionEngine as EE 

jit :: Context -> (EE.MCJIT -> IO a) -> IO a 
jit c = EE.withMCJIT c optlevel model ptrelim fastins 
    where 
    optlevel = Just 2 -- optimization level 
    model = Nothing -- code model (Default) 
    ptrelim = Nothing -- frame pointer elimination 
    fastins = Nothing -- fast instruction selection 

runJIT :: AST.Module -> IO (Either String()) 
runJIT mod = do 
    ... 
    jit context $ \executionEngine -> 
     ... 
     EE.withModuleInEngine executionEngine m $ \ee -> do 
      mainfn <- EE.getFunction ee (AST.Name "main") 
      case mainfn of 
      Just fn -> do 
       res <- run fn 
       putStrLn $ "Evaluated to: " ++ show res 
      Nothing -> return() 

Poi il tutorial estende il linguaggio per la scrittura di codice C per implementare le operazioni.

/* cbits 
$ gcc -fPIC -shared cbits.c -o cbits.so 
$ clang -fPIC -shared cbits.c -o cbits.so 
*/ 

#include "stdio.h" 

// putchard - putchar that takes a double and returns 0. 
double putchard(double X) { 
    putchar((char)X); 
    fflush(stdout); 
    return 0; 
} 

Il makefile costruisce il progetto eseguendo:

gcc -fPIC -shared src/chapter4/cbits.c -o src/chapter4/cbits.so 
ghc -no-user-package-db -package-db .cabal-sandbox/*-packages.conf.d src/chapter4/cbits.so --make src/chapter4/*.hs -o chapter4 

Ma quando provo a chiamare putchard() ottengo un errore:

LLVM ERROR: Program used external function 'putchard' which could not be resolved! 

mi manca qualcosa qui?

Ho visto persone che hanno un problema simile con la versione C++ originale del tutorial. Solitamente lo risolvono aggiungendo un comando flag al comando gcc (-rdynamic) che dovrebbe far sì che il linker aggiunga tutti i simboli, non solo quelli usati, alla tabella dei simboli dinamici. Sospetto che ghc stia strappando putchard() dal file eseguibile.

Quando seguo esattamente gli stessi passaggi su OS X I, tutto funziona correttamente e posso chiamare putchard() senza problemi.

Cosa sta succedendo?

Ho appena provato a eseguire il progetto su Centos 7 e ha funzionato. Deve esserci qualcosa di sbagliato nella mia macchina Mint.

+0

L'aggiunta di '' -optl -rdynamic'' all'invocazione di ghc risolve il problema? Puoi eseguire '' nm chapter4 | grep putchard'' e incollare l'output risultante nella domanda? –

+0

Stephen, avevo provato ad aggiungere '-optl -rdynamic' ma non funzionava. Sfortunatamente l'output di 'nm chapter4 | grep putchard' è nullo. Sembra che ghc stia ignorando 'cbits.so'. Su OS X l'eseguibile non verrà nemmeno eseguito se non trova 'cbits.so'. Su Linux non fa la differenza. Forse c'è un modo per collegarsi con ld invece di ghc? Qual è stata la tua configurazione quando hai scritto il tutorial? – esato1981

+0

Ho testato il codice su entrambi Ubuntu e Arch Linux. Le persone hanno riferito di eseguirlo su tutti i principali sistemi operativi. Forse c'era un bug del linker upstream in GHC che è un po 'troppo zelante nel rimuovere simboli che non appaiono nella fonte Haskell. Hai provato su 7.6 o 7.10? –

risposta

1

Forse GHC è un po 'troppo zelante durante il collegamento e lo spoglio del simbolo? È possibile aggiungere manualmente un riferimento utilizzando l'FFI in Main.hs e quindi ricompilare.

{-# LANGUAGE ForeignFunctionInterface #-} 

import Foreign.C.Types 

foreign import ccall safe "putchard" putchard 
    :: CDouble -> CDouble 
+0

Sarò dannato! Questa soluzione * ha funzionato * (aggiungendo manualmente un riferimento in "Main.hs".) Prima di provare ho provato a utilizzare GHC 7.6 e GHC 7.8. Ho provato un trucco per usare 'ld.gold' invece di' ld.ld', ma niente ha funzionato. – esato1981