|  | #!/usr/bin/env python | 
|  | # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  |  | 
|  | """Creates windows and posix stub files for a given set of signatures. | 
|  |  | 
|  | For libraries that need to be loaded outside of the standard executable startup | 
|  | path mechanism, stub files need to be generated for the wanted functions.  In | 
|  | windows, this is done via "def" files and the delay load mechanism.  On a posix | 
|  | system, a set of stub functions need to be generated that dispatch to functions | 
|  | found via dlsym. | 
|  |  | 
|  | This script takes a set of files, where each file is a list of C-style | 
|  | signatures (one signature per line).  The output is either a windows def file, | 
|  | or a header + implementation file of stubs suitable for use in a posix system. | 
|  |  | 
|  | This script also handles varidiac functions, e.g. | 
|  | void printf(const char* s, ...); | 
|  |  | 
|  | TODO(hclam): Fix the situation for varidiac functions. | 
|  | Stub for the above function will be generated and inside the stub function it | 
|  | is translated to: | 
|  | void printf(const char* s, ...) { | 
|  | printf_ptr(s, (void*)arg1); | 
|  | } | 
|  |  | 
|  | Only one argument from the varidiac arguments is used and it will be used as | 
|  | type void*. | 
|  | """ | 
|  |  | 
|  | __author__ = 'ajwong@chromium.org (Albert J. Wong)' | 
|  |  | 
|  | import optparse | 
|  | import os | 
|  | import re | 
|  | import string | 
|  | import subprocess | 
|  | import sys | 
|  |  | 
|  |  | 
|  | class Error(Exception): | 
|  | pass | 
|  |  | 
|  |  | 
|  | class BadSignatureError(Error): | 
|  | pass | 
|  |  | 
|  |  | 
|  | class SubprocessError(Error): | 
|  | def __init__(self, message, error_code): | 
|  | Error.__init__(self) | 
|  | self.message = message | 
|  | self.error_code = error_code | 
|  |  | 
|  | def __str__(self): | 
|  | return 'Failed with code %s: %s' % (self.message, repr(self.error_code)) | 
|  |  | 
|  |  | 
|  | # Regular expression used to parse function signatures in the input files. | 
|  | # The regex is built around identifying the "identifier" for the function name. | 
|  | # We consider the identifier to be the string that follows these constraints: | 
|  | # | 
|  | #   1) Starts with [_a-ZA-Z] (C++ spec 2.10). | 
|  | #   2) Continues with [_a-ZA-Z0-9] (C++ spec 2.10). | 
|  | #   3) Preceeds an opening parenthesis by 0 or more whitespace chars. | 
|  | # | 
|  | # From that, all preceeding characters are considered the return value. | 
|  | # Trailing characters should have a substring matching the form (.*).  That | 
|  | # is considered the arguments. | 
|  | SIGNATURE_REGEX = re.compile('(?P<return_type>.+?)' | 
|  | '(?P<name>[_a-zA-Z][_a-zA-Z0-9]+)\s*' | 
|  | '\((?P<params>.*?)\)') | 
|  |  | 
|  | # Used for generating C++ identifiers. | 
|  | INVALID_C_IDENT_CHARS = re.compile('[^_a-zA-Z0-9]') | 
|  |  | 
|  | # Constants defning the supported file types options. | 
|  | FILE_TYPE_WIN_X86 = 'windows_lib' | 
|  | FILE_TYPE_WIN_X64 = 'windows_lib_x64' | 
|  | FILE_TYPE_POSIX_STUB = 'posix_stubs' | 
|  | FILE_TYPE_WIN_DEF = 'windows_def' | 
|  |  | 
|  | # Template for generating a stub function definition.  Includes a forward | 
|  | # declaration marking the symbol as weak.  This template takes the following | 
|  | # named parameters. | 
|  | #   return_type: The return type. | 
|  | #   export: The macro used to alter the stub's visibility. | 
|  | #   name: The name of the function. | 
|  | #   params: The parameters to the function. | 
|  | #   return_prefix: 'return ' if this function is not void. '' otherwise. | 
|  | #   arg_list: The arguments used to call the stub function. | 
|  | STUB_FUNCTION_DEFINITION = ( | 
|  | """extern %(return_type)s %(name)s(%(params)s) __attribute__((weak)); | 
|  | %(return_type)s %(export)s %(name)s(%(params)s) { | 
|  | %(return_prefix)s%(name)s_ptr(%(arg_list)s); | 
|  | }""") | 
|  |  | 
|  | # Template for generating a variadic stub function definition with return | 
|  | # value. | 
|  | # Includes a forward declaration marking the symbol as weak. | 
|  | # This template takes the following named parameters. | 
|  | #   return_type: The return type. | 
|  | #   export: The macro used to alter the stub's visibility. | 
|  | #   name: The name of the function. | 
|  | #   params: The parameters to the function. | 
|  | #   arg_list: The arguments used to call the stub function without the | 
|  | #             variadic argument. | 
|  | #   last_named_arg: Name of the last named argument before the variadic | 
|  | #                   argument. | 
|  | VARIADIC_STUB_FUNCTION_DEFINITION = ( | 
|  | """extern %(return_type)s %(name)s(%(params)s) __attribute__((weak)); | 
|  | %(return_type)s %(export)s %(name)s(%(params)s) { | 
|  | va_list args___; | 
|  | va_start(args___, %(last_named_arg)s); | 
|  | %(return_type)s ret___ = %(name)s_ptr(%(arg_list)s, va_arg(args___, void*)); | 
|  | va_end(args___); | 
|  | return ret___; | 
|  | }""") | 
|  |  | 
|  | # Template for generating a variadic stub function definition without | 
|  | # return value. | 
|  | # Includes a forward declaration marking the symbol as weak. | 
|  | # This template takes the following named parameters. | 
|  | #   name: The name of the function. | 
|  | #   params: The parameters to the function. | 
|  | #   export: The macro used to alter the stub's visibility. | 
|  | #   arg_list: The arguments used to call the stub function without the | 
|  | #             variadic argument. | 
|  | #   last_named_arg: Name of the last named argument before the variadic | 
|  | #                   argument. | 
|  | VOID_VARIADIC_STUB_FUNCTION_DEFINITION = ( | 
|  | """extern void %(name)s(%(params)s) __attribute__((weak)); | 
|  | void %(export)s %(name)s(%(params)s) { | 
|  | va_list args___; | 
|  | va_start(args___, %(last_named_arg)s); | 
|  | %(name)s_ptr(%(arg_list)s, va_arg(args___, void*)); | 
|  | va_end(args___); | 
|  | }""") | 
|  |  | 
|  | # Template for the preamble for the stub header file with the header guards, | 
|  | # standard set of includes, and namespace opener.  This template takes the | 
|  | # following named parameters: | 
|  | #   guard_name: The macro to use as the header guard. | 
|  | #   namespace: The namespace for the stub functions. | 
|  | STUB_HEADER_PREAMBLE = """// This is generated file. Do not modify directly. | 
|  |  | 
|  | #ifndef %(guard_name)s | 
|  | #define %(guard_name)s | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include <map> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/logging.h" | 
|  |  | 
|  | namespace %(namespace)s { | 
|  | """ | 
|  |  | 
|  | # Template for the end of the stub header. This closes the namespace and the | 
|  | # header guards.  This template takes the following named parameters: | 
|  | #   guard_name: The macro to use as the header guard. | 
|  | #   namespace: The namespace for the stub functions. | 
|  | STUB_HEADER_CLOSER = """}  // namespace %(namespace)s | 
|  |  | 
|  | #endif  // %(guard_name)s | 
|  | """ | 
|  |  | 
|  | # The standard includes needed for the stub implementation file.  Takes one | 
|  | # string substition with the path to the associated stub header file. | 
|  | IMPLEMENTATION_PREAMBLE = """// This is generated file. Do not modify directly. | 
|  |  | 
|  | #include "%s" | 
|  |  | 
|  | #include <stdlib.h>  // For NULL. | 
|  | #include <dlfcn.h>   // For dysym, dlopen. | 
|  |  | 
|  | #include <map> | 
|  | #include <vector> | 
|  | """ | 
|  |  | 
|  | # The start and end templates for the enum definitions used by the Umbrella | 
|  | # initializer. | 
|  | UMBRELLA_ENUM_START = """// Enum and typedef for umbrella initializer. | 
|  | enum StubModules { | 
|  | """ | 
|  | UMBRELLA_ENUM_END = """  kNumStubModules | 
|  | }; | 
|  |  | 
|  | """ | 
|  |  | 
|  | # Start and end of the extern "C" section for the implementation contents. | 
|  | IMPLEMENTATION_CONTENTS_C_START = """extern "C" { | 
|  |  | 
|  | """ | 
|  | IMPLEMENTATION_CONTENTS_C_END = """ | 
|  | }  // extern "C" | 
|  |  | 
|  |  | 
|  | """ | 
|  |  | 
|  | # Templates for the start and end of a namespace.  Takes one parameter, the | 
|  | # namespace name. | 
|  | NAMESPACE_START = """namespace %s { | 
|  |  | 
|  | """ | 
|  | NAMESPACE_END = """}  // namespace %s | 
|  |  | 
|  | """ | 
|  |  | 
|  | # Comment to include before the section declaring all the function pointers | 
|  | # used by the stub functions. | 
|  | FUNCTION_POINTER_SECTION_COMMENT = ( | 
|  | """// Static pointers that will hold the location of the real function | 
|  | // implementations after the module has been loaded. | 
|  | """) | 
|  |  | 
|  | # Template for the module initialization check function.  This template | 
|  | # takes two parameteres: the function name, and the conditional used to | 
|  | # verify the module's initialization. | 
|  | MODULE_INITIALIZATION_CHECK_FUNCTION = ( | 
|  | """// Returns true if all stubs have been properly initialized. | 
|  | bool %s() { | 
|  | if (%s) { | 
|  | return true; | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | """) | 
|  |  | 
|  | # Template for the line that initialize the stub pointer.  This template takes | 
|  | # the following named parameters: | 
|  | #   name: The name of the function. | 
|  | #   return_type: The return type. | 
|  | #   params: The parameters to the function. | 
|  | STUB_POINTER_INITIALIZER = """  %(name)s_ptr = | 
|  | reinterpret_cast<%(return_type)s (*)(%(parameters)s)>( | 
|  | dlsym(module, "%(name)s")); | 
|  | VLOG_IF(1, !%(name)s_ptr) << "Couldn't load %(name)s, dlerror() says:\\n" | 
|  | << dlerror(); | 
|  | """ | 
|  |  | 
|  | # Template for module initializer function start and end.  This template takes | 
|  | # one parameter which is the initializer function name. | 
|  | MODULE_INITIALIZE_START = """// Initializes the module stubs. | 
|  | void %s(void* module) { | 
|  | """ | 
|  | MODULE_INITIALIZE_END = """} | 
|  |  | 
|  | """ | 
|  |  | 
|  | # Template for module uninitializer function start and end.  This template | 
|  | # takes one parameter which is the initializer function name. | 
|  | MODULE_UNINITIALIZE_START = ( | 
|  | """// Uninitialize the module stubs.  Reset pointers to NULL. | 
|  | void %s() { | 
|  | """) | 
|  | MODULE_UNINITIALIZE_END = """} | 
|  |  | 
|  | """ | 
|  |  | 
|  |  | 
|  | # Open namespace and add typedef for internal data structures used by the | 
|  | # umbrella initializer. | 
|  | UMBRELLA_INITIALIZER_START = """namespace %s { | 
|  | typedef std::map<StubModules, void*> StubHandleMap; | 
|  | """ | 
|  |  | 
|  | # Function close DSOs on error and clean up dangling references. | 
|  | UMBRELLA_INITIALIZER_CLEANUP_FUNCTION = ( | 
|  | """static void CloseLibraries(StubHandleMap* stub_handles) { | 
|  | for (StubHandleMap::const_iterator it = stub_handles->begin(); | 
|  | it != stub_handles->end(); | 
|  | ++it) { | 
|  | dlclose(it->second); | 
|  | } | 
|  |  | 
|  | stub_handles->clear(); | 
|  | } | 
|  | """) | 
|  |  | 
|  | # Function to initialize each DSO for the given paths. | 
|  | UMBRELLA_INITIALIZER_INITIALIZE_FUNCTION_START = ( | 
|  | """bool InitializeStubs(const StubPathMap& path_map) { | 
|  | StubHandleMap opened_libraries; | 
|  | for (int i = 0; i < kNumStubModules; ++i) { | 
|  | StubModules cur_module = static_cast<StubModules>(i); | 
|  | // If a module is missing, we fail. | 
|  | StubPathMap::const_iterator it = path_map.find(cur_module); | 
|  | if (it == path_map.end()) { | 
|  | CloseLibraries(&opened_libraries); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Otherwise, attempt to dlopen the library. | 
|  | const std::vector<std::string>& paths = it->second; | 
|  | bool module_opened = false; | 
|  | for (std::vector<std::string>::const_iterator dso_path = paths.begin(); | 
|  | !module_opened && dso_path != paths.end(); | 
|  | ++dso_path) { | 
|  | void* handle = dlopen(dso_path->c_str(), RTLD_LAZY); | 
|  | if (handle != NULL) { | 
|  | module_opened = true; | 
|  | opened_libraries[cur_module] = handle; | 
|  | } else { | 
|  | VLOG(1) << "dlopen(" << dso_path->c_str() << ") failed, " | 
|  | << "dlerror() says:\\n" << dlerror(); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!module_opened) { | 
|  | CloseLibraries(&opened_libraries); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | """) | 
|  |  | 
|  | # Template to generate code to check if each module initializer correctly | 
|  | # completed, and cleanup on failures.  This template takes the following | 
|  | # named parameters. | 
|  | #   conditional: The conditional expression for successful initialization. | 
|  | #   uninitializers: The statements needed to uninitialize the modules. | 
|  | UMBRELLA_INITIALIZER_CHECK_AND_CLEANUP = ( | 
|  | """  // Check that each module is initialized correctly. | 
|  | // Close all previously opened libraries on failure. | 
|  | if (%(conditional)s) { | 
|  | %(uninitializers)s; | 
|  | CloseLibraries(&opened_libraries); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  | """) | 
|  |  | 
|  | # Template for Initialize, Unininitialize, and IsInitialized functions for each | 
|  | # module.  This template takes the following named parameters: | 
|  | #   initialize: Name of the Initialize function. | 
|  | #   uninitialize: Name of the Uninitialize function. | 
|  | #   is_initialized: Name of the IsInitialized function. | 
|  | MODULE_FUNCTION_PROTOTYPES = """bool %(is_initialized)s(); | 
|  | void %(initialize)s(void* module); | 
|  | void %(uninitialize)s(); | 
|  |  | 
|  | """ | 
|  |  | 
|  | # Template for umbrella initializer declaration and associated datatypes. | 
|  | UMBRELLA_INITIALIZER_PROTOTYPE = ( | 
|  | """typedef std::map<StubModules, std::vector<std::string> > StubPathMap; | 
|  |  | 
|  | // Umbrella initializer for all the modules in this stub file. | 
|  | bool InitializeStubs(const StubPathMap& path_map); | 
|  | """) | 
|  |  | 
|  |  | 
|  | def ExtractModuleName(infile_path): | 
|  | """Infers the module name from the input file path. | 
|  |  | 
|  | The input filename is supposed to be in the form "ModuleName.sigs". | 
|  | This function splits the filename from the extention on that basename of | 
|  | the path and returns that as the module name. | 
|  |  | 
|  | Args: | 
|  | infile_path: String holding the path to the input file. | 
|  |  | 
|  | Returns: | 
|  | The module name as a string. | 
|  | """ | 
|  | basename = os.path.basename(infile_path) | 
|  |  | 
|  | # This loop continously removes suffixes of the filename separated by a "." | 
|  | # character. | 
|  | while 1: | 
|  | new_basename = os.path.splitext(basename)[0] | 
|  | if basename == new_basename: | 
|  | break | 
|  | else: | 
|  | basename = new_basename | 
|  | return basename | 
|  |  | 
|  |  | 
|  | def ParseSignatures(infile): | 
|  | """Parses function signatures in the input file. | 
|  |  | 
|  | This function parses a file of signatures into a list of dictionaries that | 
|  | represent the function signatures in the input file.  Each dictionary has | 
|  | the following keys: | 
|  | return_type: A string with the return type. | 
|  | name: A string with the name of the function. | 
|  | params: A list of each function parameter declaration (type + name) | 
|  |  | 
|  | The format of the input file is one C-style function signature per line, no | 
|  | trailing semicolon.  Empty lines are allowed.  An empty line is a line that | 
|  | consists purely of whitespace.  Lines that begin with a # or // are considered | 
|  | comment lines and are ignored. | 
|  |  | 
|  | We assume that "int foo(void)" is the same as "int foo()", which is not | 
|  | true in C where "int foo()" is equivalent to "int foo(...)".  Our generated | 
|  | code is C++, and we do not handle varargs, so this is a case that can be | 
|  | ignored for now. | 
|  |  | 
|  | Args: | 
|  | infile: File object holding a text file of function signatures. | 
|  |  | 
|  | Returns: | 
|  | A list of dictionaries, where each dictionary represents one function | 
|  | signature. | 
|  |  | 
|  | Raises: | 
|  | BadSignatureError: A line could not be parsed as a signature. | 
|  | """ | 
|  | signatures = [] | 
|  | for line in infile: | 
|  | line = line.strip() | 
|  | if line and line[0] != '#' and line[0:2] != '//': | 
|  | m = SIGNATURE_REGEX.match(line) | 
|  | if m is None: | 
|  | raise BadSignatureError('Unparsable line: %s' % line) | 
|  | signatures.append( | 
|  | {'return_type': m.group('return_type').strip(), | 
|  | 'name': m.group('name').strip(), | 
|  | 'params': [arg.strip() for arg in m.group('params').split(',')]}) | 
|  | return signatures | 
|  |  | 
|  |  | 
|  | def WriteWindowsDefFile(module_name, signatures, outfile): | 
|  | """Writes a windows def file to the given output file object. | 
|  |  | 
|  | The def file format is basically a list of function names.  Generation is | 
|  | simple.  After outputting the LIBRARY and EXPORTS lines, print out each | 
|  | function name, one to a line, preceeded by 2 spaces. | 
|  |  | 
|  | Args: | 
|  | module_name: The name of the module we are writing a stub for. | 
|  | signatures: The list of signature hashes, as produced by ParseSignatures, | 
|  | to create stubs for. | 
|  | outfile: File handle to populate with definitions. | 
|  | """ | 
|  | outfile.write('LIBRARY %s\n' % module_name) | 
|  | outfile.write('EXPORTS\n') | 
|  |  | 
|  | for sig in signatures: | 
|  | outfile.write('  %s\n' % sig['name']) | 
|  |  | 
|  |  | 
|  | def QuietRun(args, filter=None, write_to=sys.stdout): | 
|  | """Invoke |args| as command via subprocess.Popen, filtering lines starting | 
|  | with |filter|.""" | 
|  | popen = subprocess.Popen(args, stdout=subprocess.PIPE) | 
|  | out, _ = popen.communicate() | 
|  | for line in out.splitlines(): | 
|  | if not filter or not line.startswith(filter): | 
|  | write_to.write(line + '\n') | 
|  | return popen.returncode | 
|  |  | 
|  |  | 
|  | def CreateWindowsLib(module_name, signatures, intermediate_dir, outdir_path, | 
|  | machine): | 
|  | """Creates a windows library file. | 
|  |  | 
|  | Calling this function will create a lib file in the outdir_path that exports | 
|  | the signatures passed into the object.  A temporary def file will be created | 
|  | in the intermediate_dir. | 
|  |  | 
|  | Args: | 
|  | module_name: The name of the module we are writing a stub for. | 
|  | signatures: The list of signature hashes, as produced by ParseSignatures, | 
|  | to create stubs for. | 
|  | intermediate_dir: The directory where the generated .def files should go. | 
|  | outdir_path: The directory where generated .lib files should go. | 
|  | machine: String holding the machine type, 'X86' or 'X64'. | 
|  |  | 
|  | Raises: | 
|  | SubprocessError: If invoking the windows "lib" tool fails, this is raised | 
|  | with the error code. | 
|  | """ | 
|  | def_file_path = os.path.join(intermediate_dir, | 
|  | module_name + '.def') | 
|  | lib_file_path = os.path.join(outdir_path, | 
|  | module_name + '.lib') | 
|  | outfile = open(def_file_path, 'w') | 
|  | try: | 
|  | WriteWindowsDefFile(module_name, signatures, outfile) | 
|  | finally: | 
|  | outfile.close() | 
|  |  | 
|  | # Invoke the "lib" program on Windows to create stub .lib files for the | 
|  | # generated definitions.  These .lib files can then be used during | 
|  | # delayloading of the dynamic libraries. | 
|  | ret = QuietRun(['lib', '/nologo', | 
|  | '/machine:' + machine, | 
|  | '/def:' + def_file_path, | 
|  | '/out:' + lib_file_path], | 
|  | filter='   Creating library') | 
|  | if ret != 0: | 
|  | raise SubprocessError( | 
|  | 'Failed creating %s for %s' % (lib_file_path, def_file_path), | 
|  | ret) | 
|  |  | 
|  |  | 
|  | class PosixStubWriter(object): | 
|  | """Creates a file of stub functions for a library that is opened via dlopen. | 
|  |  | 
|  | Windows provides a function in their compiler known as delay loading, which | 
|  | effectively generates a set of stub functions for a dynamic library that | 
|  | delays loading of the dynamic library/resolution of the symbols until one of | 
|  | the needed functions are accessed. | 
|  |  | 
|  | In posix, RTLD_LAZY does something similar with DSOs.  This is the default | 
|  | link mode for DSOs.  However, even though the symbol is not resolved until | 
|  | first usage, the DSO must be present at load time of the main binary. | 
|  |  | 
|  | To simulate the windows delay load procedure, we need to create a set of | 
|  | stub functions that allow for correct linkage of the main binary, but | 
|  | dispatch to the dynamically resolved symbol when the module is initialized. | 
|  |  | 
|  | This class takes a list of function signatures, and generates a set of stub | 
|  | functions plus initialization code for them. | 
|  | """ | 
|  |  | 
|  | def __init__(self, module_name, export_macro, signatures): | 
|  | """Initializes PosixStubWriter for this set of signatures and module_name. | 
|  |  | 
|  | Args: | 
|  | module_name: The name of the module we are writing a stub for. | 
|  | export_macro: A preprocessor macro used to annotate stub symbols with | 
|  | an EXPORT marking, to control visibility. | 
|  | signatures: The list of signature hashes, as produced by ParseSignatures, | 
|  | to create stubs for. | 
|  | """ | 
|  | self.signatures = signatures | 
|  | self.module_name = module_name | 
|  | self.export_macro = export_macro | 
|  |  | 
|  | @classmethod | 
|  | def CStyleIdentifier(cls, identifier): | 
|  | """Generates a C style identifier. | 
|  |  | 
|  | The module_name has all invalid identifier characters removed (anything | 
|  | that's not [_a-zA-Z0-9]) and is run through string.capwords to try | 
|  | and approximate camel case. | 
|  |  | 
|  | Args: | 
|  | identifier: The string with the module name to turn to C-style. | 
|  |  | 
|  | Returns: | 
|  | A string that can be used as part of a C identifier. | 
|  | """ | 
|  | return string.capwords(re.sub(INVALID_C_IDENT_CHARS, '', identifier)) | 
|  |  | 
|  | @classmethod | 
|  | def EnumName(cls, module_name): | 
|  | """Gets the enum name for the module. | 
|  |  | 
|  | Takes the module name and creates a suitable enum name.  The module_name | 
|  | is munged to be a valid C identifier then prefixed with the string | 
|  | "kModule" to generate a Google style enum name. | 
|  |  | 
|  | Args: | 
|  | module_name: The name of the module to generate an enum name for. | 
|  |  | 
|  | Returns: | 
|  | A string with the name of the enum value representing this module. | 
|  | """ | 
|  | return 'kModule%s' % PosixStubWriter.CStyleIdentifier(module_name) | 
|  |  | 
|  | @classmethod | 
|  | def IsInitializedName(cls, module_name): | 
|  | """Gets the name of function that checks initialization of this module. | 
|  |  | 
|  | The name is in the format IsModuleInitialized.  Where "Module" is replaced | 
|  | with the module name, munged to be a valid C identifier. | 
|  |  | 
|  | Args: | 
|  | module_name: The name of the module to generate the function name for. | 
|  |  | 
|  | Returns: | 
|  | A string with the name of the initialization check function. | 
|  | """ | 
|  | return 'Is%sInitialized' % PosixStubWriter.CStyleIdentifier(module_name) | 
|  |  | 
|  | @classmethod | 
|  | def InitializeModuleName(cls, module_name): | 
|  | """Gets the name of the function that initializes this module. | 
|  |  | 
|  | The name is in the format InitializeModule.  Where "Module" is replaced | 
|  | with the module name, munged to be a valid C identifier. | 
|  |  | 
|  | Args: | 
|  | module_name: The name of the module to generate the function name for. | 
|  |  | 
|  | Returns: | 
|  | A string with the name of the initialization function. | 
|  | """ | 
|  | return 'Initialize%s' % PosixStubWriter.CStyleIdentifier(module_name) | 
|  |  | 
|  | @classmethod | 
|  | def UninitializeModuleName(cls, module_name): | 
|  | """Gets the name of the function that uninitializes this module. | 
|  |  | 
|  | The name is in the format UninitializeModule.  Where "Module" is replaced | 
|  | with the module name, munged to be a valid C identifier. | 
|  |  | 
|  | Args: | 
|  | module_name: The name of the module to generate the function name for. | 
|  |  | 
|  | Returns: | 
|  | A string with the name of the uninitialization function. | 
|  | """ | 
|  | return 'Uninitialize%s' % PosixStubWriter.CStyleIdentifier(module_name) | 
|  |  | 
|  | @classmethod | 
|  | def StubFunctionPointer(cls, signature): | 
|  | """Generates a function pointer declaration for the given signature. | 
|  |  | 
|  | Args: | 
|  | signature: A signature hash, as produced by ParseSignatures, | 
|  | representating the function signature. | 
|  |  | 
|  | Returns: | 
|  | A string with the declaration of the function pointer for the signature. | 
|  | """ | 
|  | return 'static %s (*%s_ptr)(%s) = NULL;' % (signature['return_type'], | 
|  | signature['name'], | 
|  | ', '.join(signature['params'])) | 
|  |  | 
|  | @classmethod | 
|  | def StubFunction(cls, signature): | 
|  | """Generates a stub function definition for the given signature. | 
|  |  | 
|  | The function definitions are created with __attribute__((weak)) so that | 
|  | they may be overridden by a real static link or mock versions to be used | 
|  | when testing. | 
|  |  | 
|  | Args: | 
|  | signature: A signature hash, as produced by ParseSignatures, | 
|  | representating the function signature. | 
|  |  | 
|  | Returns: | 
|  | A string with the stub function definition. | 
|  | """ | 
|  | return_prefix = '' | 
|  | if signature['return_type'] != 'void': | 
|  | return_prefix = 'return ' | 
|  |  | 
|  | # Generate the argument list. | 
|  | arguments = [re.split('[\*& ]', arg)[-1].strip() for arg in | 
|  | signature['params']] | 
|  | arg_list = ', '.join(arguments) | 
|  | if arg_list == 'void': | 
|  | arg_list = '' | 
|  |  | 
|  | if arg_list != '' and len(arguments) > 1 and arguments[-1] == '...': | 
|  | # If the last argment is ... then this is a variadic function. | 
|  | if return_prefix != '': | 
|  | return VARIADIC_STUB_FUNCTION_DEFINITION % { | 
|  | 'return_type': signature['return_type'], | 
|  | 'name': signature['name'], | 
|  | 'params': ', '.join(signature['params']), | 
|  | 'arg_list': ', '.join(arguments[0:-1]), | 
|  | 'last_named_arg': arguments[-2], | 
|  | 'export': signature.get('export', '')} | 
|  | else: | 
|  | return VOID_VARIADIC_STUB_FUNCTION_DEFINITION % { | 
|  | 'name': signature['name'], | 
|  | 'params': ', '.join(signature['params']), | 
|  | 'arg_list': ', '.join(arguments[0:-1]), | 
|  | 'last_named_arg': arguments[-2], | 
|  | 'export': signature.get('export', '')} | 
|  | else: | 
|  | # This is a regular function. | 
|  | return STUB_FUNCTION_DEFINITION % { | 
|  | 'return_type': signature['return_type'], | 
|  | 'name': signature['name'], | 
|  | 'params': ', '.join(signature['params']), | 
|  | 'return_prefix': return_prefix, | 
|  | 'arg_list': arg_list, | 
|  | 'export': signature.get('export', '')} | 
|  |  | 
|  | @classmethod | 
|  | def WriteImplementationPreamble(cls, header_path, outfile): | 
|  | """Write the necessary includes for the implementation file. | 
|  |  | 
|  | Args: | 
|  | header_path: The path to the header file. | 
|  | outfile: The file handle to populate. | 
|  | """ | 
|  | outfile.write(IMPLEMENTATION_PREAMBLE % header_path) | 
|  |  | 
|  | @classmethod | 
|  | def WriteUmbrellaInitializer(cls, module_names, namespace, outfile): | 
|  | """Writes a single function that will open + initialize each module. | 
|  |  | 
|  | This intializer will take in an stl map of that lists the correct | 
|  | dlopen target for each module.  The map type is | 
|  | std::map<enum StubModules, vector<std::string>> which matches one module | 
|  | to a list of paths to try in dlopen. | 
|  |  | 
|  | This function is an all-or-nothing function.  If any module fails to load, | 
|  | all other modules are dlclosed, and the function returns.  Though it is | 
|  | not enforced, this function should only be called once. | 
|  |  | 
|  | Args: | 
|  | module_names: A list with the names of the modules in this stub file. | 
|  | namespace: The namespace these functions should be in. | 
|  | outfile: The file handle to populate with pointer definitions. | 
|  | """ | 
|  | outfile.write(UMBRELLA_INITIALIZER_START % namespace) | 
|  | outfile.write(UMBRELLA_INITIALIZER_CLEANUP_FUNCTION) | 
|  |  | 
|  | # Create the initializaiton function that calls all module initializers, | 
|  | # checks if they succeeded, and backs out module loads on an error. | 
|  | outfile.write(UMBRELLA_INITIALIZER_INITIALIZE_FUNCTION_START) | 
|  | outfile.write( | 
|  | '\n  // Initialize each module if we have not already failed.\n') | 
|  | for module in module_names: | 
|  | outfile.write('  %s(opened_libraries[%s]);\n' % | 
|  | (PosixStubWriter.InitializeModuleName(module), | 
|  | PosixStubWriter.EnumName(module))) | 
|  | outfile.write('\n') | 
|  |  | 
|  | # Output code to check the initialization status, clean up on error. | 
|  | initializer_checks = ['!%s()' % PosixStubWriter.IsInitializedName(name) | 
|  | for name in module_names] | 
|  | uninitializers = ['%s()' % PosixStubWriter.UninitializeModuleName(name) | 
|  | for name in module_names] | 
|  | outfile.write(UMBRELLA_INITIALIZER_CHECK_AND_CLEANUP % { | 
|  | 'conditional': ' ||\n      '.join(initializer_checks), | 
|  | 'uninitializers': ';\n    '.join(uninitializers)}) | 
|  | outfile.write('\n}  // namespace %s\n' % namespace) | 
|  |  | 
|  | @classmethod | 
|  | def WriteHeaderContents(cls, module_names, namespace, header_guard, outfile): | 
|  | """Writes a header file for the stub file generated for module_names. | 
|  |  | 
|  | The header file exposes the following: | 
|  | 1) An enum, StubModules, listing with an entry for each enum. | 
|  | 2) A typedef for a StubPathMap allowing for specification of paths to | 
|  | search for each module. | 
|  | 3) The IsInitialized/Initialize/Uninitialize functions for each module. | 
|  | 4) An umbrella initialize function for all modules. | 
|  |  | 
|  | Args: | 
|  | module_names: A list with the names of each module in this stub file. | 
|  | namespace: The namespace these functions should be in. | 
|  | header_guard: The macro to use as our header guard. | 
|  | outfile: The output handle to populate. | 
|  | """ | 
|  | outfile.write(STUB_HEADER_PREAMBLE % | 
|  | {'guard_name': header_guard, 'namespace': namespace}) | 
|  |  | 
|  | # Generate the Initializer protoypes for each module. | 
|  | outfile.write('// Individual module initializer functions.\n') | 
|  | for name in module_names: | 
|  | outfile.write(MODULE_FUNCTION_PROTOTYPES % { | 
|  | 'is_initialized': PosixStubWriter.IsInitializedName(name), | 
|  | 'initialize': PosixStubWriter.InitializeModuleName(name), | 
|  | 'uninitialize': PosixStubWriter.UninitializeModuleName(name)}) | 
|  |  | 
|  | # Generate the enum for umbrella initializer. | 
|  | outfile.write(UMBRELLA_ENUM_START) | 
|  | outfile.write('  %s = 0,\n' % PosixStubWriter.EnumName(module_names[0])) | 
|  | for name in module_names[1:]: | 
|  | outfile.write('  %s,\n' % PosixStubWriter.EnumName(name)) | 
|  | outfile.write(UMBRELLA_ENUM_END) | 
|  |  | 
|  | outfile.write(UMBRELLA_INITIALIZER_PROTOTYPE) | 
|  | outfile.write(STUB_HEADER_CLOSER % { | 
|  | 'namespace': namespace, 'guard_name': | 
|  | header_guard}) | 
|  |  | 
|  | def WriteImplementationContents(self, namespace, outfile): | 
|  | """Given a file handle, write out the stub definitions for this module. | 
|  |  | 
|  | Args: | 
|  | namespace: The namespace these functions should be in. | 
|  | outfile: The file handle to populate. | 
|  | """ | 
|  | outfile.write(IMPLEMENTATION_CONTENTS_C_START) | 
|  | self.WriteFunctionPointers(outfile) | 
|  | self.WriteStubFunctions(outfile) | 
|  | outfile.write(IMPLEMENTATION_CONTENTS_C_END) | 
|  |  | 
|  | outfile.write(NAMESPACE_START % namespace) | 
|  | self.WriteModuleInitializeFunctions(outfile) | 
|  | outfile.write(NAMESPACE_END % namespace) | 
|  |  | 
|  | def WriteFunctionPointers(self, outfile): | 
|  | """Write the function pointer declarations needed by the stubs. | 
|  |  | 
|  | We need function pointers to hold the actual location of the function | 
|  | implementation returned by dlsym.  This function outputs a pointer | 
|  | definition for each signature in the module. | 
|  |  | 
|  | Pointers will be named with the following pattern "FuntionName_ptr". | 
|  |  | 
|  | Args: | 
|  | outfile: The file handle to populate with pointer definitions. | 
|  | """ | 
|  | outfile.write(FUNCTION_POINTER_SECTION_COMMENT) | 
|  |  | 
|  | for sig in self.signatures: | 
|  | outfile.write('%s\n' % PosixStubWriter.StubFunctionPointer(sig)) | 
|  | outfile.write('\n') | 
|  |  | 
|  | def WriteStubFunctions(self, outfile): | 
|  | """Write the function stubs to handle dispatching to real implementations. | 
|  |  | 
|  | Functions that have a return type other than void will look as follows: | 
|  |  | 
|  | ReturnType FunctionName(A a) { | 
|  | return FunctionName_ptr(a); | 
|  | } | 
|  |  | 
|  | Functions with a return type of void will look as follows: | 
|  |  | 
|  | void FunctionName(A a) { | 
|  | FunctionName_ptr(a); | 
|  | } | 
|  |  | 
|  | Args: | 
|  | outfile: The file handle to populate. | 
|  | """ | 
|  | outfile.write('// Stubs that dispatch to the real implementations.\n') | 
|  | for sig in self.signatures: | 
|  | sig['export'] = self.export_macro | 
|  | outfile.write('%s\n' % PosixStubWriter.StubFunction(sig)) | 
|  |  | 
|  | def WriteModuleInitializeFunctions(self, outfile): | 
|  | """Write functions to initialize/query initlialization of the module. | 
|  |  | 
|  | This creates 2 functions IsModuleInitialized and InitializeModule where | 
|  | "Module" is replaced with the module name, first letter capitalized. | 
|  |  | 
|  | The InitializeModule function takes a handle that is retrieved from dlopen | 
|  | and attempts to assign each function pointer above via dlsym. | 
|  |  | 
|  | The IsModuleInitialized returns true if none of the required functions | 
|  | pointers are NULL. | 
|  |  | 
|  | Args: | 
|  | outfile: The file handle to populate. | 
|  | """ | 
|  | ptr_names = ['%s_ptr' % sig['name'] for sig in self.signatures] | 
|  |  | 
|  | # Construct the conditional expression to check the initialization of | 
|  | # all the function pointers above.  It should generate a conjuntion | 
|  | # with each pointer on its own line, indented by six spaces to match | 
|  | # the indentation level of MODULE_INITIALIZATION_CHECK_FUNCTION. | 
|  | initialization_conditional = ' &&\n      '.join(ptr_names) | 
|  |  | 
|  | outfile.write(MODULE_INITIALIZATION_CHECK_FUNCTION % ( | 
|  | PosixStubWriter.IsInitializedName(self.module_name), | 
|  | initialization_conditional)) | 
|  |  | 
|  | # Create function that initializes the module. | 
|  | outfile.write(MODULE_INITIALIZE_START % | 
|  | PosixStubWriter.InitializeModuleName(self.module_name)) | 
|  | for sig in self.signatures: | 
|  | outfile.write(STUB_POINTER_INITIALIZER % { | 
|  | 'name': sig['name'], | 
|  | 'return_type': sig['return_type'], | 
|  | 'parameters': ', '.join(sig['params'])}) | 
|  | outfile.write(MODULE_INITIALIZE_END) | 
|  |  | 
|  | # Create function that uninitializes the module (sets all pointers to | 
|  | # NULL). | 
|  | outfile.write(MODULE_UNINITIALIZE_START % | 
|  | PosixStubWriter.UninitializeModuleName(self.module_name)) | 
|  | for sig in self.signatures: | 
|  | outfile.write('  %s_ptr = NULL;\n' % sig['name']) | 
|  | outfile.write(MODULE_UNINITIALIZE_END) | 
|  |  | 
|  |  | 
|  | def CreateOptionParser(): | 
|  | """Creates an OptionParser for the configuration options of script. | 
|  |  | 
|  | Returns: | 
|  | A OptionParser object. | 
|  | """ | 
|  | parser = optparse.OptionParser(usage='usage: %prog [options] input') | 
|  | parser.add_option('-o', | 
|  | '--output', | 
|  | dest='out_dir', | 
|  | default=None, | 
|  | help='Output location.') | 
|  | parser.add_option('-i', | 
|  | '--intermediate_dir', | 
|  | dest='intermediate_dir', | 
|  | default=None, | 
|  | help=('Location of intermediate files. Ignored for %s type' | 
|  | % FILE_TYPE_WIN_DEF)) | 
|  | parser.add_option('-t', | 
|  | '--type', | 
|  | dest='type', | 
|  | default=None, | 
|  | help=('Type of file. Valid types are "%s" or "%s" or "%s" ' | 
|  | 'or "%s"' % | 
|  | (FILE_TYPE_POSIX_STUB, FILE_TYPE_WIN_X86, | 
|  | FILE_TYPE_WIN_X64, FILE_TYPE_WIN_DEF))) | 
|  | parser.add_option('-s', | 
|  | '--stubfile_name', | 
|  | dest='stubfile_name', | 
|  | default=None, | 
|  | help=('Name of posix_stubs output file. Only valid with ' | 
|  | '%s type.' % FILE_TYPE_POSIX_STUB)) | 
|  | parser.add_option('-p', | 
|  | '--path_from_source', | 
|  | dest='path_from_source', | 
|  | default=None, | 
|  | help=('The relative path from the project root that the ' | 
|  | 'generated file should consider itself part of (eg. ' | 
|  | 'third_party/ffmpeg).  This is used to generate the ' | 
|  | 'header guard and namespace for our initializer ' | 
|  | 'functions and does NOT affect the physical output ' | 
|  | 'location of the file like -o does.  Ignored for ' | 
|  | '%s and %s types.' % | 
|  | (FILE_TYPE_WIN_X86, FILE_TYPE_WIN_X64))) | 
|  | parser.add_option('-e', | 
|  | '--extra_stub_header', | 
|  | dest='extra_stub_header', | 
|  | default=None, | 
|  | help=('File to insert after the system includes in the ' | 
|  | 'generated stub implemenation file. Ignored for ' | 
|  | '%s and %s types.' % | 
|  | (FILE_TYPE_WIN_X86, FILE_TYPE_WIN_X64))) | 
|  | parser.add_option('-m', | 
|  | '--module_name', | 
|  | dest='module_name', | 
|  | default=None, | 
|  | help=('Name of output DLL or LIB for DEF creation using ' | 
|  | '%s type.' % FILE_TYPE_WIN_DEF)) | 
|  | parser.add_option('-x', | 
|  | '--export_macro', | 
|  | dest='export_macro', | 
|  | default='', | 
|  | help=('A macro to place between the return type and ' | 
|  | 'function name, e.g. MODULE_EXPORT, to control the ' | 
|  | 'visbility of the stub functions.')) | 
|  |  | 
|  | return parser | 
|  |  | 
|  |  | 
|  | def ParseOptions(): | 
|  | """Parses the options and terminates program if they are not sane. | 
|  |  | 
|  | Returns: | 
|  | The pair (optparse.OptionValues, [string]), that is the output of | 
|  | a successful call to parser.parse_args(). | 
|  | """ | 
|  | parser = CreateOptionParser() | 
|  | options, args = parser.parse_args() | 
|  |  | 
|  | if not args: | 
|  | parser.error('No inputs specified') | 
|  |  | 
|  | if options.out_dir is None: | 
|  | parser.error('Output location not specified') | 
|  |  | 
|  | if (options.type not in | 
|  | [FILE_TYPE_WIN_X86, FILE_TYPE_WIN_X64, FILE_TYPE_POSIX_STUB, | 
|  | FILE_TYPE_WIN_DEF]): | 
|  | parser.error('Invalid output file type: %s' % options.type) | 
|  |  | 
|  | if options.type == FILE_TYPE_POSIX_STUB: | 
|  | if options.stubfile_name is None: | 
|  | parser.error('Output file name needed for %s' % FILE_TYPE_POSIX_STUB) | 
|  | if options.path_from_source is None: | 
|  | parser.error('Path from source needed for %s' % FILE_TYPE_POSIX_STUB) | 
|  |  | 
|  | if options.type == FILE_TYPE_WIN_DEF: | 
|  | if options.module_name is None: | 
|  | parser.error('Module name needed for %s' % FILE_TYPE_WIN_DEF) | 
|  |  | 
|  | return options, args | 
|  |  | 
|  |  | 
|  | def EnsureDirExists(dir): | 
|  | """Creates a directory. Does not use the more obvious 'if not exists: create' | 
|  | to avoid race with other invocations of the same code, which will error out | 
|  | on makedirs if another invocation has succeeded in creating the directory | 
|  | since the existence check.""" | 
|  | try: | 
|  | os.makedirs(dir) | 
|  | except: | 
|  | if not os.path.isdir(dir): | 
|  | raise | 
|  |  | 
|  |  | 
|  | def CreateOutputDirectories(options): | 
|  | """Creates the intermediate and final output directories. | 
|  |  | 
|  | Given the parsed options, create the intermediate and final output | 
|  | directories if they do not exist.  Returns the paths to both directories | 
|  | as a pair. | 
|  |  | 
|  | Args: | 
|  | options: An OptionParser.OptionValues object with the parsed options. | 
|  |  | 
|  | Returns: | 
|  | The pair (out_dir, intermediate_dir), both of which are strings. | 
|  | """ | 
|  | out_dir = os.path.normpath(options.out_dir) | 
|  | intermediate_dir = os.path.normpath(options.intermediate_dir) | 
|  | if intermediate_dir is None: | 
|  | intermediate_dir = out_dir | 
|  |  | 
|  | EnsureDirExists(out_dir) | 
|  | EnsureDirExists(intermediate_dir) | 
|  |  | 
|  | return out_dir, intermediate_dir | 
|  |  | 
|  |  | 
|  | def CreateWindowsLibForSigFiles(sig_files, out_dir, intermediate_dir, machine, | 
|  | export_macro): | 
|  | """For each signature file, create a windows lib. | 
|  |  | 
|  | Args: | 
|  | sig_files: Array of strings with the paths to each signature file. | 
|  | out_dir: String holding path to directory where the generated libs go. | 
|  | intermediate_dir: String holding path to directory generated intermdiate | 
|  | artifacts. | 
|  | machine: String holding the machine type, 'X86' or 'X64'. | 
|  | export_macro: A preprocessor macro used to annotate stub symbols with | 
|  | an EXPORT marking, to control visibility. | 
|  | """ | 
|  | for input_path in sig_files: | 
|  | infile = open(input_path, 'r') | 
|  | try: | 
|  | signatures = ParseSignatures(infile) | 
|  | module_name = ExtractModuleName(os.path.basename(input_path)) | 
|  | for sig in signatures: | 
|  | sig['export'] = export_macro | 
|  | CreateWindowsLib(module_name, signatures, intermediate_dir, out_dir, | 
|  | machine) | 
|  | finally: | 
|  | infile.close() | 
|  |  | 
|  |  | 
|  | def CreateWindowsDefForSigFiles(sig_files, out_dir, module_name): | 
|  | """For all signature files, create a single windows def file. | 
|  |  | 
|  | Args: | 
|  | sig_files: Array of strings with the paths to each signature file. | 
|  | out_dir: String holding path to directory where the generated def goes. | 
|  | module_name: Name of the output DLL or LIB which will link in the def file. | 
|  | """ | 
|  | signatures = [] | 
|  | for input_path in sig_files: | 
|  | infile = open(input_path, 'r') | 
|  | try: | 
|  | signatures += ParseSignatures(infile) | 
|  | finally: | 
|  | infile.close() | 
|  |  | 
|  | def_file_path = os.path.join( | 
|  | out_dir, os.path.splitext(os.path.basename(module_name))[0] + '.def') | 
|  | outfile = open(def_file_path, 'w') | 
|  |  | 
|  | try: | 
|  | WriteWindowsDefFile(module_name, signatures, outfile) | 
|  | finally: | 
|  | outfile.close() | 
|  |  | 
|  |  | 
|  | def CreatePosixStubsForSigFiles(sig_files, stub_name, out_dir, | 
|  | intermediate_dir, path_from_source, | 
|  | extra_stub_header, export_macro): | 
|  | """Create a posix stub library with a module for each signature file. | 
|  |  | 
|  | Args: | 
|  | sig_files: Array of strings with the paths to each signature file. | 
|  | stub_name: String with the basename of the generated stub file. | 
|  | out_dir: String holding path to directory for the .h files. | 
|  | intermediate_dir: String holding path to directory for the .cc files. | 
|  | path_from_source: String with relative path of generated files from the | 
|  | project root. | 
|  | extra_stub_header: String with path to file of extra lines to insert | 
|  | into the generated header for the stub library. | 
|  | export_macro: A preprocessor macro used to annotate stub symbols with | 
|  | an EXPORT marking, to control visibility. | 
|  | """ | 
|  | header_base_name = stub_name + '.h' | 
|  | header_path = os.path.join(out_dir, header_base_name) | 
|  | impl_path = os.path.join(intermediate_dir, stub_name + '.cc') | 
|  |  | 
|  | module_names = [ExtractModuleName(path) for path in sig_files] | 
|  | namespace = path_from_source.replace('/', '_').lower() | 
|  | header_guard = '%s_' % namespace.upper() | 
|  | header_include_path = os.path.join(path_from_source, header_base_name) | 
|  |  | 
|  | # First create the implementation file. | 
|  | impl_file = open(impl_path, 'w') | 
|  | try: | 
|  | # Open the file, and create the preamble which consists of a file | 
|  | # header plus any necessary includes. | 
|  | PosixStubWriter.WriteImplementationPreamble(header_include_path, | 
|  | impl_file) | 
|  | if extra_stub_header is not None: | 
|  | extra_header_file = open(extra_stub_header, 'r') | 
|  | try: | 
|  | impl_file.write('\n') | 
|  | for line in extra_header_file: | 
|  | impl_file.write(line) | 
|  | impl_file.write('\n') | 
|  | finally: | 
|  | extra_header_file.close() | 
|  |  | 
|  | # For each signature file, generate the stub population functions | 
|  | # for that file.  Each file represents one module. | 
|  | for input_path in sig_files: | 
|  | name = ExtractModuleName(input_path) | 
|  | infile = open(input_path, 'r') | 
|  | try: | 
|  | signatures = ParseSignatures(infile) | 
|  | finally: | 
|  | infile.close() | 
|  | writer = PosixStubWriter(name, export_macro, signatures) | 
|  | writer.WriteImplementationContents(namespace, impl_file) | 
|  |  | 
|  | # Lastly, output the umbrella function for the file. | 
|  | PosixStubWriter.WriteUmbrellaInitializer(module_names, namespace, | 
|  | impl_file) | 
|  | finally: | 
|  | impl_file.close() | 
|  |  | 
|  | # Then create the associated header file. | 
|  | header_file = open(header_path, 'w') | 
|  | try: | 
|  | PosixStubWriter.WriteHeaderContents(module_names, namespace, | 
|  | header_guard, header_file) | 
|  | finally: | 
|  | header_file.close() | 
|  |  | 
|  |  | 
|  | def main(): | 
|  | options, args = ParseOptions() | 
|  | out_dir, intermediate_dir = CreateOutputDirectories(options) | 
|  |  | 
|  | if options.type == FILE_TYPE_WIN_X86: | 
|  | CreateWindowsLibForSigFiles(args, out_dir, intermediate_dir, 'X86', | 
|  | options.export_macro) | 
|  | elif options.type == FILE_TYPE_WIN_X64: | 
|  | CreateWindowsLibForSigFiles(args, out_dir, intermediate_dir, 'X64', | 
|  | options.export_macro) | 
|  | elif options.type == FILE_TYPE_POSIX_STUB: | 
|  | CreatePosixStubsForSigFiles(args, options.stubfile_name, out_dir, | 
|  | intermediate_dir, options.path_from_source, | 
|  | options.extra_stub_header, options.export_macro) | 
|  | elif options.type == FILE_TYPE_WIN_DEF: | 
|  | CreateWindowsDefForSigFiles(args, out_dir, options.module_name) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | main() |