def _generate_shared_libraries(modules, wrapper_directory):
    """
    Compiles modules and wrappers to shared libraries using distutils.

    :raises: :class:`CouldNotCompile` if the extension could not be compiled.

    """

    wrapper_directory = _utils.resolve_path(wrapper_directory)

    for module in modules:
        so_name = "_%s" % (module, )
        wrapper_file = os.path.join(wrapper_directory, module + "_wrap.cxx")
        mod_ext = distutils.core.Extension(
            str(so_name), sources = [str(wrapper_file)]
        )

        try:
            captured = capture.capture_function(
                _build_extension, str(module), mod_ext, str(wrapper_directory)
            )
            captured.wait()
        except SystemExit:
            # Setup will call exit which can make the running script exit rather
            # suddenly. At least give the user an error with a traceback.
            raise CouldNotCompile(
                "Could not compile extension module.",
                stderr = captured.stderr.read()
            )
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
        )
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