Exemplo n.º 1
0
def generate(env):
    def _ghc_searchpath_opts(paths):
        if paths:
            return reduce(lambda list, path: " -i" + path, paths, "")
        else:
            return ""

    env["_ghc_searchpath_opts"] = _ghc_searchpath_opts

    def _ghc_package_opts(packages):
        return reduce(lambda list, package: list + " -package " + package,
                      packages, "")

    env["_ghc_package_opts"] = _ghc_package_opts

    env["HSC"] = "ghc"
    env["HSCFLAGS"] = []
    env["HSLINKFLAGS"] = []
    env["HSSEARCHPATH"] = []
    env["HSPACKAGES"] = []
    env["_HSPACKAGE_OPTS"] = "${_ghc_package_opts(HSPACKAGES)}"
    env["_HSSEARCHPATH_OPTS"] = "${_ghc_searchpath_opts(HSSEARCHPATH)}"

    ghc_scanner = Scanner(function=ghc_scanner_function,
                          skeys=[".hs", ".lhs"],
                          path_function=ghc_path_function)

    ghc_c_compiler = Builder(action="$HSC $HSCFLAGS -c -o $TARGET $SOURCE",
                             src_suffix=[".c"],
                             suffix=".o",
                             single_source=True)

    ghc_compiler = Builder(
        action="$HSC $HSCFLAGS $_HSSEARCHPATH_OPTS -c -o $TARGET $SOURCE",
        src_suffix=[".hs", ".lhs"],
        suffix=".o",
        single_source=True,
        emitter=ghc_emitter,
        source_scanner=ghc_scanner)

    ghc_linker = Builder(
        action="$HSC $HSLINKFLAGS $_HSPACKAGE_OPTS -o $TARGET $SOURCES",
        src_suffix=".o",
        suffix="$PROGSUFFIX",
        src_builder=[ghc_compiler, ghc_c_compiler])

    ghc_make = Builder(
        action="$HSC --make $HSCFLAGS $_HSSEARCHPATH_OPTS -o $TARGET $SOURCE",
        src_suffix=[".hs", ".lhs"],
        suffix="",
        single_source=True,
        emitter=ghc_make_emitter,
        source_scanner=ghc_scanner)

    env.Append(
        BUILDERS={
            "HaskellProgram": ghc_linker,
            "HaskellObject": ghc_compiler,
            "HaskellMake": ghc_make
        })
Exemplo n.º 2
0
    def __init__(self, action="yasha -o $TARGET $SOURCE"):
        def scan(node, env, path):
            src = str(node.srcnode())
            src_dir = os.path.dirname(src)
            variant_dir = os.path.dirname(str(node))

            cmd = action.replace('$SOURCE', src)
            cmd = ['-M'] + cmd.split()[1:]

            try:  # Remove $TARGET from action
                index = cmd.index('-o')
                del cmd[index]
                del cmd[index]
            except ValueError:
                pass

            runner = CliRunner()
            result = runner.invoke(cli.cli, cmd)

            deps = result.output[:-1].split(" ")[2:]
            deps = [d.replace(src_dir, variant_dir) for d in deps]

            return env.File(deps)

        def emit(target, source, env):
            env.Clean(target[0], str(target[0]) + ".d")
            return target, source

        from SCons.Scanner import Scanner
        from SCons.Action import Action
        BuilderBase.__init__(self,
                             action=Action(action),
                             emitter=emit,
                             source_scanner=Scanner(function=scan),
                             single_source=True)
Exemplo n.º 3
0
def add_custom_builders(env):
    """Call this to add all our custom builders to the environment."""
    from SCons.Scanner import Scanner
    from SCons.Builder import Builder
    from SCons.Action import Action

    # Add the file substitution tool
    TOOL_SUBST(env)

    # XXX: Put them into tools ?
    env['BUILDERS']['DistutilsSharedLibrary'] = DistutilsSharedLibrary
    env['BUILDERS']['NumpyCtypes'] = NumpyCtypes
    env['BUILDERS']['DistutilsPythonExtension'] = DistutilsPythonExtension
    env['BUILDERS']['NumpyPythonExtension'] = NumpyPythonExtension

    tpl_scanner = Scanner(function=generate_from_template_scanner,
                          skeys=['.src'])
    env['BUILDERS']['FromCTemplate'] = Builder(
        action=Action(generate_from_c_template, '$CTEMPLATECOMSTR'),
        emitter=generate_from_template_emitter,
        source_scanner=tpl_scanner)

    env['BUILDERS']['FromFTemplate'] = Builder(
        action=Action(generate_from_f_template, '$FTEMPLATECOMSTR'),
        emitter=generate_from_template_emitter,
        source_scanner=tpl_scanner)

    createStaticExtLibraryBuilder(env)
    env['BUILDERS']['DistutilsStaticExtLibrary'] = DistutilsStaticExtLibrary
    env['BUILDERS']['DistutilsInstalledStaticExtLibrary'] = \
            DistutilsInstalledStaticExtLibrary
Exemplo n.º 4
0
def generate(env):
    env["CYTHON"] = "cython"
    env["CYTHONCOM"] = "$CYTHON $CYTHONFLAGS -o $TARGET $SOURCE"
    env["CYTHONCFILESUFFIX"] = ".c"

    c_file, cxx_file = SCons.Tool.createCFileBuilders(env)

    c_file.suffix['.pyx'] = cython_suffix_emitter
    c_file.add_action('.pyx', cythonAction)

    c_file.suffix['.py'] = cython_suffix_emitter
    c_file.add_action('.py', cythonAction)

    create_builder(env)

    pyxscanner = Scanner(function=cython_scan, skeys=['.pyx'], name='PYX')
    env.Append(SCANNERS=[pyxscanner])
Exemplo n.º 5
0
def generate(env):
    """Add Builders and construction variables for swig to an Environment."""
    c_file, cxx_file = SCons.Tool.createCFileBuilders(env)

    c_file.suffix['.i'] = swigSuffixEmitter
    cxx_file.suffix['.i'] = swigSuffixEmitter

    c_file.add_action('.i', SwigAction)
    c_file.add_emitter('.i', _swigEmitter)
    cxx_file.add_action('.i', SwigAction)
    cxx_file.add_emitter('.i', _swigEmitter)

    env['SWIG'] = 'swig'
    env['SWIGFLAGS'] = SCons.Util.CLVar('')
    env['SWIGCFILESUFFIX'] = '_wrap$CFILESUFFIX'
    env['SWIGCXXFILESUFFIX'] = '_wrap$CXXFILESUFFIX'
    env['SWIGCOM'] = '$SWIG $SWIGFLAGS -o $TARGET $SOURCES'
    env.Append(SCANNERS=Scanner(function=_scanSwig, skeys=[".i"]))
Exemplo n.º 6
0
    def __init__(self, action="yasha $SOURCE -o $TARGET"):
        def scan(node, env, path):
            src = str(node.srcnode())
            src_dir = os.path.dirname(src)
            variant_dir = os.path.dirname(str(node))

            cli_command = [src, "-M"]
            extensions = re.search(r"(-e|--extensions)\s*(.+)", action)
            variables = re.search(r"(-v|--variables)\s*(.+)", action)

            if extensions:
                cli_command += ["-e", extensions.group(2)]
            if variables:
                cli_command += ["-v", extensions.group(2)]
            if re.match(r"--no-variables", action):
                cli_command += ["--no-variable-file"]
            if re.match(r"--no-extensions", action):
                cli_command += ["--no-extension-file"]

            runner = CliRunner()
            result = runner.invoke(cli.cli, cli_command)

            deps = result.output[:-1].split(" ")[2:]
            deps = [d.replace(src_dir, variant_dir) for d in deps]
            return env.File(deps)

        def emit(target, source, env):
            env.Clean(target[0], str(target[0]) + ".d")
            return target, source

        from SCons.Scanner import Scanner
        from SCons.Action import Action
        BuilderBase.__init__(self,
                             action=Action(action),
                             emitter=emit,
                             source_scanner=Scanner(function=scan),
                             single_source=True)
Exemplo n.º 7
0
def generate(env):
    env["HS"] = env.Detect("ghc") or "ghc"
    env["HSLINK"] = "$HS $_LIBS $SOURCES -o $TARGET"
    env["HSCOM"] = "$HS $_IMPORTS $_LIBS -c $SOURCE -o $TARGET"
    env["_IMPORTS"] = "${_concat(IMPORTSPREFIX, LIBPATH, IMPORTSSUFFIX, __env__)}"
    env["IMPORTSPREFIX"] = "-i"
    env["IMPORTSSUFFIX"] = ""
    env["_LIBS"] = "${_concat(LIBSPREFIX, LIBS, LIBSSUFFIX, __env__)}"
    env["LIBSPREFIX"] = "-package "
    env["LIBSSUFFIX"] = ""

    haskellSuffixes = [".hs", ".lhs"]

    compileAction = SCons.Action.Action("$HSCOM")

    linkAction = SCons.Action.Action("$HSLINK")

    def addHaskellInterface(target, source, env):
        """ Add the .hi target with the same name as the object file. """
        targetName = os.path.splitext(str(target[0]))[0]
        return (target + [targetName + ".hi"], source)

    def importedModules(node, env, path):
        """ Use ghc to find all the imported modules. """

        #print "Figuring out dependencies for " + str(node)
        def removeFile(fileName, errmsg=None):
            """ Try to remove fileName, returns true on success, false otherwise. """
            if os.path.exists(fileName):
                try:
                    os.remove(fileName)
                except OSError:
                    print "Unable to remove '%s'." % fileName
                    return False
            return True

        # Generate the name of the file that is going to contain the dependency mappings.
        fileName = os.path.join(os.path.dirname(str(node)),
                                "." + os.path.basename(str(node)) + ".dep")

        # Just in case the file already exist, to avoid the creation of a .bak file, delete it.
        if not removeFile(fileName):
            print "Dependencies will not be calculated."
            return []

        # Build the command to obtain the dependency mapping from ghc.
        command = ["ghc", "-M", "-optdep-f", "-optdep" + fileName]
        if env._dict.has_key("LIBPATH"):
            command += ["-i" + string.join(env["LIBPATH"], ":")]
        command += [str(node)]
        command = string.join(command)

        commandIn, commandOut = os.popen4(command, "r")
        errorMessage = commandOut.read()
        commandIn.close()
        commandOut.read()
        if (errorMessage != ""):
            print "An error ocurred running `%s`:" % command
            for line in string.split(errorMessage, "\n"):
                print ">" + line
            print "Dependencies will not be calculated."
            removeFile(fileName)
            return []

        try:
            file = open(fileName, "r")
            fileContents = file.read()
            file.close()
        except:
            print "Unable to open '%s'." % fileName
            print "Dependencies will not be calculated."
            removeFile(fileName)
            return []

        fileContents = string.split(fileContents, "\n")

        deps = []
        for line in fileContents:
            #print "deps=%s." % str(deps)
            if len(line) > 0 and line[0] != "#":
                files = string.split(line, ":")
                target = string.strip(files[0])
                source = string.strip(files[1])
                if source != str(
                        node):  # and os.path.splitext(source)[1] != ".hi":
                    deps += [os.path.basename(source)]
                #if os.path.splitext(target)[0] != os.path.splitext(str(node))[0]:
                #    deps += [os.path.basename(target)]
                #print "   %s depends on %s." % (target, source)

        removeFile(fileName)
        #print "%s depends on %s." % (str(node), str(deps))
        return deps

    haskellScanner = Scanner(function=importedModules,
                             name="HaskellScanner",
                             skeys=haskellSuffixes,
                             recursive=False)

    haskellProgram = SCons.Builder.Builder(action=linkAction,
                                           prefix="$PROGPREFIX",
                                           suffix="$PROGSUFFIX",
                                           src_suffix="$OBJSUFFIX",
                                           src_builder="HaskellObject")
    env["BUILDERS"]["HaskellProgram"] = haskellProgram

    haskellLibrary = SCons.Builder.Builder(action=SCons.Defaults.ArAction,
                                           prefix="$LIBPREFIX",
                                           suffix="$LIBSUFFIX",
                                           src_suffix="$OBJSUFFIX",
                                           src_builder="HaskellObject")
    env["BUILDERS"]["HaskellLibrary"] = haskellLibrary

    haskellObject = SCons.Builder.Builder(action=compileAction,
                                          emitter=addHaskellInterface,
                                          prefix="$OBJPREFIX",
                                          suffix="$OBJSUFFIX",
                                          src_suffix=haskellSuffixes,
                                          source_scanner=haskellScanner)
    env["BUILDERS"]["HaskellObject"] = haskellObject
