[Lldb-commits] [lldb] r253317 - Add Pythonic language binding wrapper generation script.

Todd Fiala via lldb-commits lldb-commits at lists.llvm.org
Tue Nov 17 08:15:34 PST 2015


Yes, I am planning on separating out the usage of the swig output from the
massaging of that into the build.

Right now I'm just in phase 1, which is to clean up the existing process
without modifying it, and adopting it on Xcode.

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.

On Tue, Nov 17, 2015 at 8:12 AM, Zachary Turner <zturner at google.com> wrote:

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


-- 
-Todd
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20151117/318878e3/attachment-0001.html>


More information about the lldb-commits mailing list