18

Haskell 中的条件编译

 4 years ago
source link: https://mp.weixin.qq.com/s?__biz=MzU4OTQyODI0Mw%3D%3D&%3Bmid=2247484054&%3Bidx=1&%3Bsn=3ede8f70b14992c08764801d5a9bb9e6&%3Bchksm=fdcce1eacabb68fcb27c9962def9874894ac0b4abe1f41b4d3bdc54a6422e5510846095c91e7
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

背景

最近在用 Haskell 语言和 haskell-gi 包写一款 Haskell IDE ,这款软件初步支持简体中文和英文两种语言环境(中文简体语言环境展示中文简体,其他环境展示英文)。实现这种国际化的需求,有多种方法,比如,在 C/C++ 下可以使用 GNU gettext ,在Haskell下也有其移植。我采用了另一种方法:通过判断当前语言环境,决定要使用的语言版本,所以实现都是可以通过纯 Haskell 代码实现,多了一层类型安全的保证。

由于目前在Haskell中还没有好用的方法获取语言环境(glib中提供了 g_get_language_names 函数实际上可以达到目的,但比较难用),所以需要调用平台相关的函数,在 Windows 下使用 GetSystemDefaultLangID 。这需要根据不同的操作系统执行的不一样的代码,即根据不同的平台编译不同部分的代码,即 条件编译

Haskell中的条件编译支持

比较令人失望的是,在条件编译这块, Haskell 并没有自己出彩的地方,继续沿用了 C/C++ 那一套,即使用预处理指令判断预定义的宏达到编译不同部分代码的目的。在语法上,Haskell的预编译指令跟C/C++的完全一样,所以有了 C/C++ 的经验可以无缝迁移到 Haskell 上面。

下面是一些使用上的细节点:

Q1:怎么启用 Haskell 程序的预处理过程

我们知道,正常的 Haskell 程序处理过程是没有预处理的,我们需要一种方式明确告知构造过程要调用预处理器。这是通过 CPP 语言扩展实现的,这需要我们在源文件的顶层添加:

{-# LANGUAGE CPP #-}

Q2:Haskell提供了哪些标准宏

GHC (8.2.2)用户手册 7.11.3.1. Standard CPP macros 列了一些可用的宏可以用于代码,包括GHC软件版本、操作系统、硬件架构、软件包等方面的宏,下面仅摘录两个:

os_HOST_OS=1

This define allows conditional compilation based on the Operating System, where⟨os⟩ is the name of the current Operating System (eg. linux , mingw32 for Windows, solaris , etc.).

arch_HOST_ARCH=1

This define allows conditional compilation based on the host architecture, where⟨arch⟩ is the name of the current architecture (eg. i386 , x86_64 , powerpc , sparc , etc.).

除了这些预定义宏,你也可以在代码里像使用 C/C++ 一样,定义自己的宏。

Q3:怎将通过命令参数定义宏

一般的 C/C++ 编译器都允许通过编译器选项定义宏,而 GHC 也提供了类似的选项:

QFnQJff.jpg!web

最常用的是 -D 选项,这跟gcc编译器的用法完全一致,可以在编译时通过定义不同的宏控制编译过程。

示例

最后一个简单例子演示怎么使用条件编译。

{-# LANGUAGE CPP #-}


main :: IO ()

main =

#if defined linux_HOST_OS

putStrLn "Linux"

#elif defined mingw32_HOST_OS

putStrLn "Windows"

#else

putStrLn "Other"

#endif

有一点需要注意的是, Windows 下的宏定义 mingw32_HOST_OS 代表全部 Windows 系统,不要被其中的 32 迷惑,以为仅代表是 32 Windows 系统。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK