<div dir="ltr">Breaking out the binding generation into a separate step will also be important for a couple reasons:<div><br></div><div>* (from before) I want to eliminate the requirement for the vast majority of the builds to have a swig on their system, and</div><div><br></div><div>* (not stated before) we'd like to move away from swig for binding generation at some point.</div><div><br></div><div>-Todd</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Nov 17, 2015 at 8:15 AM, Todd Fiala <span dir="ltr"><<a href="mailto:todd.fiala@gmail.com" target="_blank">todd.fiala@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Yes, I am planning on separating out the usage of the swig output from the massaging of that into the build.<div><br></div><div>Right now I'm just in phase 1, which is to clean up the existing process without modifying it, and adopting it on Xcode.</div><div><br></div><div>Humorously, with our recent removal of the searching for swig in the python scripts (which our OS X CI depends on, but since we weren't using the Python ones, I didn't detect), I ended breaking our CI.  I'm adding the searching back in.</div></div><div class="gmail_extra"><div><div class="h5"><br><div class="gmail_quote">On Tue, Nov 17, 2015 at 8:12 AM, Zachary Turner <span dir="ltr"><<a href="mailto:zturner@google.com" target="_blank">zturner@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Is there any way to have the step that runs the swig executable not be part of this script?  Seems like running swig should be a build step, and running these scripts on the output of swig should be a step that follows</div><br><div class="gmail_quote"><div dir="ltr">On Mon, Nov 16, 2015 at 11:20 PM Todd Fiala via lldb-commits <<a href="mailto:lldb-commits@lists.llvm.org" target="_blank">lldb-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: tfiala<br>
Date: Tue Nov 17 01:17:38 2015<br>
New Revision: 253317<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=253317&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=253317&view=rev</a><br>
Log:<br>
Add Pythonic language binding wrapper generation script.<br>
<br>
This is only used by Xcode at the moment.  It replaces the<br>
buildSwigWrapperClasses.py and related per-script-language<br>
scripts.  It also fixes a couple bugs in those w/r/t Xcode<br>
usage:<br>
<br>
* the presence of the GCC_PREPROCESSOR_DEFINITIONS env var<br>
  should not be short-circuiting generation of the language<br>
  binding; rather, only if LLDB_DISABLE_PYTHON is present<br>
  within that environment variable.<br>
<br>
* some logic around what to do when building in "non-Makefile"<br>
  mode.  I've switched the handling of that to be on a<br>
  "--framework" flag - if specified, we build an OS X-style<br>
  framework; otherwise, we go with non.<br>
<br>
Putting this up now only attached to the Xcode build so<br>
others can look at it but not be affected by it yet.<br>
After this, I'll tackle the finalizer, along with trying<br>
it locally on Linux.<br>
<br>
Added:<br>
    lldb/trunk/scripts/Python/prepare_binding_Python.py<br>
    lldb/trunk/scripts/prepare_bindings.py   (with props)<br>
Modified:<br>
    lldb/trunk/lldb.xcodeproj/project.pbxproj<br>
<br>
Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=253317&r1=253316&r2=253317&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=253317&r1=253316&r2=253317&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)<br>
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Tue Nov 17 01:17:38 2015<br>
@@ -5984,7 +5984,7 @@<br>
                        isa = PBXNativeTarget;<br>
                        buildConfigurationList = 2668020B115FD0EE008E1FE4 /* Build configuration list for PBXNativeTarget "LLDB" */;<br>
                        buildPhases = (<br>
-                               26DC6A5813380D4300FF7998 /* Build swig wrapper classes */,<br>
+                               26DC6A5813380D4300FF7998 /* Prepare Swig Bindings */,<br>
                                26680202115FD0ED008E1FE4 /* Headers */,<br>
                                26680203115FD0ED008E1FE4 /* Resources */,<br>
                                26680204115FD0ED008E1FE4 /* Sources */,<br>
@@ -6214,19 +6214,19 @@<br>
                        shellPath = /bin/sh;<br>
                        shellScript = "perl $SRCROOT/scripts/<a href="http://build-llvm.pl" rel="noreferrer" target="_blank">build-llvm.pl</a>";<br>
                };<br>
