Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GHC: insert compilation date

Tags:

haskell

ghc

I thought there would already be a question about this, but I can't find one.

I want my program to print out the date it was compiled on. What's the easiest way to set that up?

I can think of several possibilities, but none of them are what you'd call "easy". Ideally I'd like to be able to just do ghc --make Foo and have Foo print out the compilation date each time I run it.

Various non-easy possibilities that spring to mind:

  • Learn Template Haskell. Figure out how to use Data.Time to fetch today's date. Find a way how to transform that into a string. (Now my program requires TH in order to work. I also need to convince it to recompile that module every time, otherwise I get the compilation date for that module [which never changes] rather than the whole program.)

  • Write a shell script that generates a tiny Haskell module containing the system date. (Now I have to use that shell script rather than compile my program directly. Also, shell scripting on Windows leaves much to be desired!)

  • Sit down and write some Haskell code which generates a tiny Haskell module containing the date. (More portable than previous idea - but still requires extra build steps or the date printed will be incorrect.)

  • There might be some way to do this through Cabal - but do I really want to package up this little program just to get a date facility?

Does anybody have any simpler suggestions?

like image 553
MathematicalOrchid Avatar asked Jul 22 '13 20:07

MathematicalOrchid


2 Answers

Using Template Haskell for this is relatively simple. You just need to:

  1. Run IO action within Template Haskell monad:

    runIO :: IO a -> Exp a
    
  2. Then create a string literal with:

    stringE :: String -> ExpQ
    
  3. Put a whole expression within a quasiquote.

    $( ... )
    

This program will print time of its compilation:

{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
import Data.Time

main = print $(stringE =<< runIO (show `fmap` Data.Time.getCurrentTime))

You may put the relevant fragment into a module that imports all other modules to make sure it is recompiled.

Or take current revision information from your versioning system. See: TemplateHaskell and IO

like image 51
Michal Gajda Avatar answered Jan 12 '23 02:01

Michal Gajda


The preprocessor helpfully defines __DATE__ and __TIME__ macros (just like in C), so this works:

{-# LANGUAGE CPP #-}
main = putStrLn (__DATE__ ++ " " ++ __TIME__)

This is probably simpler than Michal's suggestion of Template Haskell, but doesn't let you choose the format of the date.

like image 24
Nick Smallbone Avatar answered Jan 12 '23 03:01

Nick Smallbone