PageRenderTime 28ms CodeModel.GetById 1ms app.highlight 11ms RepoModel.GetById 14ms app.codeStats 0ms

/haskell_pupeno.py

https://bitbucket.org/russel/scons_haskell
Python | 149 lines | 118 code | 9 blank | 22 comment | 6 complexity | 7737d9fdbcf35d6e797382c1bf919818 MD5 | raw file
  1# -*- mode:python; coding:utf-8; -*-
  2
  3#  A SCons tool to enable compilation of Haskell in SCons.
  4#
  5# Copyright © 2005 José Pablo Ezequiel "Pupeno" Fernández Silva
  6# Copyright © 2009 Russel Winder
  7#
  8#  This program is free software: you can redistribute it and/or modify it under the terms of the GNU
  9#  General Public License as published by the Free Software Foundation, either version 3 of the License, or
 10#  (at your option) any later version.
 11#
 12#  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 13#  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 14#  License for more details.
 15#
 16#  You should have received a copy of the GNU General Public License along with this program.  If not, see
 17#  <http://www.gnu.org/licenses/>.
 18#
 19#  Original this code was licenced under GPLv2.  This fork is relicenced under GPLv3 as is permitted.
 20
 21import SCons.Tool
 22import SCons.Action
 23from SCons.Scanner import Scanner
 24from SCons.Defaults import ObjSourceScan, ArAction
 25import os.path
 26import string
 27
 28def generate(env):
 29    env["HS"] = env.Detect("ghc") or "ghc"
 30    env["HSLINK"] = "$HS $_LIBS $SOURCES -o $TARGET"
 31    env["HSCOM"] = "$HS $_IMPORTS $_LIBS -c $SOURCE -o $TARGET"
 32    env["_IMPORTS"] = "${_concat(IMPORTSPREFIX, LIBPATH, IMPORTSSUFFIX, __env__)}"
 33    env["IMPORTSPREFIX"] = "-i"
 34    env["IMPORTSSUFFIX"] = ""
 35    env["_LIBS"] = "${_concat(LIBSPREFIX, LIBS, LIBSSUFFIX, __env__)}"
 36    env["LIBSPREFIX"] = "-package "
 37    env["LIBSSUFFIX"] = ""
 38        
 39    haskellSuffixes = [".hs", ".lhs"]
 40        
 41    compileAction = SCons.Action.Action("$HSCOM")
 42
 43    linkAction = SCons.Action.Action("$HSLINK")
 44
 45    def addHaskellInterface(target, source, env):
 46        """ Add the .hi target with the same name as the object file. """
 47        targetName = os.path.splitext(str(target[0]))[0]
 48        return (target + [ targetName + ".hi"], source)
 49
 50    def importedModules(node, env, path):
 51        """ Use ghc to find all the imported modules. """
 52
 53        #print "Figuring out dependencies for " + str(node)
 54        def removeFile(fileName, errmsg = None):
 55            """ Try to remove fileName, returns true on success, false otherwise. """
 56            if os.path.exists(fileName):
 57                try:
 58                    os.remove(fileName)
 59                except OSError:
 60                    print "Unable to remove '%s'." % fileName
 61                    return False
 62            return True
 63
 64        # Generate the name of the file that is going to contain the dependency mappings.
 65        fileName = os.path.join(os.path.dirname(str(node)),
 66                                "." + os.path.basename(str(node)) + ".dep")
 67
 68        # Just in case the file already exist, to avoid the creation of a .bak file, delete it.
 69        if not removeFile(fileName):
 70            print "Dependencies will not be calculated."
 71            return []
 72
 73        # Build the command to obtain the dependency mapping from ghc.
 74        command = ["ghc", "-M", "-optdep-f", "-optdep" + fileName]
 75        if env._dict.has_key("LIBPATH"):
 76            command += ["-i" + string.join(env["LIBPATH"], ":")]
 77        command += [str(node)]
 78        command = string.join(command)
 79
 80        commandIn, commandOut = os.popen4(command, "r")
 81        errorMessage = commandOut.read()
 82        commandIn.close()
 83        commandOut.read()
 84        if(errorMessage != ""):
 85             print "An error ocurred running `%s`:" % command
 86             for line in string.split(errorMessage, "\n"):
 87                print ">" + line
 88             print "Dependencies will not be calculated."
 89             removeFile(fileName)
 90             return []
 91
 92        try:
 93            file = open(fileName, "r")
 94            fileContents = file.read()
 95            file.close()
 96        except:
 97            print "Unable to open '%s'." % fileName
 98            print "Dependencies will not be calculated."
 99            removeFile(fileName)
100            return []
101
102        fileContents = string.split(fileContents, "\n")
103
104        deps = []
105        for line in fileContents:
106            #print "deps=%s." % str(deps)
107            if len(line) > 0 and line[0] != "#":
108                files = string.split(line, ":")
109                target = string.strip(files[0])
110                source = string.strip(files[1])
111                if source != str(node): # and os.path.splitext(source)[1] != ".hi":
112                    deps += [os.path.basename(source)]
113                #if os.path.splitext(target)[0] != os.path.splitext(str(node))[0]:
114                #    deps += [os.path.basename(target)]
115                #print "   %s depends on %s." % (target, source)
116
117        removeFile(fileName)
118        #print "%s depends on %s." % (str(node), str(deps))
119        return deps
120
121    haskellScanner = Scanner(function = importedModules,
122                             name = "HaskellScanner",
123                             skeys = haskellSuffixes,
124                             recursive = False)
125
126    haskellProgram = SCons.Builder.Builder(action = linkAction,
127                                           prefix = "$PROGPREFIX",
128                                           suffix = "$PROGSUFFIX",
129                                           src_suffix = "$OBJSUFFIX",
130                                           src_builder = "HaskellObject")
131    env["BUILDERS"]["HaskellProgram"] = haskellProgram
132
133    haskellLibrary = SCons.Builder.Builder(action = SCons.Defaults.ArAction,
134                                           prefix = "$LIBPREFIX",
135                                           suffix = "$LIBSUFFIX",
136                                           src_suffix = "$OBJSUFFIX",
137                                           src_builder = "HaskellObject")
138    env["BUILDERS"]["HaskellLibrary"] = haskellLibrary
139
140    haskellObject = SCons.Builder.Builder(action = compileAction,
141                                          emitter = addHaskellInterface,
142                                          prefix = "$OBJPREFIX",
143                                          suffix = "$OBJSUFFIX",
144                                          src_suffix = haskellSuffixes,
145                                          source_scanner = haskellScanner)
146    env["BUILDERS"]["HaskellObject"] = haskellObject
147
148def exists(env):
149    return env.Detect(["ghc"])