Exemplo n.º 1
0
def _generate_swig_wrappers(interface_files, output_directory):
    """
    Generates SWIG Wrapper files (.cxx) and python modules that can be
    compiled into a shared library by distutils.

    :raises: ``EnvironmentError`` if swig is not installed.

    """

    if swig_path is None:
        raise EnvironmentError("No swig executable found.")

    output_directory = _utils.resolve_path(output_directory)

    for current_file in interface_files:
        module_name = _utils.file_name(current_file)
        output_file = os.path.join(
            output_directory, "%s_wrap.cxx" % (module_name, )
        )

        # Let swig generate the wrapper files.
        subprocess.check_call(
            [swig_path, "-c++", "-python", "-o", output_file, current_file],
            cwd = output_directory,
            stdout = _utils.DEVNULL,
            stderr = subprocess.STDOUT
        )
Exemplo n.º 2
0
def _generate_swig_interface(file_path, output_directory):
    """
    Generates a SWIG Interface file (.i) that can be compiled with SWIG to
    a shared library file that can be imported into python for testing.

    """

    file_path = _utils.resolve_path(file_path)
    output_directory = _utils.resolve_path(output_directory)

    # Figure out what this module will be named by getting just the filename
    # (minus extension) of the code file.
    module_name = _utils.file_name(file_path)

    # -MM flag returns all dependencies needed to compile file.
    gpp_process = subprocess.Popen(
        ["g++", "-MM", file_path],
        stdout = subprocess.PIPE,
        stderr = subprocess.STDOUT
    )
    gpp_output = gpp_process.communicate()[0]

    # Get dependencies, minus the .o file and the white space
    gpp_output = gpp_output.split(":")[1].strip()
    dependencies = [i.strip() for i in gpp_output.split(" ") if i.strip() != "\\"]

    necessary_includes = []
    for include in dependencies:
        necessary_includes.append("#include \"%s\"" % (include))

        # TODO: Add comment describing what's going on here.
        if ".h" in include:
            include = include.replace(".hpp", ".h")
            include = include.replace(".h", ".cpp")

            if file_path not in include and os.path.isfile(include):
                necessary_includes.append("#include \"%s\"" % (include))

    with open(os.path.join(output_directory, module_name + ".i"), "w") as f:
        f.write("%%module %s\n\n" % (module_name, ))

        # Ensure we include all of the special swig interface files that allow
        # us to interop with the C++ Standard Library.
        for interface in STD_INTERFACES:
            f.write("%%include \"%s\"\n" % (interface, ))

        # Write directives inside and out of wrapper for consistency in wrapped
        # file.
        f.write("\n".join(EXPOSURE_DIRECTIVES) + "\n")
        f.write("using namespace std;\n\n")
        f.write("%{\n")
        f.write("\n".join(EXPOSURE_DIRECTIVES) + "\n")
        for include in necessary_includes:
            f.write("%s\n" % include)
        f.write("%}\n\n")

        # SWIG cannot import global include like iostream, but it does need
        # all local includes
        local_includes = \
            (include for include in necessary_includes if '<' not in include)
        for include in local_includes:
            f.write("%s\n" % include.replace("#", "%"))

    return module_name