如何从Haskell源文件访问Cabal/Setup.hs信息并获取构建目录路径?
把Cabal配置信息从自定义Setup.hs传递到Haskell源码的方法
我来分享几个实用的方案,帮你把Setup.hs里的Cabal级配置(比如configDistPref对应的构建目录路径)传递到你的Haskell源文件中:
方法1:自动生成配置模块(最可靠推荐)
这种方式是在Setup.hs的配置阶段生成一个包含所需信息的Haskell模块,然后在你的主代码里直接导入使用,稳定性最高。
步骤:
- 编写自定义
Setup.hs,在confHook中生成配置模块:
import Distribution.Simple import Distribution.Simple.Setup import System.IO main = defaultMainWithHooks simpleUserHooks { confHook = \args pkgDesc -> do -- 获取Cabal配置的dist路径 let distPref = configDistPref (configFlags args) -- 生成自动配置模块(路径可根据项目结构调整) writeFile "autogen/Config.hs" $ unlines [ "module Config where" , "" , "-- 从Cabal配置中获取的dist构建目录路径" , "distPath :: String" , "distPath = " ++ show distPref ] -- 执行默认的配置逻辑 confHook simpleUserHooks args pkgDesc }
- 在你的
.cabal文件中配置自动生成模块:
-- 告诉Cabal这是自动生成的模块,不需要手动维护 autogen-modules: Config -- 指定自动生成文件的存放目录 autogen-dir: autogen -- 确保构建时能找到这个模块 hs-source-dirs: src, autogen
- 在你的Haskell源码中导入使用:
import Config (distPath) import Language.Haskell.TH (runIO) -- 在TemplateHaskell中使用示例 exampleTH :: IO () exampleTH = runIO $ putStrLn $ "Dist路径是:" ++ distPath
方法2:通过环境变量传递
你可以在Setup.hs的构建阶段设置环境变量,然后在TemplateHaskell中读取这个变量,适合轻量场景。
步骤:
- 修改
Setup.hs的buildHook来设置环境变量:
import Distribution.Simple import Distribution.Simple.Setup import System.Environment main = defaultMainWithHooks simpleUserHooks { buildHook = \pkgDesc args buildFlags -> do let distPref = configDistPref (configFlags args) -- 设置环境变量 setEnv "CABAL_DIST_PATH" distPref -- 执行默认的构建逻辑 buildHook simpleUserHooks pkgDesc args buildFlags }
- 在你的源码中用TemplateHaskell读取环境变量:
import Language.Haskell.TH import System.Environment (getEnv) getDistPath :: Q Exp getDistPath = do distPath <- runIO $ getEnv "CABAL_DIST_PATH" lift distPath -- 使用示例 myDistPath :: String myDistPath = $(getDistPath)
注意:这种方法依赖于构建环境的环境变量传递,某些Cabal版本或构建模式下可能会有环境变量被重置的情况,稳定性不如第一种方法。
方法3:读取Cabal的setup-config文件(不推荐)
如果不想生成额外模块,你也可以在TemplateHaskell中直接读取Cabal生成的dist/setup-config文件,解析其中的distpref字段。不过这种方法需要自己编写配置解析逻辑,而且路径依赖可能不稳定,只适合临时调试场景。
内容的提问来源于stack exchange,提问作者nh2
相关产品推荐
相关产品推荐

