2013-07-22 18 views
16

Myślałem, że już będzie pytanie na ten temat, ale nie mogę znaleźć.GHC: wstaw datę kompilacji

Chcę, aby mój program wydrukował datę, w której został skompilowany. Jak najłatwiej to ustawić?

Mogę wymyślić kilka możliwości, ale żadne z nich nie jest tak proste, jak to można nazwać "łatwym". Idealnie chciałbym móc po prostu zrobić ghc --make Foo i mieć Foo wydrukować datę kompilacji za każdym razem, gdy go uruchomię.

Różne non-Easy możliwości, które przychodzi na myśl:

  • Learn Template Haskell. Dowiedz się, jak użyć Data.Time, aby pobrać dzisiejszą datę. Znajdź sposób przekształcenia tego w ciąg znaków. (Teraz mój program wymaga TH do działania, muszę też przekonać go, aby za każdym razem przekompilować ten moduł, w przeciwnym razie otrzymam datę kompilacji dla tego modułu [który nigdy się nie zmienia] zamiast całego programu.)

  • Napisz skrypt powłoki, który generuje maleńki moduł Haskell zawierający datę systemową. (Teraz muszę użyć tego skryptu powłoki zamiast skompilować mój program bezpośrednio. Również, skrypty powłoki Windows pozostawia znacznie do życzenia!)

  • usiąść i napisać trochę kodu Haskell, który generuje mały moduł Haskell zawierającego data. (Bardziej przenośny niż poprzedni pomysł - ale nadal wymaga dodatkowych kroków konstrukcyjnych lub drukowana data będzie niepoprawna).

  • Może być jakiś sposób, aby to zrobić przez Cabal - ale czy naprawdę chcę spakować ten mały program po prostu uzyskać termin obiektu?

Czy ktoś ma jakieś prostsze sugestie?

+1

Alias ​​ghc na coś podobnego do '' ghc -DNOW = "\" 'date' \" "' '(nie mam pojęcia jak to by wyglądało na powłokę Windows), aw twoim module użyj' {- # LANGUAGE CPP # -} 'i' now = NOW' dla ciągu daty. Brzydki hack, może być na tyle brzydki, by popchnąć cię do czystszej alternatywy, która wymaga więcej pracy. –

+0

@DanielFischer Najwyraźniej powłoka systemu Windows nie ma możliwości ustawienia zmiennej z wyjścia polecenia. Zamiast tego musisz użyć hacka z 'SET/P VAR =', który odczytuje tekst ze standardowego wejścia. Jeśli wyprowadzasz dane wyjściowe polecenia do pliku, a następnie ponownie je z powrotem, możesz osiągnąć pożądany efekt ... ale JEZUS !! > _ < – MathematicalOrchid

+0

Och, wow. Czy nawet PowerShell nie ma takiej możliwości? –

Odpowiedz

26

Używanie szablonu Haskella jest stosunkowo proste. Wystarczy:

    działanie
  1. Run IO wewnątrz szablonu Haskell monady:

    runIO :: IO a -> Exp a 
    
  2. Następnie utworzyć ciąg dosłowne z:

    stringE :: String -> ExpQ 
    
  3. Put całą wyrażeń w quasiquote.

    $(...) 
    

Ten program wypisze czas jego kompilacji:

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

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

można umieścić odpowiedni fragment w module, który importuje wszystkie inne moduły, aby upewnić się, że jest rekompilacji.

Możesz też pobrać aktualne informacje o wersji ze swojego systemu wersjonowania.Zobacz: TemplateHaskell and IO

+1

Co za wspaniała pierwsza odpowiedź! Witamy w Stack Overflow! – AndrewC

+0

To wydaje się być tylko najczystszym rozwiązaniem. Łańcuch wersji jest używany w kilku różnych miejscach, dlatego ten kod został umieszczony w osobnym module. Jedyny problem, jaki przewiduję, polega na tym, że moduł wersji jest rekompilowany za każdym razem; może mógłbym użyć TH by "dotknąć" pliku źródłowego za każdym razem czy coś? – MathematicalOrchid

+0

MathematicalOrchid: Dlatego zasugerowałem, że ten moduł importuje wszystkie inne moduły toplevel. Lub można umieścić ten kod w module "głównym". Następnie jest zawsze rekompilowany. Inne rozwiązanie ma ten sam problem, a próba "dotyku" pliku źródłowego może wydawać się dla niektórych nieco bardziej uciążliwa. –

7

Preprocesor usłużnie definiuje __DATE__ i __TIME__ makr (podobnie jak w C), więc to działa:

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

To chyba prostsze niż sugestią Michała szablonu Haskell, ale nie pozwalają wybierz format daty.

+0

oczywiście, gdy już raz dostaniesz datę w programie jako literał, możesz łączyć ją w dowolny sposób. – muhmuhten

+0

Miałem nadzieję, że tak będzie - ale nie mogłem znaleźć żadnej wzmianki o tym w dokumentacji. Czy istnieje powód, dla którego pisanie '' __DATE __ "' nie działa, ale '__DATE__' na własną rękę działa? – MathematicalOrchid

+0

GHC po prostu wywołuje preprocesor C, dzięki czemu znajdziesz tam wstępnie zdefiniowane makra. Jedynymi użytecznymi są: __DATA__', '__TIME__',' __FILE__' (nazwa pliku źródłowego) i '__LINE__' (numer wiersza pliku źródłowego) - dwie ostatnie są przydatne do zdefiniowania makra błędu, które zawiera lokalizację źródłową. Co do tego, dlaczego '" __DATE __ "' nie działa, preprocesor nie rozwija makr wewnątrz literału łańcuchowego. Poza tym, '__DATE__' samo w sobie rozszerza się na literał łańcuchowy. –