Exemplo n.º 8
0
def generate(env):
    env.SetDefault(
        PYTHON=sys.executable,
        NODEJS='node',
        JS_ENGINE='$NODEJS',
        EMSCRIPTEN_FLAGS=['-v', '-j', '--suppressUsageWarning'],
        EMSCRIPTEN_TEMP_DIR=env.Dir('#/emscripten.tmp'),
        _expand_settings_flags=_expand_settings_flags,
        EMSCRIPTEN_PREJS=[],
        EMSCRIPTEN_POSTJS=[],
        EMSCRIPTEN_SETTINGS={},
        _EMSCRIPTEN_SETTINGS_FLAGS=
        '${_expand_settings_flags(EMSCRIPTEN_SETTINGS, __env__)}',
        JS_OPTIMIZER_PASSES=[],
        LLVM_OPT_PASSES=['-std-compile-opts', '-std-link-opts'],
        EMSCRIPTEN_HOME=env.Dir(os.path.join(os.path.dirname(__file__), '..')),
    )

    env.Replace(
        CC=os.path.join('${LLVM_ROOT}', '${CLANG}'),
        CXX=os.path.join('${LLVM_ROOT}', '${CLANGXX}'),
        AR=os.path.join('${LLVM_ROOT}', '${LLVM_LINK}'),
        ARCOM='$AR -o $TARGET $SOURCES',
        OBJSUFFIX='.bc',
        LIBPREFIX='',
        LIBSUFFIX='.bc',
        RANLIBCOM='',
        CCFLAGS=[
            '-U__STRICT_ANSI__', '-target', 'le32-unknown-nacl', '-nostdinc',
            '-Wno-#warnings', '-Wno-error=unused-variable', '-Werror', '-Os',
            '-fno-threadsafe-statics', '-fvisibility=hidden',
            '-fvisibility-inlines-hidden', '-Xclang', '-nostdinc++', '-Xclang',
            '-nobuiltininc', '-Xclang', '-nostdsysteminc', '-Xclang',
            '-isystem$EMSCRIPTEN_HOME/system/include', '-Xclang',
            '-isystem$EMSCRIPTEN_HOME/system/include/libc', '-Xclang',
            '-isystem$EMSCRIPTEN_HOME/system/include/libcxx', '-Xclang',
            '-isystem$EMSCRIPTEN_HOME/system/include/bsd', '-emit-llvm'
        ],
        CXXFLAGS=['-std=c++11', '-fno-exceptions'],
    )
    env.Append(CPPDEFINES=[
        'EMSCRIPTEN',
        '__EMSCRIPTEN__',
        '__STDC__',
        '__IEEE_LITTLE_ENDIAN',
    ])

    env.Append(CPPPATH=[
        env.Dir('${EMSCRIPTEN_HOME}/system/include'),
    ])

    env['BUILDERS']['Emscripten'] = Builder(
        action=
        '$PYTHON ${EMSCRIPTEN_HOME}/emscripten.py $EMSCRIPTEN_FLAGS $_EMSCRIPTEN_SETTINGS_FLAGS --temp-dir=$EMSCRIPTEN_TEMP_DIR --compiler $JS_ENGINE --relooper=third-party/relooper.js $SOURCE > $TARGET',
        target_scanner=EmscriptenScanner)

    env['BUILDERS']['JSOptimizer'] = Builder(
        action=
        '$JS_ENGINE ${EMSCRIPTEN_HOME}/tools/js-optimizer.js $SOURCE $JS_OPTIMIZER_PASSES > $TARGET',
        target_scanner=EmscriptenScanner)

    def depend_on_embedder(target, source, env):
        env.Depends(target, env['JS_EMBEDDER'])
        return target, source

    def embed_files_in_js(target, source, env, for_signature):
        return '$PYTHON $JS_EMBEDDER $SOURCE.srcpath > $TARGET'

    def get_files_in_tree(node, env, path):
        tree_paths = []
        for root, dirs, files in os.walk(str(node)):
            tree_paths += [os.path.join(root, f) for f in files]
        return [env.File(p) for p in tree_paths]

    env.SetDefault(JS_EMBEDDER=env.File('#/bin/embed_files_in_js.py'))

    FileTreeScanner = Scanner(function=get_files_in_tree,
                              name='FileTreeScanner',
                              recursive=False)

    env['BUILDERS']['EmbedFilesInJS'] = Builder(generator=embed_files_in_js,
                                                emitter=depend_on_embedder,
                                                source_scanner=FileTreeScanner)

    env.AddMethod(emscripten)

    def ConcatenateAction(target, source, env):
        [target] = target
        total = ''.join(file(str(s), 'rb').read() for s in source)
        file(str(target), 'wb').write(total)

    env['BUILDERS']['Concatenate'] = Builder(action=ConcatenateAction)

    libembind = build_libembind(env)
    libcxx = build_libcxx(env)

    # should embind be its own tool?
    env.Append(
        CPPPATH=['${EMSCRIPTEN_HOME}/system/include'],
        LIBPATH=['$EMSCRIPTEN_TEMP_DIR/internal_libs'],
        LIBS=[
            libembind,
            libcxx,
        ],
    )
Exemplo n.º 9
0
def get_emscripten_version_file(env):
    EMSCRIPTEN_HOME = env.Dir('$EMSCRIPTEN_HOME').abspath
    try:
        version_file = emscripten_version_files[EMSCRIPTEN_HOME]
    except KeyError:
        version_file = build_version_file(env)
        emscripten_version_files[EMSCRIPTEN_HOME] = version_file
    return version_file


def depend_on_emscripten(node, env, path):
    return [get_emscripten_version_file(env)]


EmscriptenScanner = Scanner(name='emscripten', function=depend_on_emscripten)


def setExtension(filename, extension):
    return os.path.splitext(filename)[0] + '.' + extension


def emscripten(env, target_js, source_bc):
    env = env.Clone()

    def buildName(extension):
        return setExtension(target_js, extension)

    # for debugging and reading generated code.
    # not in critical path, uses spare cores.
    env.LLVMDis(buildName('ll'), source_bc)
