2013-10-30 8 views
69

Ich muss einige Informationen aus Kompilierungsskripten in Template Haskell kommunizieren. Momentan behalten die Kompilierungsskripte die Informationen in der Systemumgebung, also lese ich sie nur unter Verwendung von System.Environment.getEnvironment, eingepackt in runIO. Gibt es einen besseren Weg, zum Beispiel einige Argumente an ghc (ähnlich -D... für den C-Pre-Prozessor) zu übergeben, oder vielleicht etwas speziell für diesen Zweck in TH?Wie werden Informationen zur Kompilierung korrekt an die Template-Haskell-Funktionen übermittelt?

+9

Diese Informationen aus einer externen Datei lesen und [addDependentFile'] verwenden (http://hackage.haskell.org/package/template-haskell-2.8.0.0/docs/Language-Haskell-TH-Syntax. html # v: addDependentFile), um diese Datei zu 'ghc --make 'bekannt zu machen, ist eine offensichtliche Alternative. Was sind die Probleme, die Sie mit dem aktuellen System haben? –

+2

@MikhailGlushenkov Tatsächlich passiert die Umgebung nur die Wurzel des Projektverzeichnisses und dann werden mehr Informationen aus einer Datei gelesen. Also 'addDependentFile' wird für meinen Fall hilfreich sein. Das aktuelle Schema funktioniert, ich wollte nur wissen, ob es einen anderen, kanonischen Weg gibt, wie es geht. –

+5

Sie können auch die Funktion ['location'] (http://hackage.haskell.org/package/template-haskell-2.8.0.0/docs/Language-Haskell-TH-Syntax.html#v:location) verwenden Holen Sie den Stamm des Projektverzeichnisses (vorausgesetzt, Sie kennen den relativen Pfad vom aktuellen Modul zum Stamm). Hier ist [ein Beispiel] (https://gist.github.com/23Skidoo/6258379). –

Antwort

3

Es sieht so aus, als ob Sie versuchen, here, Die -D-Option in Ghc scheint eine Kompilierzeit Variable zu definieren.

Hier zum gleichen Thema ist eine question, die auch den anderen Teil Ihrer Frage zu beantworten scheint. Von dem, was ich sagen kann, bedingte Kompilierung zu tun, tun Sie so etwas wie:

#ifdef MACRO_NAME 
    //Do stuff here 
    #endif 
+1

Wie ich in den Kommentaren sagte, möchte ich nicht CPP und bedingte Kompilierung verwenden. Ich habe keinen Nutzen dafür, alles was ich will ist, Informationen an Template Haskell weiterzuleiten. Die "-D" -Option wäre nett, wenn es einen Weg geben würde, es in TH ohne CPP zu lesen. –

+1

Dies ist wiederum für die bedingte Kompilierung im * haskell * -Code.Ich weiß nichts anderes als das Definieren von Makros mit -D (vielleicht mit einem bestimmten Wert), und dann könnten Sie den Wert in Ihrem Haskell überprüfen und es könnte funktionieren. Ich weiß allerdings nicht genug über Haskell, um sicher zu sein. – jaked122

10

Da so viele Menschen in der Frage interessiert sind, werde ich meinen aktuellen Ansatz hinzufügen, vielleicht wird jemand es nützlich finden. Wahrscheinlich wäre der beste Weg, wenn TH -D Parameter auf der GHC-Befehlszeile lesen könnte, aber es scheint, als sei nichts dergleichen implementiert.

Ein einfaches Modul ermöglicht TH, Kompilierzeitumgebung zu lesen. Eine Hilfsfunktion ermöglicht auch das Lesen von Dateien; Lies beispielsweise den Pfad einer Konfigurationsdatei von der Umgebung und lies dann die Datei.

{-# LANGUAGE TemplateHaskell #-} 
module THEnv 
    (
    -- * Compile-time configuration 
     lookupCompileEnv 
    , lookupCompileEnvExp 
    , getCompileEnv 
    , getCompileEnvExp 
    , fileAsString 
    ) where 

import Control.Monad 
import qualified Data.Text as T 
import qualified Data.Text.IO as T 
import Language.Haskell.TH 
import Language.Haskell.TH.Syntax (Lift(..)) 
import System.Environment (getEnvironment) 

-- Functions that work with compile-time configuration 

-- | Looks up a compile-time environment variable. 
lookupCompileEnv :: String -> Q (Maybe String) 
lookupCompileEnv key = lookup key `liftM` runIO getEnvironment 

-- | Looks up a compile-time environment variable. The result is a TH 
-- expression of type @Maybe [email protected] 
lookupCompileEnvExp :: String -> Q Exp 
lookupCompileEnvExp = (`sigE` [t| Maybe String |]) . lift <=< lookupCompileEnv 
    -- We need to explicly type the result so that things like `print Nothing` 
    -- work. 

-- | Looks up an compile-time environment variable and fail, if it's not 
-- present. 
getCompileEnv :: String -> Q String 
getCompileEnv key = 
    lookupCompileEnv key >>= 
    maybe (fail $ "Environment variable " ++ key ++ " not defined") return 

-- | Looks up an compile-time environment variable and fail, if it's not 
-- present. The result is a TH expression of type @[email protected] 
getCompileEnvExp :: String -> Q Exp 
getCompileEnvExp = lift <=< getCompileEnv 

-- | Loads the content of a file as a string constant expression. 
-- The given path is relative to the source directory. 
fileAsString :: FilePath -> Q Exp 
fileAsString = do 
    -- addDependentFile path -- works only with template-haskell >= 2.7 
    stringE . T.unpack . T.strip <=< runIO . T.readFile 

Es kann wie folgt verwendet werden:

{-# LANGUAGE TemplateHaskell #-} 
import THEnv 
main = print $(lookupCompileEnvExp "DEBUG") 

Dann:

Nothing
  • runhaskell Main.hs druckt;
  • DEBUG="yes" runhaskell Main.hs druckt Just "yes".