-               26DC6A5813380D4300FF7998 /* Build swig wrapper classes */ = {<br>
+               26DC6A5813380D4300FF7998 /* Prepare Swig Bindings */ = {<br>
                        isa = PBXShellScriptBuildPhase;<br>
                        buildActionMask = <a href="tel:2147483647" value="+12147483647" target="_blank">2147483647</a>;<br>
                        files = (<br>
                        );<br>
                        inputPaths = (<br>
                        );<br>
-                       name = "Build swig wrapper classes";<br>
+                       name = "Prepare Swig Bindings";<br>
                        outputPaths = (<br>
                        );<br>
                        runOnlyForDeploymentPostprocessing = 0;<br>
-                       shellPath = /bin/sh;<br>
-                       shellScript = "$SRCROOT/scripts/build-swig-wrapper-classes.sh $SRCROOT $TARGET_BUILD_DIR $CONFIGURATION_BUILD_DIR \"\"\n";<br>
+                       shellPath = /bin/bash;<br>
+                       shellScript = "/usr/bin/python $SRCROOT/scripts/prepare_bindings.py --framework --src-root $SRCROOT --target-dir $TARGET_BUILD_DIR --config-build-dir $CONFIGURATION_BUILD_DIR --swig-executable `which swig`";<br>
                };<br>
                4959511A1A1ACE9500F6F8FC /* Install Clang compiler headers */ = {<br>
                        isa = PBXShellScriptBuildPhase;<br>
<br>
Added: lldb/trunk/scripts/Python/prepare_binding_Python.py<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/prepare_binding_Python.py?rev=253317&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/prepare_binding_Python.py?rev=253317&view=auto</a><br>
==============================================================================<br>
--- lldb/trunk/scripts/Python/prepare_binding_Python.py (added)<br>
+++ lldb/trunk/scripts/Python/prepare_binding_Python.py Tue Nov 17 01:17:38 2015<br>
@@ -0,0 +1,435 @@<br>
+"""<br>
+                     The LLVM Compiler Infrastructure<br>
+<br>
+This file is distributed under the University of Illinois Open Source<br>
+License. See LICENSE.TXT for details.<br>
+<br>
+Python binding preparation script.<br>
+"""<br>
+<br>
+# Python modules:<br>
+from __future__ import print_function<br>
+<br>
+import logging<br>
+import os<br>
+import re<br>
+import shutil<br>
+import subprocess<br>
+import sys<br>
+<br>
+<br>
+class SwigSettings(object):<br>
+    """Provides a single object to represent swig files and settings."""<br>
+    def __init__(self):<br>
+        self.extensions_file = None<br>
+        self.header_files = None<br>
+        self.input_file = None<br>
+        self.interface_files = None<br>
+        self.output_file = None<br>
+        self.safecast_file = None<br>
+        self.typemaps_file = None<br>
+        self.wrapper_file = None<br>
+<br>
+    @classmethod<br>
+    def _any_files_newer(cls, files, check_mtime):<br>
+        """Returns if any of the given files has a newer modified time.<br>
+<br>
+        @param cls the class<br>
+        @param files a list of zero or more file paths to check<br>
+        @param check_mtime the modification time to use as a reference.<br>
+<br>
+        @return True if any file's modified time is newer than check_mtime.<br>
+        """<br>
+        for path in files:<br>
+            path_mtime = os.path.getmtime(path)<br>
+            if path_mtime > check_mtime:<br>
+                # This path was modified more recently than the<br>
+                # check_mtime.<br>
+                return True<br>
+        # If we made it here, nothing was newer than the check_mtime<br>
+        return False<br>
+<br>
+    @classmethod<br>
+    def _file_newer(cls, path, check_mtime):<br>
+        """Tests how recently a file has been modified.<br>
+<br>
+        @param cls the class<br>
+        @param path a file path to check<br>
+        @param check_mtime the modification time to use as a reference.<br>
+<br>
+        @return True if the file's modified time is newer than check_mtime.<br>
+        """<br>
+        path_mtime = os.path.getmtime(path)<br>
+        return path_mtime > check_mtime<br>
+<br>
+    def output_out_of_date(self):<br>
+        """Returns whether the output file is out of date.<br>
+<br>
+        Compares output file time to all the input files.<br>
+<br>
+        @return True if any of the input files are newer than<br>
+        the output file, or if the output file doesn't exist;<br>
+        False otherwise.<br>
+        """<br>
+        if not os.path.exists(self.output_file):<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("will generate, missing binding output file")<br>
+            return True<br>
+        output_mtime = os.path.getmtime(self.output_file)<br>
+        if self._any_files_newer(self.header_files, output_mtime):<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("will generate, header files newer")<br>
+            return True<br>
+        if self._any_files_newer(self.interface_files, output_mtime):<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("will generate, interface files newer")<br>
+            return True<br>
+        if self._file_newer(self.input_file, output_mtime):<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("will generate, swig input file newer")<br>
+            return True<br>
+        if self._file_newer(self.extensions_file, output_mtime):<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("will generate, swig extensions file newer")<br>
+            return True<br>
+        if self._file_newer(self.wrapper_file, output_mtime):<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("will generate, swig wrapper file newer")<br>
+            return True<br>
+        if self._file_newer(self.typemaps_file, output_mtime):<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("will generate, swig typemaps file newer")<br>
+            return True<br>
+        if self._file_newer(self.safecast_file, output_mtime):<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("will generate, swig safecast file newer")<br>
+            return True<br>
+<br>
+        # If we made it here, nothing is newer than the output file.<br>
+        # Thus, the output file is not out of date.<br>
+        return False<br>
+<br>
+<br>
+def get_header_files(options):<br>
+    """Returns a list of paths to C++ header files for the LLDB API.<br>
+<br>
+    These are the files that define the C++ API that will be wrapped by Python.<br>
+<br>
+    @param options the dictionary of options parsed from the command line.<br>
+<br>
+    @return a list of full paths to the include files used to define the public<br>
+    LLDB C++ API.<br>
+    """<br>
+<br>
+    header_file_paths = []<br>
+    header_base_dir = os.path.join(options.src_root, "include", "lldb")<br>
+<br>
+    # Specify the include files in include/lldb that are not easy to<br>
+    # grab programatically.<br>
+    for header in [<br>
+            "lldb-defines.h",<br>
+            "lldb-enumerations.h",<br>
+            "lldb-forward.h",<br>
+            "lldb-types.h"]:<br>
+        header_file_paths.append(os.path.normcase(<br>
+            os.path.join(header_base_dir, header)))<br>
+<br>
+    # Include the main LLDB.h file.<br>
+    api_dir = os.path.join(header_base_dir, "API")<br>
+    header_file_paths.append(os.path.normcase(<br>
+        os.path.join(api_dir, "LLDB.h")))<br>
+<br>
+    filename_regex = re.compile(r"^SB.+\.h$")<br>
+<br>
+    # Include all the SB*.h files in the API dir.<br>
+    for filename in os.listdir(api_dir):<br>
+        if filename_regex.match(filename):<br>
+            header_file_paths.append(<br>
+                os.path.normcase(os.path.join(api_dir, filename)))<br>
+<br>
+    logging.debug("found public API header file paths: %s", header_file_paths)<br>
+    return header_file_paths<br>
+<br>
+<br>
+def get_interface_files(options):<br>
+    """Returns a list of interface files used as input to swig.<br>
+<br>
+    @param options the options dictionary parsed from the command line args.<br>
+<br>
+    @return a list of full paths to the interface (.i) files used to describe<br>
+    the public API language binding.<br>
+    """<br>
+    interface_file_paths = []<br>
+    interface_dir = os.path.join(options.src_root, "scripts", "interface")<br>
+<br>
+    for filepath in [f for f in os.listdir(interface_dir)<br>
+                     if os.path.splitext(f)[1] == ".i"]:<br>
+        interface_file_paths.append(<br>
+            os.path.normcase(os.path.join(interface_dir, filepath)))<br>
+<br>
+    logging.debug("found swig interface files: %s", interface_file_paths)<br>
+    return interface_file_paths<br>
+<br>
+<br>
+def remove_ignore_enoent(filename):<br>
+    """Removes given file, ignoring error if it doesn't exist.<br>
+<br>
+    @param filename the path of the file to remove.<br>
+    """<br>
+    try:<br>
+        os.remove(filename)<br>
+    except OSError as error:<br>
+        import errno<br>
+        if error.errno != errno.ENOENT:<br>
+            raise<br>
+<br>
+<br>
+def do_swig_rebuild(options, dependency_file, config_build_dir, settings):<br>
+    """Generates Python bindings file from swig.<br>
+<br>
+    This method will do a sys.exit() if something fails.  If it returns to<br>
+    the caller, it succeeded.<br>
+<br>
+    @param options the parsed command line options structure.<br>
+    @param dependency_file path to the bindings dependency file<br>
+    to be generated; otherwise, None if a dependency file is not<br>
+    to be generated.<br>
+    @param config_build_dir used as the output directory used by swig<br>
+    @param settings the SwigSettings that specify a number of aspects used<br>
+    to configure building the Python binding with swig (mostly paths)<br>
+    """<br>
+    if options.generate_dependency_file:<br>
+        temp_dep_file_path = dependency_file + ".tmp"<br>
+<br>
+    # Build the SWIG args list<br>
+    command = [<br>
+        options.swig_executable,<br>
+        "-c++",<br>
+        "-shadow",<br>
+        "-python",<br>
+        "-threads",<br>
+        "-I\"%s\"" % os.path.normcase(<br>
+            os.path.join(options.src_root, "include")),<br>
+        "-I\"%s\"" % os.path.normcase("./."),<br>
+        "-D__STDC_LIMIT_MACROS",<br>
+        "-D__STDC_CONSTANT_MACROS"]<br>
+    if options.generate_dependency_file:<br>
+        command.append("-MMD -MF \"%s\"" % temp_dep_file_path)<br>
+    command.extend([<br>
+        "-outdir", "\"%s\"" % config_build_dir,<br>
+        "-o", "\"%s\"" % settings.output_file,<br>
+        "\"%s\"" % settings.input_file<br>
+        ])<br>
+    <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("running swig with: %s", command)<br>
+<br>
+    # Execute swig<br>
+    process = subprocess.Popen(<br>
+        ' '.join(command),<br>
+        stdout=subprocess.PIPE,<br>
+        stderr=subprocess.PIPE,<br>
+        shell=True)<br>
+    # Wait for SWIG process to terminate<br>
+    swig_stdout, swig_stderr = process.communicate()<br>
+    return_code = process.returncode<br>
+    if return_code != 0:<br>
+        logging.error(<br>
+            "swig failed with error code %d: stdout=%s, stderr=%s",<br>
+            return_code,<br>
+            swig_stdout,<br>
+            swig_stderr)<br>
+        logging.error(<br>
+            "command line:\n%s", ' '.join(command))<br>
+        sys.exit(return_code)<br>
+<br>
+    <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("swig generation succeeded")<br>
+    if swig_stdout is not None and len(swig_stdout) > 0:<br>
+        <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("swig output: %s", swig_stdout)<br>
+<br>
+    # Move the depedency file we just generated to the proper location.<br>
+    if options.generate_dependency_file:<br>
+        if os.path.exists(temp_dep_file_path):<br>
+            shutil.move(temp_dep_file_path, dependency_file)<br>
+        else:<br>
+            logging.error(<br>
+                "failed to generate Python binding depedency file '%s'",<br>
+                temp_dep_file_path)<br>
+            if os.path.exists(dependency_file):<br>
+                # Delete the old one.<br>
+                os.remove(dependency_file)<br>
+            sys.exit(-10)<br>
+<br>
+<br>
+def run_python_script(script_and_args):<br>
+    """Runs a python script, logging appropriately.<br>
+<br>
+    If the command returns anything non-zero, it is registered as<br>
+    an error and exits the program.<br>
+<br>
+    @param script_and_args the python script to execute, along with<br>
+    the command line arguments to pass to it.<br>
+    """<br>
+    command_line = "%s %s" % (sys.executable, script_and_args)<br>
+    process = subprocess.Popen(command_line, shell=True)<br>
+    script_stdout, script_stderr = process.communicate()<br>
+    return_code = process.returncode<br>
+    if return_code != 0:<br>
+        logging.error("failed to run '%s': %s", command_line, script_stderr)<br>
+        sys.exit(return_code)<br>
+    else:<br>
+        <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("ran script '%s'", command_line)<br>
+        if script_stdout is not None:<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("output: %s", script_stdout)<br>
+<br>
+<br>
+def do_modify_python_lldb(options, config_build_dir):<br>
+    """Executes the modify-python-lldb.py script.<br>
+<br>
+    @param options the parsed command line arguments<br>
+    @param config_build_dir the directory where the Python output was created.<br>
+    """<br>
+    script_path = os.path.normcase(<br>
+        os.path.join(<br>
+            options.src_root,<br>
+            "scripts",<br>
+            "Python",<br>
+            "modify-python-lldb.py"))<br>
+<br>
+    if not os.path.exists(script_path):<br>
+        logging.error("failed to find python script: '%s'", script_path)<br>
+        sys.exit(-11)<br>
+<br>
+    script_invocation = "%s %s" % (script_path, config_build_dir)<br>
+    run_python_script(script_invocation)<br>
+<br>
+<br>
+def get_python_module_path(options):<br>
+    """Returns the location where the lldb Python module should be placed.<br>
+<br>
+    @param options dictionary of options parsed from the command line.<br>
+<br>
+    @return the directory where the lldb module should be placed.<br>
+    """<br>
+    if options.framework:<br>
+        # Caller wants to use the OS X framework packaging.<br>
+<br>
+        # We are packaging in an OS X-style framework bundle. The<br>
+        # module dir will be within the<br>
+        # LLDB.framework/Resources/Python subdirectory.<br>
+        return os.path.join(<br>
+            options.target_dir,<br>
+            "LLDB.framework",<br>
+            "Resources",<br>
+            "Python",<br>
+            "lldb")<br>
+    else:<br>
+        from distutils.sysconfig import get_python_lib<br>
+<br>
+        if options.prefix is not None:<br>
+            module_path = get_python_lib(True, False, options.prefix)<br>
+        else:<br>
+            module_path = get_python_lib(True, False)<br>
+        return os.path.normcase(<br>
+            os.path.join(module_path, "lldb"))<br>
+<br>
+<br>
+def main(options):<br>
+    """Pepares the Python language binding to LLDB.<br>
+<br>
+    @param options the parsed command line argument dictionary<br>
+    """<br>
+    # Setup generated dependency file options.<br>
+    if options.generate_dependency_file:<br>
+        dependency_file = os.path.normcase(os.path.join(<br>
+            options.target_dir, "LLDBWrapPython.cpp.d"))<br>
+    else:<br>
+        dependency_file = None<br>
+<br>
+    # Keep track of all the swig-related settings.<br>
+    settings = SwigSettings()<br>
+<br>
+    # Determine the final binding file path.<br>
+    settings.output_file = os.path.normcase(<br>
+        os.path.join(options.target_dir, "LLDBWrapPython.cpp"))<br>
+<br>
+    # Touch the output file (but don't really generate it) if python<br>
+    # is disabled.<br>
+    disable_python = os.getenv("LLDB_DISABLE_PYTHON", None)<br>
+    if disable_python is not None and disable_python == "1":<br>
+        remove_ignore_enoent(settings.output_file)<br>
+        # Touch the file.<br>
+        open(settings.output_file, 'w').close()<br>
+        <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>(<br>
+            "Created empty python binding file due to LLDB_DISABLE_PYTHON "<br>
+            "being set")<br>
+        return<br>
+<br>
+    # We also check the GCC_PREPROCESSOR_DEFINITIONS to see if it<br>
+    # contains LLDB_DISABLE_PYTHON.  If so, we skip generating<br>
+    # the binding.<br>
+    gcc_preprocessor_defs = os.getenv("GCC_PREPROCESSOR_DEFINITIONS", None)<br>
+    if gcc_preprocessor_defs is not None:<br>
+        if re.search(r"LLDB_DISABLE_PYTHON", gcc_preprocessor_defs):<br>
+            remove_ignore_enoent(settings.output_file)<br>
+            # Touch the file<br>
+            open(settings.output_file, 'w').close()<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>(<br>
+                "Created empty python binding file due to "<br>
+                "finding LLDB_DISABLE_PYTHON in GCC_PREPROCESSOR_DEFINITIONS")<br>
+            return<br>
+<br>
+    # Setup paths used during swig invocation.<br>
+    settings.input_file = os.path.normcase(<br>
+        os.path.join(options.src_root, "scripts", "lldb.swig"))<br>
+    scripts_python_dir = os.path.dirname(os.path.realpath(__file__))<br>
+    settings.extensions_file = os.path.normcase(<br>
+        os.path.join(scripts_python_dir, "python-extensions.swig"))<br>
+    settings.wrapper_file = os.path.normcase(<br>
+        os.path.join(scripts_python_dir, "python-wrapper.swig"))<br>
+    settings.typemaps_file = os.path.normcase(<br>
+        os.path.join(scripts_python_dir, "python-typemaps.swig"))<br>
+    settings.safecast_file = os.path.normcase(<br>
+        os.path.join(scripts_python_dir, "python-swigsafecast.swig"))<br>
+<br>
+    settings.header_files = get_header_files(options)<br>
+    settings.interface_files = get_interface_files(options)<br>
+<br>
+    generate_output = settings.output_out_of_date()<br>
+<br>
+    # Determine where to put the module.<br>
+    python_module_path = get_python_module_path(options)<br>
+    <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("python module path: %s", python_module_path)<br>
+<br>
+    # Handle the configuration build dir.<br>
+    if options.config_build_dir is not None:<br>
+        config_build_dir = options.config_build_dir<br>
+    else:<br>
+        config_build_dir = python_module_path<br>
+<br>
+    # Allow missing/non-link _lldb.so to force regeneration.<br>
+    if not generate_output:<br>
+        # Ensure the _lldb.so file exists.<br>
+        so_path = os.path.join(python_module_path, "_lldb.so")<br>
+        if not os.path.exists(so_path) or not os.path.islink(so_path):<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("_lldb.so doesn't exist or isn't a symlink")<br>
+            generate_output = True<br>
+<br>
+    # Allow missing __init__.py to force regeneration.<br>
+    if not generate_output:<br>
+        # Ensure the __init__.py for the lldb module can be found.<br>
+        init_path = os.path.join(python_module_path, "__init__.py")<br>
+        if not os.path.exists(init_path):<br>
+            <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("__init__.py doesn't exist")<br>
+            generate_output = True<br>
+<br>
+    if not generate_output:<br>
+        <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>(<br>
+            "Skipping Python binding generation: everything is up to date")<br>
+        return<br>
+<br>
+    # Generate the Python binding with swig.<br>
+    <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("Python binding is out of date, regenerating")<br>
+    do_swig_rebuild(options, dependency_file, config_build_dir, settings)<br>
+    if options.generate_dependency_file:<br>
+        return<br>
+<br>
+    # Post process the swig-generated file.<br>
+    do_modify_python_lldb(options, config_build_dir)<br>
+<br>
+<br>
+# This script can be called by another Python script by calling the main()<br>
+# function directly<br>
+if __name__ == "__main__":<br>
+    print("Script cannot be called directly.")<br>
+    sys.exit(-1)<br>
<br>
Added: lldb/trunk/scripts/prepare_bindings.py<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/prepare_bindings.py?rev=253317&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/prepare_bindings.py?rev=253317&view=auto</a><br>
==============================================================================<br>
--- lldb/trunk/scripts/prepare_bindings.py (added)<br>
+++ lldb/trunk/scripts/prepare_bindings.py Tue Nov 17 01:17:38 2015<br>
@@ -0,0 +1,196 @@<br>
+#!/usr/bin/env python<br>
+"""<br>
+                     The LLVM Compiler Infrastructure<br>
+<br>
+This file is distributed under the University of Illinois Open Source<br>
+License. See LICENSE.TXT for details.<br>
+<br>
+Prepares language bindings for LLDB build process.  Run with --help<br>
+to see a description of the supported command line arguments.<br>
+"""<br>
+<br>
+# Python modules:<br>
+import argparse<br>
+import logging<br>
+import os<br>
+import sys<br>
+<br>
+<br>
+def prepare_binding_for_language(scripts_dir, script_lang, options):<br>
+    """Prepares the binding for a specific language.<br>
+<br>
+    @param scripts_dir the full path to the scripts source directory.<br>
+    @param script_lang the name of the script language.  Should be a child<br>
+    directory within the scripts dir, and should contain a<br>
+    prepare_scripts_{script_lang}.py script file in it.<br>
+    @param options the dictionary of parsed command line options.<br>
+<br>
+    There is no return value.  If it returns, the process succeeded; otherwise,<br>
+    the process will exit where it fails.<br>
+    """<br>
+    # Ensure the language-specific prepare module exists.<br>
+    script_name = "prepare_binding_{}.py".format(script_lang)<br>
+    lang_path = os.path.join(scripts_dir, script_lang)<br>
+    script_path = os.path.join(lang_path, script_name)<br>
+    if not os.path.exists(script_path):<br>
+        logging.error(<br>
+            "failed to find prepare script for language '%s' at '%s'",<br>
+            script_lang,<br>
+            script_path)<br>
+        sys.exit(-9)<br>
+<br>
+    # Include this language-specific directory in the Python search<br>
+    # path.<br>
+    sys.path.append(os.path.normcase(lang_path))<br>
+<br>
+    # Execute the specific language script<br>
+    module_name = os.path.splitext(script_name)[0]<br>
+    module = __import__(module_name)<br>
+    module.main(options)<br>
+<br>
+    # Remove the language-specific directory from the Python search path.<br>
+    sys.path.remove(os.path.normcase(lang_path))<br>
+<br>
+<br>
+def prepare_all_bindings(options):<br>
+    """Prepares bindings for each of the languages supported.<br>
+<br>
+    @param options the parsed arguments from the command line<br>
+<br>
+    @return the exit value for the program. 0 is success, all othes<br>
+    indicate some kind of failure.<br>
+    """<br>
+    # Check for the existence of the SWIG scripts folder<br>
+    scripts_dir = os.path.join(options.src_root, "scripts")<br>
+    if not os.path.exists(scripts_dir):<br>
+        logging.error("failed to find scripts dir: '%s'", scripts_dir)<br>
+        sys.exit(-8)<br>
+<br>
+    # Collect list of child directories.  We expect there to be one<br>
+    # for each supported script language.<br>
+    child_dirs = [f for f in os.listdir(scripts_dir)<br>
+                  if os.path.isdir(os.path.join(scripts_dir, f))]<br>
+<br>
+    # Remove directories that do not represent script languages.<br>
+    for removal_dir in [".svn", "interface", "__pycache__", "sphinx"]:<br>
+        if removal_dir in child_dirs:<br>
+            child_dirs.remove(removal_dir)<br>
+<br>
+    <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("found script directories: %s", child_dirs)<br>
+<br>
+    # Iterate script directory find any script language directories<br>
+    for script_lang in child_dirs:<br>
+        <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("executing language script for: '%s'", script_lang)<br>
+        prepare_binding_for_language(scripts_dir, script_lang, options)<br>
+<br>
+<br>
+def process_args(args):<br>
+    """Returns options processed from the provided command line.<br>
+<br>
+    @param args the command line to process.<br>
+    """<br>
+<br>
+    # Setup the parser arguments that are accepted.<br>
+    parser = argparse.ArgumentParser(<br>
+        description="Prepare language bindings for LLDB build.")<br>
+<br>
+    # Arguments to control logging verbosity.<br>
+    parser.add_argument(<br>
+        "--debug", "-d",<br>
+        action="store_true",<br>
+        help="Set program logging level to DEBUG.")<br>
+    parser.add_argument(<br>
+        "--verbose", "-v",<br>
+        action="count",<br>
+        default=0,<br>
+        help=(<br>
+            "Increase logging verbosity level.  Default: only error and "<br>
+            "higher are displayed.  Each -v increases level of verbosity."))<br>
+<br>
+    # Arguments to control whether we're building an OS X-style<br>
+    # framework.  This is the opposite of the older "-m" (makefile)<br>
+    # option.<br>
+    parser.add_argument(<br>
+        "--config-build-dir",<br>
+        "--cfgBldDir",<br>
+        help=(<br>
+            "Configuration build dir, will use python module path "<br>
+            "if unspecified."))<br>
+    parser.add_argument(<br>
+        "--framework",<br>
+        action="store_true",<br>
+        help="Prepare as OS X-style framework.")<br>
+    parser.add_argument(<br>
+        "--generate-dependency-file",<br>
+        "-M",<br>
+        action="store_true",<br>
+        help="Make the dependency (.d) file for the wrappers.")<br>
+    parser.add_argument(<br>
+        "--prefix",<br>
+        help="Override path where the LLDB module is placed.")<br>
+    parser.add_argument(<br>
+        "--src-root",<br>
+        "--srcRoot",<br>
+        "-s",<br>
+        # Default to the parent directory of this script's directory.<br>
+        default=os.path.abspath(<br>
+            os.path.join(<br>
+                os.path.dirname(os.path.realpath(__file__)),<br>
+                os.path.pardir)),<br>
+        help="Specifies the LLDB source root directory.")<br>
+    parser.add_argument(<br>
+        "--swig-executable",<br>
+        "--swigExecutable",<br>
+        help="Path to the swig executable.")<br>
+    parser.add_argument(<br>
+        "--target-dir",<br>
+        "--targetDir",<br>
+        required=True,<br>
+        help=(<br>
+            "Specifies the build dir where the language binding "<br>
+            "should be placed"))<br>
+<br>
+    # Process args.<br>
+    options = parser.parse_args(args)<br>
+<br>
+    # Set logging level based on verbosity count.<br>
+    if options.debug:<br>
+        log_level = logging.DEBUG<br>
+    else:<br>
+        # See logging documentation for error levels.  We'll default<br>
+        # to showing ERROR or higher error messages.  For each -v<br>
+        # specified, we'll shift to the next lower-priority log level.<br>
+        log_level = logging.ERROR - 10 * options.verbose<br>
+        if log_level < logging.NOTSET:<br>
+            # Displays all logged messages.<br>
+            log_level = logging.NOTSET<br>
+    logging.basicConfig(level=log_level)<br>
+    <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("logging is using level: %d", log_level)<br>
+<br>
+    return options<br>
+<br>
+<br>
+def main(args):<br>
+    """Drives the main script preparation steps.<br>
+<br>
+    @param args list of command line arguments.<br>
+    """<br>
+    # Process command line arguments.<br>
+    options = process_args(args)<br>
+    logging.debug("Processed args: options=%s", options)<br>
+<br>
+    # Check if the swig file exists.<br>
+    swig_path = os.path.normcase(<br>
+        os.path.join(options.src_root, "scripts", "lldb.swig"))<br>
+    if not os.path.isfile(swig_path):<br>
+        logging.error("swig file not found at '%s'", swig_path)<br>
+        sys.exit(-3)<br>
+<br>
+    # Prepare bindings for each supported language binding.<br>
+    # This will error out if it doesn't succeed.<br>
+    prepare_all_bindings(options)<br>
+    sys.exit(0)<br>
+<br>
+if __name__ == "__main__":<br>
+    # Run the main driver loop.<br>
+    main(sys.argv[1:])<br>
<br>
Propchange: lldb/trunk/scripts/prepare_bindings.py<br>
------------------------------------------------------------------------------<br>
    svn:executable = *<br>
<br>
<br>
_______________________________________________<br>
lldb-commits mailing list<br>
<a href="mailto:lldb-commits@lists.llvm.org" target="_blank">lldb-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits</a><br>
</blockquote></div>
</blockquote></div><br><br clear="all"><div><br></div></div></div><span class="HOEnZb"><font color="#888888">-- <br><div><div dir="ltr">-Todd</div></div>
</font></span></div>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr">-Todd</div></div>
</div>