Exemplo n.º 10
0
def generate(env):
    env["ERLC"] = env.Detect("erlc") or "erlc"
    env["ERL"] = env.Detect("erl") or "erl"

    bugReport = '''
Please report this bug via the SCons Erlang tool project issue tracker on BitBucket ( cf. https://bitbucket.org/russel/scons_erlang)
or direct to Russel Winder <*****@*****.**>.'''

    def addTarget(target, source, env):
        """ Adds the targets (.beam, .script and/or .boot) according to source's extension, source's path and $OUTPUT. """

        # We should receive one and only one source.
        if len(source) > 1:
            print("Warning: unexpected internal situation.")
            print("This is a bug. {}".format(bugReport))
            print("addTarget received more than one source.")
            print("addTarget({}, {}, {})".format(source, target, env))

        sourceStr = str(source[0])

        # Tear appart the source.
        filename = os.path.basename(sourceStr)
        extension = os.path.splitext(filename)[1]
        basename = os.path.splitext(filename)[0]

        # Use $OUTPUT or where the source is as the prefix.
        prefix = outputDir(sourceStr, env)

        # Generate the targen according to the source.
        if extension == ".erl":
            # .erls generate a .beam.
            return ([prefix + basename + ".beam"], source)
        elif extension == ".rel":
            # .rels generate a .script and a .boot.
            return ([
                prefix + basename + ".script", prefix + basename + ".boot"
            ], source)
        else:
            print("Warning: extension '{}' is unknown.".format(extension))
            print(
                "If you feel this is a valid extension, then it might be a missing feature or a bug. {}"
                .format(bugReport))
            print("addTarget({}, {}, {}).".format(target, source, env))
            return (target, source)

    def erlangGenerator(source, target, env, for_signature):
        """ Generate the erlc compilation command line. """

        # We should receive one and only one source.
        if len(source) > 1:
            print("Warning: unexpected internal situation.")
            print("This is a bug. {}".format(bugReport))
            print("erlangGenerator received more than one source.")
            print("erlangGenerator({}, {}, {}, {})".format(
                source, target, env, for_signature))

        source = str(source[0])

        # Start with the complier.
        command = "$ERLC"

        # The output (-o) parameter
        command += " -o " + outputDir(source, env)

        # Add the libpaths.
        if env.has_key("ERLLIBPATH"):
            if not isinstance(env["ERLLIBPATH"], list):
                env["ERLLIBPATH"] = [env["ERLLIBPATH"]]
            for libpath in env["ERLLIBPATH"]:
                command += " -I " + libpath

        # At last, the source.
        return command + " " + source

    erlangBuilder = Builder(
        generator=erlangGenerator,
        #action = "$ERLC -o $OUTPUT $SOURCE",
        #suffix = [".beam", ".boot", ".script"],
        src_suffix=".erl",
        emitter=addTarget,
        single_source=True)
    env.Append(BUILDERS={"Erlang": erlangBuilder})
    env.Append(ENV={"HOME": os.environ["HOME"]})  # erlc needs $HOME.

    def outputDir(source, env):
        """ Given a source and its environment, return the output directory. """
        if env.has_key("OUTPUT"):
            return env["OUTPUT"]
        else:
            return dirOf(source)

    def libpath(env):
        """ Return a list of the libpath or an empty list. """
        if env.has_key("ERLLIBPATH"):
            if isinstance(env["ERLLIBPATH"], list):
                return env["ERLLIBPATH"]
            else:
                return [env["ERLLIBPATH"]]
        else:
            return []

    def dirOf(filename):
        """ Returns the relative directory of filename. """
        directory = os.path.dirname(filename)
        if directory == "":
            return "./"
        else:
            return directory + "/"

    def relModules(node, env, path):
        """ Return a list of modules needed by a release (.rel) file. """

        # Run the function reApplications of erlangscanner to get the applications.
        command = "erl -noshell -s erlangscanner relApplications \"" + str(
            node) + "\" -s init stop"
        sp = subprocess.Popen(command,
                              shell=True,
                              stdin=None,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
        sp.wait()
        if sp.returncode != 0:
            print(
                "Warning: The scanner failed to scan your files, dependencies won't be calculated."
            )
            print(
                "If your file '{}' is correctly (syntactically and semantically), this is a bug. {}"
                .format((node, bugReport)))
            print("Command: {}.".format(command))
            print("Return code: {}.".format(sp.returncode))
            print("Output: \n{}\n".format(sp.stdout.read().strip()))
            print("Error: \n{}\n".format(sp.stderr.read().strip()))
            return []

        # Get the applications defined in the .rel.
        appNames = sp.stdout.read().split()

        # Build the search path
        paths = set([outputDir(str(node), env)] + libpath(env))

        modules = []
        for path in paths:
            for appName in appNames:
                appFileName = path + appName + ".app"
                if os.access(appFileName, os.R_OK):
                    modules += appModules(appFileName, env, path)
        return modules

    def appModules(node, env, path):
        """ Return a list of modules needed by a application (.app) file. """

        # Run the function appModules of erlangscanner to get the modules.
        command = "erl -noshell -s erlangscanner appModules \"" + str(
            node) + "\" -s init stop"
        sp = subprocess.Popen(command,
                              shell=True,
                              stdin=None,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
        sp.wait()
        if sp.returncode != 0:
            print(
                "Warning: The scanner failed to scan your files, dependencies won't be calculated."
            )
            print(
                "If your file '{}' is correctly (syntactically and semantically), this is a bug. {}"
                .format(node, bugReport))
            print("Command: {}.".format(command))
            print("Return code: {}.".format(sp.returncode))
            print("Output: \n{}\n".format(sp.stdout.read().strip()))
            print("Error: \n{}\n".format(sp.stderr.read().strip()))
            return []

        # Get the applications defined in the .rel.
        moduleNames = sp.stdout.read().split()

        # Build the search path
        paths = set([outputDir(node, env)] + libpath(env))

        modules = []
        # When there are more than one application in a project, since we are scanning all paths against all files, we might end up with more dependencies that really exists. The worst is that we'll get recompilation of a file that didn't really needed it.
        for path in paths:
            for moduleName in moduleNames:
                modules.append(moduleName + ".beam")
        return modules

    relScanner = Scanner(function=relModules,
                         name="RelScanner",
                         skeys=[".rel"],
                         recursive=False)
    env.Append(SCANNERS=relScanner)

    def edocGenerator(source, target, env, for_signature):
        """ Generate the command line to generate the code. """
        tdir = os.path.dirname(str(target[0])) + "/"

        command = "erl -noshell -run edoc_run files '[%s]' '[{dir, \"%s\"}]' -run init stop" % (
            ",".join(['"' + str(x) + '"' for x in source]), tdir)

        return command

    def documentTargets(target, source, env):
        """ Artifitially create all targets that generating documentation will generate to clean them up latter. """
        tdir = os.path.dirname(str(target[0])) + "/"

        newTargets = [str(target[0])]
        # TODO: What happens if two different sources has the same name on different directories ?
        newTargets += [
            tdir + os.path.splitext(os.path.basename(filename))[0] + ".html"
            for filename in map(str, source)
        ]

        newTargets += [
            tdir + filename for filename in [
                "edoc-info", "modules-frame.html", "overview-summary.html",
                "overview-summary.html", "stylesheet.css",
                "packages-frame.html"
            ]
        ]

        #newSources = source + [tdir + "overview.edoc"]
        return (newTargets, source)

    def edocScanner(node, env, path):
        #print "edocScanner(%s, %s, %s)\n" % (node, env, path)
        overview = os.path.dirname(str(node)) + "/overview.edoc"
        if os.path.exists(overview):
            return ["overview.edoc"]
        else:
            return []

    edocBuilder = Builder(generator=edocGenerator,
                          emitter=documentTargets,
                          target_scanner=Scanner(function=edocScanner))
    env.Append(BUILDERS={"EDoc": edocBuilder})
Exemplo n.º 11
0
def generate(env):
    scan = Scanner(function=scan_dependencies, skeys=".js")
    env.Append(SCANNERS=scan)
    env.AddMethod(ConcatJS)
Exemplo n.º 12
0
            # right, platform-specific extension for "schemescanner". eg. ".exe"
            # on Windows.
            # cmd = '%s %s' % (env['schemescanner'] + env.get('EXESUFFIX', ""), str(node))
            cmd = '%s %s' % (env['schemescanner'], str(node))

            stringresults = exe(cmd)
            # print "RESULTS ", results
        results_split = re.split(' ', stringresults)
        for i in results_split:
            if i != '':
                filtered.append(i)
        # print "RESULTS SPLIT ", filtered
        return filtered


SchemeScanner = Scanner(function=schemefile_scan, skeys=['.scm', '.ss'])

mzc = Builder(action=Action('$MZCCOM', '$MZCCOMSTR'),
              src_suffix=".scm",
              single_source=True,
              source_scanner=SchemeScanner)


def generate(env, *kw):
    env['BUILDERS']['Mzc'] = mzc
    env['MZC'] = 'mzc'
    env['MZCCOM'] = '$MZC --exe $TARGET $SOURCE'


def exists(env):
    return 1
Exemplo n.º 13
0
def generate(env):
    bugReport = "Please report it to Pupeno <*****@*****.**> (http://pupeno.com/software/scons-erlang)."
    env["ERLC"] = env.Detect("erlc")
    env["ERL"] = env.Detect("erl")
    env["RUN_ERL"] = env.Detect("run_erl")
    env["ERL_CALL"] = env.Detect("erl_call")
    
    # The following might be useful, but it is actually needed before the environment is built, so, it is useless.
    # Find the Erlang root.
    #command = "erl -noshell -s erlangscanner erlang_dir -s init stop"
    #sp = subprocess.Popen(command,
    #                      shell = True,
    #                      stdin = None,
    #                      stdout = subprocess.PIPE,
    #                      stderr = subprocess.PIPE)
    #sp.wait()
    #if sp.returncode != 0:
    #    print("Warning: Failed to find Erlang's root directory, falling back to a default.")
    #    print("If you have a correct Erlang installation (and it seems likely if you reached this point) and you are not compiling SCons Erlang itself righ now, this is likely to be a bug. %s" % bugReport)
    #    print("Command: %s." % command)
    #    print("Return code: %s." % sp.returncode)
    #    print("Output: \n%s\n" % sp.stdout.read().strip())
    #    print("Error: \n%s\n" % sp.stderr.read().strip())
    #    env["ERLROOTDIR"] = "/usr/local/lib/erlang"
    #else:
    #    env["ERLROOTDIR"] = sp.stdout.read()
    #
    #env["ERLLIBDIR"] = "$ERLROOTDIR/lib"
    
    ##################################################
    ##### Erlang Builder methods and definitions #####

    def addTarget(target, source, env):
        """ When the source is a .erl file the target is a .beam file of the same base name and on the output directory according to the user preferences. When the source is a .rel file the targets are a .script and a .boot files with the same rules as for .erl files. For everything else just compalain.
            If the user chooses to set the output to false disabling automating handling of the output, this function will be useless.
            The goal of this function is to be used as emitter on the Erlang builder, it make SCons aware of what files to clean when cleaning. """
        
        # We should receive one and only one source.
        if len(source) > 1:
            print("Warning: unexpected internal situation.")
            print("This is a bug. %s" % bugReport)
            print("addTarget received more than one source.")
            print("addTarget(%s, %s, %s)" % (source, target, env))
        
        sourceStr = str(source[0])
        
        # Tear appart the source.
        filename = os.path.basename(sourceStr)
        extension = os.path.splitext(filename)[1]
        basename = os.path.splitext(filename)[0]
        
        # Get the directory where the output is going to end.
        output_dir = outputDir(sourceStr, env)
        
        # If the output_dir is False the user doesn't want us to do automatic handling of the output.
        if output_dir:
            # Generate the targen according to the source.
            if extension == ".erl":
                # .erls generate a .beam.
                return ([output_dir + basename + ".beam"], source)
            elif extension == ".rel":
                # .rels generate a .script and a .boot.
                return ([output_dir + basename + ".script", output_dir + basename + ".boot"], source) 
            else:
                print("Warning: extension '%s' is unknown." % extension)
                print("If you feel this is a valid extension, then it might be a missing feature or a bug. %s" % bugReport)
                print("addTarget(%s, %s, %s)." % (target, source, env))
                return (target, source)
        else:
            return (target, source)
    
    def erlangGenerator(source, target, env, for_signature):
        """ Generate the erlc compilation command line.
            The purpose of this function is to be used in the Erlang builder. """
        
        # We should receive one and only one source.
        if len(source) > 1:
            print("Warning: unexpected internal situation.")
            print("This is a bug. %s" % bugReport)
            print("erlangGenerator received more than one source.")
            print("erlangGenerator(%s, %s, %s, %s)" % (source, target, env, for_signature))
        
        # Get the source name as a string.
        source = str(source[0])
        
        # Do we have any path to prepend ?
        if env.has_key("PATHPREPEND"):
            if isinstance(env["PATHPREPEND"], str):
                path_prepend = [env["PATHPREPEND"]]
            else:
                path_prepend = env["PATH_PREPEND"]
        else:
            path_prepend = []

        # Do we have any path to append ?
        if env.has_key("PATHAPPEND"):
            if isinstance(env["PATHAPPEND"], str):
                path_append = [env["PATHAPPEND"]]
            else:
                path_append = env["PATHAPPEND"]
        else:
            path_append = []
        
        # Get the output directory to be used or False if no automatic output handling is going to be used.
        output_dir = outputDir(source, env)
        
        # Start with the complier.
        command = "$ERLC $ERLFLAGS"

        # Add the output statment if it's being used.
        if output_dir:
            command += " -o " + output_dir
            path_prepend.append(output_dir)
        
        # Path preppend.
        if path_prepend:
            arg = " -pa "
            command += arg + arg.join(path_prepend) + " "
        
        # Path append.
        if path_append:
            arg = " -pz "
            command += arg + arg.join(path_append) + " "
        
        # Add the libpaths.
        if env.has_key("LIBPATH"):
            if not isinstance(env["LIBPATH"], list):
                env["LIBPATH"] = [env["LIBPATH"]]
            for libpath in env["LIBPATH"]:
                command += " -I " + libpath
        
        # At last, the source.
        return command + " " + source
    
    erlangBuilder = Builder(generator = erlangGenerator,
                            #suffix = [".beam", ".boot", ".script"],
                            src_suffix = ".erl",
                            emitter = addTarget,
                            single_source = True)
    env.Append(BUILDERS = {"Erlang" : erlangBuilder})
    env.Append(ENV = {"HOME" : os.environ["HOME"]})  # erlc needs $HOME.

    ###############################################################
    ##### Erlang Release file scanner methods and definitions #####
    
    def erlangRelScanner(node, env, path):
        """ Erlang Release file scanner. Returns the list of modules needed by a .rel file to be compiled into the .script and .boot files. """

        # Get the name of the release file as a string.
        rel = str(node)

        # Build the search path for applications and modules.
        output_dir = outputDir(rel, env)
        if output_dir:
            paths = set([output_dir] + libpath(env))
        else:
            paths = set(libpath(env))

        # Find the applications needed by the release.
        apps = appNeededByRel(rel, paths)
        
        modules = []
        # Find the modules needed by each application.
        for app in apps:
            mods = modNeededByApp(app, paths)
            modules += mods
        return modules
    
    def appNeededByRel(rel, paths):
        """ Return a list of applications (.app files) needed by a release (.rel file). """
        
        # Run the function relApplications of erlangscanner to get the applications.
        command = "erl -noshell -s erlangscanner app_needed_by_rel \"%s\" -s init stop" % rel
        
        sp = subprocess.Popen(command,
                              shell = True,
                              stdin = None,
                              stdout = subprocess.PIPE,
                              stderr = subprocess.PIPE)
        sp.wait()
        if sp.returncode != 0:
            print("Warning: The scanner failed to scan your files, dependencies won't be calculated.")
            print("If your file '%s' is correctly (syntactically and semantically), this is a bug. %s" % (rel, bugReport))
            print("Command: %s." % command)
            print("Return code: %s." % sp.returncode)
            print("Output: \n%s\n" % sp.stdout.read().strip())
            print("Error: \n%s\n" % sp.stderr.read().strip())
            return []
        
        # Get the applications defined in the .rel.
        appNames = sp.stdout.read().split()
        
        modules = []
        for path in paths:
            for appName in appNames:
                appFileName = path + appName + ".app"
                if os.access(appFileName, os.R_OK):
                    modules.append(appFileName)
                    #modules += appModules(appFileName, env, path)
        return modules
    
    def modNeededByApp(app, paths):
        """ Return a list of modules (.beam files) needed by a application (.app file). """
        
        # Run the function appModules of erlangscanner to get the modules.
        command = "erl -noshell -s erlangscanner mod_needed_by_app \"%s\" -s init stop" % app
        
        sp = subprocess.Popen(command,
                              shell = True,
                              stdin = None,
                              stdout = subprocess.PIPE,
                              stderr = subprocess.PIPE)
        sp.wait()
        if sp.returncode != 0:
            print("Warning: The scanner failed to scan your files, dependencies won't be calculated.")
            print("If your file '%s' is correctly (syntactically and semantically), this is a bug. %s" % (app, bugReport))
            print("Command: %s." % command)
            print("Return code: %s." % sp.returncode)
            print("Output: \n%s\n" % sp.stdout.read().strip())
            print("Error: \n%s\n" % sp.stderr.read().strip())
            return []
        
        # Get the applications defined in the .rel.
        moduleNames = sp.stdout.read().split()
        
        modules = []
        # When there are more than one application in a project, since we are scanning all paths against all files, we might end up with more dependencies that really exists. The worst is that we'll get recompilation of a file that didn't really needed it.
        for path in paths:
            for moduleName in moduleNames:
                modules.append(os.path.abspath(path + moduleName +".beam"))
        return modules
    
    erlangRelScanner = Scanner(function = erlangRelScanner,
                               name = "ErlangRelScanner",
                               skeys = [".rel"],
                               recursive = False)
    env.Append(SCANNERS = erlangRelScanner)

    #######################################################
    ##### Erlang EDoc builder methods and definitions #####
    
    def edocFilesGenerator(source, target, env, for_signature):
        """ Generate the command line to generate the code. """
        
        options = []

        if env.has_key("DIR"):
            options.append(("dir", strInStr(env["DIR"])))
        else:
            # Automatic generation of dir based on the target.
            options.append(("dir", strInStr("doc/")))

        if env.has_key("DEF"):
            defs =  map(lambda (key, value): pyTupleToErlTulpe((key, strInStr(value))), env["DEF"])
            options.append(("def", "[" + ",".join(defs) + "]"))
        
        options = "[" + ",".join(map(pyTupleToErlTulpe, options)) + "]"

        command = "erl -noshell -run edoc_run files '[%s]' '%s'" % (",".join(['"' + str(x) + '"' for x in source]), options)
        
        return command
    
    def documentTargets(target, source, env):
        """ Artifitially create all targets that generating documentation will generate to clean them up latter. """

        # Find the output dir.
        if env.has_key("DIR"):
            dir = env["DIR"]
        else:
            dir = "doc/"
        
        # TODO: What happens if two different sources has the same name on different directories ?
        target = [dir + os.path.splitext(os.path.basename(filename))[0] + ".html"
                  for filename in map(str, source)]
        
        target += [dir + filename for filename in
                   ["edoc-info", "index.html", "modules-frame.html", "overview-summary.html", "stylesheet.css", "packages-frame.html"]]
        
        #newSources = source + [tdir + "overview.edoc"]
        return (target, source)
    
    def edocScanner(node, env, path):
        overview = os.path.dirname(str(node)) + "/overview.edoc"
        if os.path.exists(overview):
            return ["overview.edoc"]
        else:
            return []
    
    edocFilesBuilder = Builder(generator = edocFilesGenerator,
                               emitter = documentTargets,
                               target_scanner = Scanner(function=edocScanner))
    env.Append(BUILDERS = {"EDocFiles" : edocFilesBuilder})

    ################################################
    ##### EUnit runner methods and definitions #####

    ##########################
    ##### Helper Methods #####
    
    def outputDir(source, env):
        """ Given a source and its environment, return the output directory.
            The OUTPUTDIR environment variable will be checked first, if it is set to False this function returns False (the user wants us out of the way), otherwise the directory of the OUTPUTDIR will be used.
            If the variable is not set the output directory will be calculate from the source of the file, which is just the directory where the source is unless it ends in src/ in which case the ebin/ counterpart would be used. """

        if env.has_key("OUTPUTDIR"):
            if env["OUTPUTDIR"]:
                if env["OUTPUTDIR"][-1] != "/":
                    return env["OUTPUTDIR"] + "/"
                else:
                    return env["OUTPUTDIR"]
            else:
                False
        else:
            output = dirOf(source)
            if output[-4:] == "src/":
                return output[:-4] + "ebin/"
            else:
                return output
    
    def libpath(env):
        """ Return a list of the libpath or an empty list. """
        if env.has_key("LIBPATH"):
            if isinstance(env["LIBPATH"], list):
                return env["LIBPATH"]
            else:
                return [env["LIBPATH"]]
        else:
            return []
    
    def dirOf(filename):
        """ Returns the relative directory of filename. """
        directory = os.path.dirname(filename)
        if directory == "":
            return "./"
        else:
            return directory + "/"

    def strInStr(str):
        """ Put a string inside a string, that is, the string will contain leading and trailing double quotes so it is a string containing an Erlang string (otherwise it would be a string containing possible an atom, variable name or something just invalid). """
        return '"%s"' % str

    def pyTupleToErlTulpe(tpl):
        """ Turn a Python tuple into a string containing a valid Erlang tuple. """
        return "{" + ",".join(map(str, tpl)) + "}"
Exemplo n.º 14
0
    files = [m.replace('.', '/') + '.pxd' for m in matches]
    files += [m.replace('.', '/') + '.pyx' for m in matches]

    # cdef extern from <file>
    files += cdef_import_re.findall(contents)

    # Handle relative imports
    cur_dir = str(node.get_dir())
    files = [cur_dir + f if f.startswith('/') else f for f in files]

    # Filter out non-existing files (probably system imports)
    files = [f for f in files if env.File(f).exists()]
    return env.File(files)


pyxscanner = Scanner(function=pyx_scan, skeys=['.pyx', '.pxd'], recursive=True)
cythonAction = Action("$CYTHONCOM")


def create_builder(env):
    try:
        cython = env['BUILDERS']['Cython']
    except KeyError:
        cython = SCons.Builder.Builder(action=cythonAction,
                                       emitter={},
                                       suffix=cython_suffix_emitter,
                                       single_source=1)
        env.Append(SCANNERS=pyxscanner)
        env['BUILDERS']['Cython'] = cython
    return cython
Exemplo n.º 15
0
def generate(env, **kw):
    occbuild = kw.get('occbuild', None)
    if occbuild:
        occbuild_path = occbuild[0].abspath
        depend_emitter = lambda target, source, env: occbuild_depend_emitter(
            target, source, env, occbuild)
    else:
        occbuild_path = 'occbuild'
        depend_emitter = None
    pideps_scanner = Scanner(function=pideps_scan,
                             skeys=['.occ'],
                             path_function=FindPathDirs('INCPATH'))
    tce_bld = Builder(action=Action('$OCCBUILDCOM', '$OCCBUILDCOMSTR'),
                      emitter=depend_emitter,
                      suffix='.tce',
                      src_suffix='.occ')
    # FIXME: The source scanner does not work well enough yet :/
    #source_scanner = pideps_scanner)
    lib_bld = Builder(action=Action('$OCCBUILDLIBRARYCOM',
                                    '$OCCBUILDLIBRARYCOMSTR'),
                      emitter=[depend_emitter, occbuild_library_emitter],
                      suffix='.lib',
                      src_suffix='.tce',
                      src_builder=[tce_bld])
    prog_bld = Builder(
        action=Action('$OCCBUILDPROGRAMCOM', '$OCCBUILDPROGRAMCOMSTR'),
        emitter=[depend_emitter, occbuild_program_emitter],
        suffix='$PROGSUFFIX',
        src_suffix=['.occ', '.tce'],
        # FIXME: If I leave the sourcebuilder in, scons seems to
        # want to turn my .occ extensions when I have a mixed
        # .occ, .tce source list into .tce using the builder
    )  #src_builder = [tce_bld])
    tbc_headr_bld = Builder(action=Action('$TBCHEADERCOM', '$TBCHEADERCOMSTR'),
                            emitter=[depend_emitter],
                            suffix='.h',
                            src_suffix=['.occ', '.tce'],
                            src_bulider=[tce_bld])
    # Add the new Builder to the list of builders
    # Use of $( $)  causes bracketed flags not trigger rebuild when changed
    env['BUILDERS']['OccamObject'] = tce_bld
    env['OCCBUILDCOM'] = '$OCCBUILD $_OCCBUILD_TOOLCHAIN $_OCCBUILD_SEARCH_DIRS $OCCBUILDFLAGS --object $SOURCES'
    env['BUILDERS']['OccamLibrary'] = lib_bld
    env['OCCBUILDLIBRARYCOM'] = '$OCCBUILD $_OCCBUILD_TOOLCHAIN $_OCCBUILD_SEARCH_DIRS $OCCBUILDFLAGS --library $TARGET $SOURCES'
    env['BUILDERS']['OccamProgram'] = prog_bld
    env['OCCBUILDPROGRAMCOM'] = '$OCCBUILD $_OCCBUILD_TOOLCHAIN $_OCCBUILD_SEARCH_DIRS $OCCBUILDFLAGS --program $SOURCES'
    env['BUILDERS']['OccamBytecodeHeader'] = tbc_headr_bld
    env['TBCHEADERCOM'] = '$SKROC $_SKROC_SEARCH_DIRS $SKROCFLAGS --c -f $TARGET $SOURCES'
    env['OCCBUILD'] = occbuild_path
    env['_OCCBUILD_SEARCH_DIRS'] = '$( ${_concat(OCCBUILD_SEARCH_PFX, INCPATH, "", __env__, RDirs, TARGET, SOURCE)} $)'
    env['_SKROC_SEARCH_DIRS'] = '$( ${_concat(SKROC_SEARCH_PFX, INCPATH, "", __env__, RDirs, TARGET, SOURCE)} $)'
    env['OCCBUILD_SEARCH_PFX'] = '--search '
    env['SKROC_SEARCH_PFX'] = '-L '
    env['OCCBUILD_TOOLCHAIN'] = None
    env['_OCCBUILD_TOOLCHAIN'] = '${(OCCBUILD_TOOLCHAIN and "--toolchain $OCCBUILD_TOOLCHAIN" or "")}'

    def OccLibDepend(self, node, lib_name):
        if not isinstance(lib_name, list): list(lib_name)
        for lib in lib_name:
            self.Depends(node, self['OCCLIBS'][lib]['dep'])
            if 'inc' in self['OCCLIBS'][lib]:
                for n in node:
                    n.env.AppendUnique(INCPATH=self['OCCLIBS'][lib]['inc'])

    env.AddMethod(OccLibDepend)
    env['OCCLIBS'] = dict()
    env['INCPATH'] = CLVar('')
    env['OCCBUILDFLAGS'] = CLVar('')
Exemplo n.º 16
0
                accum = ''

    command = ['$OCAMLDEP', '$_OCAML_PATH', '$_OCAML_PP', str(node)]
    [command] = env.subst_list(command)
    deps = env.ReadPipe(command)
    deps = joinLines(deps)
    deps = imap(str.split, deps)
    deps = (fields[2:] for fields in deps if fields[0] == target)
    deps = chain(*deps)
    deps = imap(env.File, deps)
    return deps


__ocamldep_scanner = Scanner(
    function=__ocamldep_scan,
    name='ocamldep_scanner',
    node_class=File,
    skeys=['.mli', '.ml'],
)

########################################################################
#
#  Object file builder
#

__lex_action = Action([['$OCAMLLEX', '-o', '$TARGET', '$SOURCE']])

__lex_builder = Builder(
    src_suffix='.mll',
    single_source=True,
    action=__lex_action,
    suffix='.ml',
Exemplo n.º 17
0
        )
        if package is not None:
            result.append(package)
            continue
        # Check for a build result
        package = env.FindFile(
            package_name + os.path.extsep + env['GO_ARCHNAME'],
            subpaths,
        )
        if package is not None:
            result.append(package)
            continue
    return result


go_scanner = Scanner(function=_go_scan_func, skeys=['.go'])


def _gc_emitter(target, source, env):
    if env['GO_STRIPTESTS']:
        return (target, [s for s in source if not str(s).endswith('_test.go')])
    else:
        return (target, source)


def _ld_scan_func(node, env, path):
    obj_suffix = os.path.extsep + env['GO_ARCHNAME']
    result = []
    for child in node.children():
        if str(child).endswith(obj_suffix) or str(child).endswith('.a'):
            result.append(child)
Exemplo n.º 18
0
def generate(env):
    def depend_on_combiner(target, source, env):
        env.Depends(target, env['MODULE_COMBINE'])
        env.Depends(target, env['MODULE_SCAN'])

        return target, source

    def combine(target, source, env, for_signature):
        aliases = [
            "--alias %s=%s" % (key, value)
            for key, value in env['MODULE_ALIASES'].items()
        ]
        module_combine = os.path.relpath(
            env.subst('$MODULE_COMBINE'), env['MODULE_COMBINE'].cwd
            or os.getcwd())
        return '$NODEJS ' + module_combine + ' ' + ' '.join(
            aliases) + ' $SOURCE > $TARGET'

    path = os.path.join(os.path.relpath(os.path.dirname(__file__)), '..',
                        'bin', 'combine.js')
    env['MODULE_COMBINE'] = env.File(path)

    path = os.path.join(os.path.relpath(os.path.dirname(__file__)), '..',
                        'bin', 'scan-dependencies.js')
    env['MODULE_SCAN'] = env.File(path)
    env['MODULE_ALIASES'] = {}

    def scan_module_dependencies(node, env, path):
        # TODO: maybe we should pass the list of aliases and loaders to the tool rather than parsing the @ here
        import os
        module_scan = os.path.relpath(env.subst('$MODULE_SCAN'),
                                      env['MODULE_SCAN'].cwd or os.getcwd())
        cmd = [env.subst('$NODEJS'), module_scan, str(node)]
        popen = subprocess.Popen(cmd, stdout=subprocess.PIPE)
        stdout, _ = popen.communicate()
        if popen.returncode:
            raise AssertionError(
                'scan-dependencies failed with return code %r' %
                (popen.returncode, ))

        def resolveAlias(path):
            if path.startswith('@'):
                a = path[1:]
                try:
                    return env['MODULE_ALIASES'][a]
                except KeyError:
                    return None
            else:
                return path

        paths = filter(None, stdout.split('\n'))
        paths = [path.replace('\\', '/') for path in paths]
        paths = filter(lambda s: '!' not in s, paths)
        paths = filter(None, map(resolveAlias, paths))
        return map(env.File, paths)

    ModuleScanner = Scanner(function=scan_module_dependencies,
                            name='ModuleScanner',
                            recursive=False)
    CombinedModule = Builder(generator=combine,
                             emitter=depend_on_combiner,
                             source_scanner=ModuleScanner)
    env.Append(BUILDERS={'CombinedModule': CombinedModule})