File: DirectCodegen.hs

package info (click to toggle)
ghc 9.0.2-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 177,780 kB
  • sloc: haskell: 494,441; ansic: 70,262; javascript: 9,423; sh: 8,537; python: 2,646; asm: 1,725; makefile: 1,333; xml: 196; cpp: 167; perl: 143; ruby: 84; lisp: 7
file content (113 lines) | stat: -rw-r--r-- 4,198 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
{-# LANGUAGE CPP #-}
module DirectCodegen where

{-
The standard mode for hsc2hs: generates a C file which is
compiled and run; the output of that program is the .hs file.
-}

import Data.Char                ( isAlphaNum, toUpper )
import Data.Foldable            ( foldl' )
import Control.Monad            ( when, forM_ )

import System.Exit              ( ExitCode(..), exitWith )
import System.FilePath          ( normalise )

import C
import Common
import Flags
import HSCParser
import UtilsCodegen

outputDirect :: Config -> FilePath -> FilePath -> FilePath -> String -> [Token] -> IO ()
outputDirect config outName outDir outBase name toks = do

    let beVerbose    = cVerbose config
        flags        = cFlags config
        enableCol    = cColumn config
        cProgName    = outDir++outBase++"_hsc_make.c"
        oProgName    = outDir++outBase++"_hsc_make.o"
        progName     = outDir++outBase++"_hsc_make"
#if defined(mingw32_HOST_OS) || defined(__CYGWIN32__)
-- This is a real hack, but the quoting mechanism used for calling the C preprocesseor
-- via GHC has changed a few times, so this seems to be the only way...  :-P * * *
                          ++ ".exe"
#endif
        outHFile     = outBase++"_hsc.h"
        outHName     = outDir++outHFile
        outCName     = outDir++outBase++"_hsc.c"

    let execProgName
            | null outDir = normalise ("./" ++ progName)
            | otherwise   = progName

    let specials = [(pos, key, arg) | Special pos key arg <- toks]

    let needsC = any (\(_, key, _) -> key == "def") specials
        needsH = needsC
        possiblyRemove = if cKeepFiles config
                         then flip const
                         else finallyRemove

    let includeGuard = map fixChar outHName
            where
            fixChar c | isAlphaNum c = toUpper c
                      | otherwise    = '_'

    when (cCrossSafe config) $
        forM_ specials (\ (SourcePos file line _,key,_) ->
            when (not $ key `elem` ["const","offset","size","alignment","peek","poke","ptr",
                                    "type","enum","error","warning","include","define","undef",
                                    "if","ifdef","ifndef", "elif","else","endif"]) $
             die (file ++ ":" ++ show line ++ " directive \"" ++ key ++ "\" is not safe for cross-compilation"))

    writeBinaryFile cProgName $
        outTemplateHeaderCProg (cTemplate config)++
        concatMap outFlagHeaderCProg flags++
        concatMap outHeaderCProg specials++
        "\nint main (void)\n{\n"++
        outHeaderHs flags (if needsH then Just outHName else Nothing) specials++
        outHsLine (SourcePos name 0 1)++
        fst (foldl' (outTokenHs enableCol) (id, (True, True)) toks) ""++
        "    return 0;\n}\n"

    when (cNoCompile config) $ exitWith ExitSuccess

    rawSystemL outDir outBase ("compiling " ++ cProgName) beVerbose
        (cCompiler config)
        (  ["-c"]
        ++ [cProgName]
        ++ ["-o", oProgName]
        ++ [f | CompFlag f <- flags]
        )
    possiblyRemove cProgName $
        withUtilsObject config outDir outBase $ \oUtilsName -> do

      rawSystemL outDir outBase ("linking " ++ oProgName) beVerbose
        (cLinker config)
        (  [oProgName, oUtilsName]
        ++ ["-o", progName]
        ++ [f | LinkFlag f <- flags]
        )
      possiblyRemove oProgName $ do

        rawSystemWithStdOutL outDir outBase ("running " ++ execProgName) beVerbose execProgName [] outName
        possiblyRemove progName $ do

          when needsH $ writeBinaryFile outHName $
            "#ifndef "++includeGuard++"\n" ++
            "#define "++includeGuard++"\n" ++
            "#include <HsFFI.h>\n" ++
            "#if __NHC__\n" ++
            "#undef HsChar\n" ++
            "#define HsChar int\n" ++
            "#endif\n" ++
            concatMap outFlagH flags++
            concatMap outTokenH specials++
            "#endif\n"

          when needsC $ writeBinaryFile outCName $
            "#include \""++outHFile++"\"\n"++
            concatMap outTokenC specials
            -- NB. outHFile not outHName; works better when processed
            -- by gcc or mkdependC.