15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Creates windows and posix stub files for a given set of signatures.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)For libraries that need to be loaded outside of the standard executable startup
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)path mechanism, stub files need to be generated for the wanted functions.  In
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)windows, this is done via "def" files and the delay load mechanism.  On a posix
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)system, a set of stub functions need to be generated that dispatch to functions
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)found via dlsym.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This script takes a set of files, where each file is a list of C-style
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)signatures (one signature per line).  The output is either a windows def file,
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)or a header + implementation file of stubs suitable for use in a posix system.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This script also handles varidiac functions, e.g.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void printf(const char* s, ...);
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TODO(hclam): Fix the situation for varidiac functions.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Stub for the above function will be generated and inside the stub function it
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)is translated to:
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void printf(const char* s, ...) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf_ptr(s, (void*)arg1);
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Only one argument from the varidiac arguments is used and it will be used as
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)type void*.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)__author__ = 'ajwong@chromium.org (Albert J. Wong)'
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import optparse
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import string
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Error(Exception):
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pass
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BadSignatureError(Error):
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pass
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SubprocessError(Error):
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, message, error_code):
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Error.__init__(self)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.message = message
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.error_code = error_code
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __str__(self):
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'Failed with code %s: %s' % (self.message, repr(self.error_code))
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Regular expression used to parse function signatures in the input files.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The regex is built around identifying the "identifier" for the function name.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# We consider the identifier to be the string that follows these constraints:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   1) Starts with [_a-ZA-Z] (C++ spec 2.10).
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   2) Continues with [_a-ZA-Z0-9] (C++ spec 2.10).
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   3) Preceeds an opening parenthesis by 0 or more whitespace chars.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# From that, all preceeding characters are considered the return value.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Trailing characters should have a substring matching the form (.*).  That
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# is considered the arguments.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SIGNATURE_REGEX = re.compile('(?P<return_type>.+?)'
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             '(?P<name>[_a-zA-Z][_a-zA-Z0-9]+)\s*'
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             '\((?P<params>.*?)\)')
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Used for generating C++ identifiers.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)INVALID_C_IDENT_CHARS = re.compile('[^_a-zA-Z0-9]')
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Constants defning the supported file types options.
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FILE_TYPE_WIN_X86 = 'windows_lib'
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FILE_TYPE_WIN_X64 = 'windows_lib_x64'
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FILE_TYPE_POSIX_STUB = 'posix_stubs'
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FILE_TYPE_WIN_DEF = 'windows_def'
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template for generating a stub function definition.  Includes a forward
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# declaration marking the symbol as weak.  This template takes the following
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# named parameters.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   return_type: The return type.
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#   export: The macro used to alter the stub's visibility.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   name: The name of the function.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   params: The parameters to the function.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   return_prefix: 'return ' if this function is not void. '' otherwise.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   arg_list: The arguments used to call the stub function.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STUB_FUNCTION_DEFINITION = (
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """extern %(return_type)s %(name)s(%(params)s) __attribute__((weak));
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)%(return_type)s %(export)s %(name)s(%(params)s) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  %(return_prefix)s%(name)s_ptr(%(arg_list)s);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}""")
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template for generating a variadic stub function definition with return
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# value.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Includes a forward declaration marking the symbol as weak.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This template takes the following named parameters.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   return_type: The return type.
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#   export: The macro used to alter the stub's visibility.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   name: The name of the function.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   params: The parameters to the function.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   arg_list: The arguments used to call the stub function without the
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#             variadic argument.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   last_named_arg: Name of the last named argument before the variadic
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#                   argument.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VARIADIC_STUB_FUNCTION_DEFINITION = (
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """extern %(return_type)s %(name)s(%(params)s) __attribute__((weak));
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)%(return_type)s %(export)s %(name)s(%(params)s) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_list args___;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_start(args___, %(last_named_arg)s);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  %(return_type)s ret___ = %(name)s_ptr(%(arg_list)s, va_arg(args___, void*));
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_end(args___);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret___;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}""")
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template for generating a variadic stub function definition without
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# return value.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Includes a forward declaration marking the symbol as weak.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This template takes the following named parameters.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   name: The name of the function.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   params: The parameters to the function.
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#   export: The macro used to alter the stub's visibility.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   arg_list: The arguments used to call the stub function without the
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#             variadic argument.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   last_named_arg: Name of the last named argument before the variadic
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#                   argument.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VOID_VARIADIC_STUB_FUNCTION_DEFINITION = (
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """extern void %(name)s(%(params)s) __attribute__((weak));
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void %(export)s %(name)s(%(params)s) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_list args___;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_start(args___, %(last_named_arg)s);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  %(name)s_ptr(%(arg_list)s, va_arg(args___, void*));
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_end(args___);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}""")
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template for the preamble for the stub header file with the header guards,
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# standard set of includes, and namespace opener.  This template takes the
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# following named parameters:
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   guard_name: The macro to use as the header guard.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   namespace: The namespace for the stub functions.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STUB_HEADER_PREAMBLE = """// This is generated file. Do not modify directly.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef %(guard_name)s
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define %(guard_name)s
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace %(namespace)s {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template for the end of the stub header. This closes the namespace and the
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# header guards.  This template takes the following named parameters:
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   guard_name: The macro to use as the header guard.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   namespace: The namespace for the stub functions.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STUB_HEADER_CLOSER = """}  // namespace %(namespace)s
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // %(guard_name)s
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The standard includes needed for the stub implementation file.  Takes one
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# string substition with the path to the associated stub header file.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IMPLEMENTATION_PREAMBLE = """// This is generated file. Do not modify directly.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "%s"
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>  // For NULL.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <dlfcn.h>   // For dysym, dlopen.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The start and end templates for the enum definitions used by the Umbrella
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# initializer.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UMBRELLA_ENUM_START = """// Enum and typedef for umbrella initializer.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum StubModules {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UMBRELLA_ENUM_END = """  kNumStubModules
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Start and end of the extern "C" section for the implementation contents.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IMPLEMENTATION_CONTENTS_C_START = """extern "C" {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IMPLEMENTATION_CONTENTS_C_END = """
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // extern "C"
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Templates for the start and end of a namespace.  Takes one parameter, the
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# namespace name.
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NAMESPACE_START = """namespace %s {
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NAMESPACE_END = """}  // namespace %s
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Comment to include before the section declaring all the function pointers
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# used by the stub functions.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FUNCTION_POINTER_SECTION_COMMENT = (
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """// Static pointers that will hold the location of the real function
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// implementations after the module has been loaded.
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template for the module initialization check function.  This template
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# takes two parameteres: the function name, and the conditional used to
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# verify the module's initialization.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MODULE_INITIALIZATION_CHECK_FUNCTION = (
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """// Returns true if all stubs have been properly initialized.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool %s() {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (%s) {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template for the line that initialize the stub pointer.  This template takes
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the following named parameters:
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   name: The name of the function.
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   return_type: The return type.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   params: The parameters to the function.
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STUB_POINTER_INITIALIZER = """  %(name)s_ptr =
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reinterpret_cast<%(return_type)s (*)(%(parameters)s)>(
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dlsym(module, "%(name)s"));
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG_IF(1, !%(name)s_ptr) << "Couldn't load %(name)s, dlerror() says:\\n"
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << dlerror();
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template for module initializer function start and end.  This template takes
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# one parameter which is the initializer function name.
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MODULE_INITIALIZE_START = """// Initializes the module stubs.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void %s(void* module) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MODULE_INITIALIZE_END = """}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template for module uninitializer function start and end.  This template
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# takes one parameter which is the initializer function name.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MODULE_UNINITIALIZE_START = (
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """// Uninitialize the module stubs.  Reset pointers to NULL.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void %s() {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MODULE_UNINITIALIZE_END = """}
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Open namespace and add typedef for internal data structures used by the
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# umbrella initializer.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UMBRELLA_INITIALIZER_START = """namespace %s {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef std::map<StubModules, void*> StubHandleMap;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Function close DSOs on error and clean up dangling references.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UMBRELLA_INITIALIZER_CLEANUP_FUNCTION = (
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """static void CloseLibraries(StubHandleMap* stub_handles) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (StubHandleMap::const_iterator it = stub_handles->begin();
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != stub_handles->end();
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it) {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dlclose(it->second);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stub_handles->clear();
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Function to initialize each DSO for the given paths.
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UMBRELLA_INITIALIZER_INITIALIZE_FUNCTION_START = (
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """bool InitializeStubs(const StubPathMap& path_map) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StubHandleMap opened_libraries;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < kNumStubModules; ++i) {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StubModules cur_module = static_cast<StubModules>(i);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If a module is missing, we fail.
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StubPathMap::const_iterator it = path_map.find(cur_module);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it == path_map.end()) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CloseLibraries(&opened_libraries);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Otherwise, attempt to dlopen the library.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<std::string>& paths = it->second;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool module_opened = false;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<std::string>::const_iterator dso_path = paths.begin();
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         !module_opened && dso_path != paths.end();
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         ++dso_path) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      void* handle = dlopen(dso_path->c_str(), RTLD_LAZY);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (handle != NULL) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        module_opened = true;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        opened_libraries[cur_module] = handle;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VLOG(1) << "dlopen(" << dso_path->c_str() << ") failed, "
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                << "dlerror() says:\\n" << dlerror();
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!module_opened) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CloseLibraries(&opened_libraries);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template to generate code to check if each module initializer correctly
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# completed, and cleanup on failures.  This template takes the following
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# named parameters.
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   conditional: The conditional expression for successful initialization.
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   uninitializers: The statements needed to uninitialize the modules.
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UMBRELLA_INITIALIZER_CHECK_AND_CLEANUP = (
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """  // Check that each module is initialized correctly.
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close all previously opened libraries on failure.
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (%(conditional)s) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    %(uninitializers)s;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseLibraries(&opened_libraries);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template for Initialize, Unininitialize, and IsInitialized functions for each
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# module.  This template takes the following named parameters:
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   initialize: Name of the Initialize function.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   uninitialize: Name of the Uninitialize function.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   is_initialized: Name of the IsInitialized function.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MODULE_FUNCTION_PROTOTYPES = """bool %(is_initialized)s();
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void %(initialize)s(void* module);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void %(uninitialize)s();
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Template for umbrella initializer declaration and associated datatypes.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UMBRELLA_INITIALIZER_PROTOTYPE = (
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """typedef std::map<StubModules, std::vector<std::string> > StubPathMap;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Umbrella initializer for all the modules in this stub file.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InitializeStubs(const StubPathMap& path_map);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractModuleName(infile_path):
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Infers the module name from the input file path.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The input filename is supposed to be in the form "ModuleName.sigs".
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  This function splits the filename from the extention on that basename of
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  the path and returns that as the module name.
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    infile_path: String holding the path to the input file.
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The module name as a string.
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  basename = os.path.basename(infile_path)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # This loop continously removes suffixes of the filename separated by a "."
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # character.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while 1:
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_basename = os.path.splitext(basename)[0]
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if basename == new_basename:
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      basename = new_basename
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return basename
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ParseSignatures(infile):
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Parses function signatures in the input file.
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  This function parses a file of signatures into a list of dictionaries that
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  represent the function signatures in the input file.  Each dictionary has
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  the following keys:
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_type: A string with the return type.
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name: A string with the name of the function.
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params: A list of each function parameter declaration (type + name)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The format of the input file is one C-style function signature per line, no
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  trailing semicolon.  Empty lines are allowed.  An empty line is a line that
396f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  consists purely of whitespace.  Lines that begin with a # or // are considered
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  comment lines and are ignored.
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  We assume that "int foo(void)" is the same as "int foo()", which is not
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  true in C where "int foo()" is equivalent to "int foo(...)".  Our generated
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  code is C++, and we do not handle varargs, so this is a case that can be
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ignored for now.
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    infile: File object holding a text file of function signatures.
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    A list of dictionaries, where each dictionary represents one function
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signature.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Raises:
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BadSignatureError: A line could not be parsed as a signature.
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signatures = []
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in infile:
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    line = line.strip()
417f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if line and line[0] != '#' and line[0:2] != '//':
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      m = SIGNATURE_REGEX.match(line)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if m is None:
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise BadSignatureError('Unparsable line: %s' % line)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      signatures.append(
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          {'return_type': m.group('return_type').strip(),
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'name': m.group('name').strip(),
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'params': [arg.strip() for arg in m.group('params').split(',')]})
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return signatures
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def WriteWindowsDefFile(module_name, signatures, outfile):
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Writes a windows def file to the given output file object.
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The def file format is basically a list of function names.  Generation is
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    simple.  After outputting the LIBRARY and EXPORTS lines, print out each
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function name, one to a line, preceeded by 2 spaces.
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    module_name: The name of the module we are writing a stub for.
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signatures: The list of signature hashes, as produced by ParseSignatures,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                to create stubs for.
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile: File handle to populate with definitions.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  outfile.write('LIBRARY %s\n' % module_name)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  outfile.write('EXPORTS\n')
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for sig in signatures:
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write('  %s\n' % sig['name'])
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def QuietRun(args, filter=None, write_to=sys.stdout):
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Invoke |args| as command via subprocess.Popen, filtering lines starting
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  with |filter|."""
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  popen = subprocess.Popen(args, stdout=subprocess.PIPE)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out, _ = popen.communicate()
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in out.splitlines():
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not filter or not line.startswith(filter):
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      write_to.write(line + '\n')
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return popen.returncode
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def CreateWindowsLib(module_name, signatures, intermediate_dir, outdir_path,
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     machine):
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Creates a windows library file.
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Calling this function will create a lib file in the outdir_path that exports
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  the signatures passed into the object.  A temporary def file will be created
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  in the intermediate_dir.
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    module_name: The name of the module we are writing a stub for.
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signatures: The list of signature hashes, as produced by ParseSignatures,
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                to create stubs for.
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    intermediate_dir: The directory where the generated .def files should go.
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outdir_path: The directory where generated .lib files should go.
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    machine: String holding the machine type, 'X86' or 'X64'.
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Raises:
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SubprocessError: If invoking the windows "lib" tool fails, this is raised
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     with the error code.
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def_file_path = os.path.join(intermediate_dir,
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               module_name + '.def')
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lib_file_path = os.path.join(outdir_path,
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               module_name + '.lib')
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  outfile = open(def_file_path, 'w')
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WriteWindowsDefFile(module_name, signatures, outfile)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  finally:
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.close()
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Invoke the "lib" program on Windows to create stub .lib files for the
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # generated definitions.  These .lib files can then be used during
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # delayloading of the dynamic libraries.
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ret = QuietRun(['lib', '/nologo',
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  '/machine:' + machine,
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  '/def:' + def_file_path,
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  '/out:' + lib_file_path],
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 filter='   Creating library')
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ret != 0:
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise SubprocessError(
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Failed creating %s for %s' % (lib_file_path, def_file_path),
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PosixStubWriter(object):
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Creates a file of stub functions for a library that is opened via dlopen.
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Windows provides a function in their compiler known as delay loading, which
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  effectively generates a set of stub functions for a dynamic library that
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delays loading of the dynamic library/resolution of the symbols until one of
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  the needed functions are accessed.
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  In posix, RTLD_LAZY does something similar with DSOs.  This is the default
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  link mode for DSOs.  However, even though the symbol is not resolved until
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  first usage, the DSO must be present at load time of the main binary.
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  To simulate the windows delay load procedure, we need to create a set of
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stub functions that allow for correct linkage of the main binary, but
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dispatch to the dynamically resolved symbol when the module is initialized.
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  This class takes a list of function signatures, and generates a set of stub
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  functions plus initialization code for them.
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def __init__(self, module_name, export_macro, signatures):
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Initializes PosixStubWriter for this set of signatures and module_name.
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      module_name: The name of the module we are writing a stub for.
5285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      export_macro: A preprocessor macro used to annotate stub symbols with
5295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    an EXPORT marking, to control visibility.
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      signatures: The list of signature hashes, as produced by ParseSignatures,
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  to create stubs for.
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.signatures = signatures
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.module_name = module_name
5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self.export_macro = export_macro
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @classmethod
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CStyleIdentifier(cls, identifier):
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Generates a C style identifier.
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The module_name has all invalid identifier characters removed (anything
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    that's not [_a-zA-Z0-9]) and is run through string.capwords to try
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    and approximate camel case.
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      identifier: The string with the module name to turn to C-style.
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A string that can be used as part of a C identifier.
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return string.capwords(re.sub(INVALID_C_IDENT_CHARS, '', identifier))
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @classmethod
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def EnumName(cls, module_name):
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the enum name for the module.
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Takes the module name and creates a suitable enum name.  The module_name
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is munged to be a valid C identifier then prefixed with the string
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "kModule" to generate a Google style enum name.
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      module_name: The name of the module to generate an enum name for.
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A string with the name of the enum value representing this module.
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'kModule%s' % PosixStubWriter.CStyleIdentifier(module_name)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @classmethod
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsInitializedName(cls, module_name):
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the name of function that checks initialization of this module.
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The name is in the format IsModuleInitialized.  Where "Module" is replaced
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with the module name, munged to be a valid C identifier.
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      module_name: The name of the module to generate the function name for.
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A string with the name of the initialization check function.
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'Is%sInitialized' % PosixStubWriter.CStyleIdentifier(module_name)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @classmethod
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def InitializeModuleName(cls, module_name):
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the name of the function that initializes this module.
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The name is in the format InitializeModule.  Where "Module" is replaced
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with the module name, munged to be a valid C identifier.
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      module_name: The name of the module to generate the function name for.
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A string with the name of the initialization function.
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'Initialize%s' % PosixStubWriter.CStyleIdentifier(module_name)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @classmethod
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def UninitializeModuleName(cls, module_name):
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the name of the function that uninitializes this module.
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The name is in the format UninitializeModule.  Where "Module" is replaced
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with the module name, munged to be a valid C identifier.
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      module_name: The name of the module to generate the function name for.
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A string with the name of the uninitialization function.
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'Uninitialize%s' % PosixStubWriter.CStyleIdentifier(module_name)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @classmethod
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def StubFunctionPointer(cls, signature):
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Generates a function pointer declaration for the given signature.
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      signature: A signature hash, as produced by ParseSignatures,
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 representating the function signature.
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A string with the declaration of the function pointer for the signature.
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'static %s (*%s_ptr)(%s) = NULL;' % (signature['return_type'],
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                signature['name'],
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                ', '.join(signature['params']))
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @classmethod
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def StubFunction(cls, signature):
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Generates a stub function definition for the given signature.
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The function definitions are created with __attribute__((weak)) so that
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    they may be overridden by a real static link or mock versions to be used
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    when testing.
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      signature: A signature hash, as produced by ParseSignatures,
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 representating the function signature.
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A string with the stub function definition.
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_prefix = ''
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if signature['return_type'] != 'void':
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return_prefix = 'return '
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Generate the argument list.
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    arguments = [re.split('[\*& ]', arg)[-1].strip() for arg in
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 signature['params']]
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    arg_list = ', '.join(arguments)
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if arg_list == 'void':
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arg_list = ''
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if arg_list != '' and len(arguments) > 1 and arguments[-1] == '...':
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # If the last argment is ... then this is a variadic function.
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if return_prefix != '':
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return VARIADIC_STUB_FUNCTION_DEFINITION % {
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'return_type': signature['return_type'],
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'name': signature['name'],
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'params': ', '.join(signature['params']),
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'arg_list': ', '.join(arguments[0:-1]),
6635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            'last_named_arg': arguments[-2],
6645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            'export': signature.get('export', '')}
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return VOID_VARIADIC_STUB_FUNCTION_DEFINITION % {
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'name': signature['name'],
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'params': ', '.join(signature['params']),
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'arg_list': ', '.join(arguments[0:-1]),
6705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            'last_named_arg': arguments[-2],
6715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            'export': signature.get('export', '')}
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # This is a regular function.
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return STUB_FUNCTION_DEFINITION % {
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'return_type': signature['return_type'],
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'name': signature['name'],
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'params': ', '.join(signature['params']),
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'return_prefix': return_prefix,
6795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          'arg_list': arg_list,
6805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          'export': signature.get('export', '')}
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @classmethod
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WriteImplementationPreamble(cls, header_path, outfile):
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Write the necessary includes for the implementation file.
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      header_path: The path to the header file.
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile: The file handle to populate.
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(IMPLEMENTATION_PREAMBLE % header_path)
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @classmethod
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WriteUmbrellaInitializer(cls, module_names, namespace, outfile):
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Writes a single function that will open + initialize each module.
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This intializer will take in an stl map of that lists the correct
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dlopen target for each module.  The map type is
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::map<enum StubModules, vector<std::string>> which matches one module
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to a list of paths to try in dlopen.
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This function is an all-or-nothing function.  If any module fails to load,
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all other modules are dlclosed, and the function returns.  Though it is
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    not enforced, this function should only be called once.
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      module_names: A list with the names of the modules in this stub file.
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      namespace: The namespace these functions should be in.
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile: The file handle to populate with pointer definitions.
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(UMBRELLA_INITIALIZER_START % namespace)
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(UMBRELLA_INITIALIZER_CLEANUP_FUNCTION)
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Create the initializaiton function that calls all module initializers,
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # checks if they succeeded, and backs out module loads on an error.
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(UMBRELLA_INITIALIZER_INITIALIZE_FUNCTION_START)
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '\n  // Initialize each module if we have not already failed.\n')
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for module in module_names:
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile.write('  %s(opened_libraries[%s]);\n' %
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    (PosixStubWriter.InitializeModuleName(module),
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     PosixStubWriter.EnumName(module)))
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write('\n')
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Output code to check the initialization status, clean up on error.
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initializer_checks = ['!%s()' % PosixStubWriter.IsInitializedName(name)
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          for name in module_names]
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uninitializers = ['%s()' % PosixStubWriter.UninitializeModuleName(name)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      for name in module_names]
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(UMBRELLA_INITIALIZER_CHECK_AND_CLEANUP % {
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'conditional': ' ||\n      '.join(initializer_checks),
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'uninitializers': ';\n    '.join(uninitializers)})
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write('\n}  // namespace %s\n' % namespace)
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @classmethod
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WriteHeaderContents(cls, module_names, namespace, header_guard, outfile):
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Writes a header file for the stub file generated for module_names.
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The header file exposes the following:
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       1) An enum, StubModules, listing with an entry for each enum.
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       2) A typedef for a StubPathMap allowing for specification of paths to
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          search for each module.
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       3) The IsInitialized/Initialize/Uninitialize functions for each module.
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       4) An umbrella initialize function for all modules.
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      module_names: A list with the names of each module in this stub file.
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      namespace: The namespace these functions should be in.
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      header_guard: The macro to use as our header guard.
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile: The output handle to populate.
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(STUB_HEADER_PREAMBLE %
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  {'guard_name': header_guard, 'namespace': namespace})
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Generate the Initializer protoypes for each module.
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write('// Individual module initializer functions.\n')
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for name in module_names:
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile.write(MODULE_FUNCTION_PROTOTYPES % {
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'is_initialized': PosixStubWriter.IsInitializedName(name),
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'initialize': PosixStubWriter.InitializeModuleName(name),
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'uninitialize': PosixStubWriter.UninitializeModuleName(name)})
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Generate the enum for umbrella initializer.
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(UMBRELLA_ENUM_START)
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write('  %s = 0,\n' % PosixStubWriter.EnumName(module_names[0]))
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for name in module_names[1:]:
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile.write('  %s,\n' % PosixStubWriter.EnumName(name))
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(UMBRELLA_ENUM_END)
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(UMBRELLA_INITIALIZER_PROTOTYPE)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(STUB_HEADER_CLOSER % {
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'namespace': namespace, 'guard_name':
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        header_guard})
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WriteImplementationContents(self, namespace, outfile):
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Given a file handle, write out the stub definitions for this module.
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      namespace: The namespace these functions should be in.
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile: The file handle to populate.
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(IMPLEMENTATION_CONTENTS_C_START)
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WriteFunctionPointers(outfile)
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WriteStubFunctions(outfile)
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(IMPLEMENTATION_CONTENTS_C_END)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(NAMESPACE_START % namespace)
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WriteModuleInitializeFunctions(outfile)
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(NAMESPACE_END % namespace)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WriteFunctionPointers(self, outfile):
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Write the function pointer declarations needed by the stubs.
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    We need function pointers to hold the actual location of the function
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    implementation returned by dlsym.  This function outputs a pointer
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    definition for each signature in the module.
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Pointers will be named with the following pattern "FuntionName_ptr".
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile: The file handle to populate with pointer definitions.
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(FUNCTION_POINTER_SECTION_COMMENT)
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for sig in self.signatures:
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile.write('%s\n' % PosixStubWriter.StubFunctionPointer(sig))
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write('\n')
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WriteStubFunctions(self, outfile):
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Write the function stubs to handle dispatching to real implementations.
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Functions that have a return type other than void will look as follows:
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReturnType FunctionName(A a) {
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return FunctionName_ptr(a);
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Functions with a return type of void will look as follows:
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      void FunctionName(A a) {
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FunctionName_ptr(a);
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile: The file handle to populate.
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write('// Stubs that dispatch to the real implementations.\n')
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for sig in self.signatures:
8285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      sig['export'] = self.export_macro
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile.write('%s\n' % PosixStubWriter.StubFunction(sig))
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WriteModuleInitializeFunctions(self, outfile):
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Write functions to initialize/query initlialization of the module.
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This creates 2 functions IsModuleInitialized and InitializeModule where
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Module" is replaced with the module name, first letter capitalized.
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The InitializeModule function takes a handle that is retrieved from dlopen
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    and attempts to assign each function pointer above via dlsym.
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The IsModuleInitialized returns true if none of the required functions
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pointers are NULL.
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile: The file handle to populate.
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ptr_names = ['%s_ptr' % sig['name'] for sig in self.signatures]
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Construct the conditional expression to check the initialization of
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # all the function pointers above.  It should generate a conjuntion
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # with each pointer on its own line, indented by six spaces to match
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # the indentation level of MODULE_INITIALIZATION_CHECK_FUNCTION.
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initialization_conditional = ' &&\n      '.join(ptr_names)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(MODULE_INITIALIZATION_CHECK_FUNCTION % (
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PosixStubWriter.IsInitializedName(self.module_name),
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        initialization_conditional))
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Create function that initializes the module.
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(MODULE_INITIALIZE_START %
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  PosixStubWriter.InitializeModuleName(self.module_name))
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for sig in self.signatures:
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile.write(STUB_POINTER_INITIALIZER % {
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'name': sig['name'],
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'return_type': sig['return_type'],
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'parameters': ', '.join(sig['params'])})
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(MODULE_INITIALIZE_END)
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Create function that uninitializes the module (sets all pointers to
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # NULL).
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(MODULE_UNINITIALIZE_START %
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  PosixStubWriter.UninitializeModuleName(self.module_name))
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for sig in self.signatures:
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outfile.write('  %s_ptr = NULL;\n' % sig['name'])
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(MODULE_UNINITIALIZE_END)
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CreateOptionParser():
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Creates an OptionParser for the configuration options of script.
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    A OptionParser object.
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser = optparse.OptionParser(usage='usage: %prog [options] input')
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-o',
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    '--output',
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    dest='out_dir',
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    default=None,
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='Output location.')
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-i',
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    '--intermediate_dir',
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    dest='intermediate_dir',
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    default=None,
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help=('Location of intermediate files. Ignored for %s type'
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          % FILE_TYPE_WIN_DEF))
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-t',
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    '--type',
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    dest='type',
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    default=None,
8992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    help=('Type of file. Valid types are "%s" or "%s" or "%s" '
9002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          'or "%s"' %
9012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          (FILE_TYPE_POSIX_STUB, FILE_TYPE_WIN_X86,
9022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           FILE_TYPE_WIN_X64, FILE_TYPE_WIN_DEF)))
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-s',
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    '--stubfile_name',
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    dest='stubfile_name',
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    default=None,
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help=('Name of posix_stubs output file. Only valid with '
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          '%s type.' % FILE_TYPE_POSIX_STUB))
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-p',
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    '--path_from_source',
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    dest='path_from_source',
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    default=None,
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help=('The relative path from the project root that the '
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          'generated file should consider itself part of (eg. '
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          'third_party/ffmpeg).  This is used to generate the '
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          'header guard and namespace for our initializer '
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          'functions and does NOT affect the physical output '
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          'location of the file like -o does.  Ignored for '
9192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          '%s and %s types.' %
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          (FILE_TYPE_WIN_X86, FILE_TYPE_WIN_X64)))
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-e',
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    '--extra_stub_header',
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    dest='extra_stub_header',
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    default=None,
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help=('File to insert after the system includes in the '
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          'generated stub implemenation file. Ignored for '
9272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          '%s and %s types.' %
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          (FILE_TYPE_WIN_X86, FILE_TYPE_WIN_X64)))
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-m',
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    '--module_name',
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    dest='module_name',
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    default=None,
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help=('Name of output DLL or LIB for DEF creation using '
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          '%s type.' % FILE_TYPE_WIN_DEF))
9355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  parser.add_option('-x',
9365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    '--export_macro',
9375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    dest='export_macro',
9385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    default='',
9395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    help=('A macro to place between the return type and '
9405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          'function name, e.g. MODULE_EXPORT, to control the '
9415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          'visbility of the stub functions.'))
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return parser
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ParseOptions():
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Parses the options and terminates program if they are not sane.
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The pair (optparse.OptionValues, [string]), that is the output of
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    a successful call to parser.parse_args().
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser = CreateOptionParser()
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options, args = parser.parse_args()
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not args:
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.error('No inputs specified')
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.out_dir is None:
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.error('Output location not specified')
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (options.type not in
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      [FILE_TYPE_WIN_X86, FILE_TYPE_WIN_X64, FILE_TYPE_POSIX_STUB,
9642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       FILE_TYPE_WIN_DEF]):
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.error('Invalid output file type: %s' % options.type)
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.type == FILE_TYPE_POSIX_STUB:
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if options.stubfile_name is None:
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parser.error('Output file name needed for %s' % FILE_TYPE_POSIX_STUB)
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if options.path_from_source is None:
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parser.error('Path from source needed for %s' % FILE_TYPE_POSIX_STUB)
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.type == FILE_TYPE_WIN_DEF:
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if options.module_name is None:
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parser.error('Module name needed for %s' % FILE_TYPE_WIN_DEF)
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return options, args
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def EnsureDirExists(dir):
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Creates a directory. Does not use the more obvious 'if not exists: create'
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  to avoid race with other invocations of the same code, which will error out
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  on makedirs if another invocation has succeeded in creating the directory
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  since the existence check."""
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.makedirs(dir)
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  except:
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not os.path.isdir(dir):
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CreateOutputDirectories(options):
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Creates the intermediate and final output directories.
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Given the parsed options, create the intermediate and final output
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  directories if they do not exist.  Returns the paths to both directories
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  as a pair.
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options: An OptionParser.OptionValues object with the parsed options.
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The pair (out_dir, intermediate_dir), both of which are strings.
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out_dir = os.path.normpath(options.out_dir)
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  intermediate_dir = os.path.normpath(options.intermediate_dir)
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if intermediate_dir is None:
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    intermediate_dir = out_dir
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureDirExists(out_dir)
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureDirExists(intermediate_dir)
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return out_dir, intermediate_dir
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def CreateWindowsLibForSigFiles(sig_files, out_dir, intermediate_dir, machine,
10175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                export_macro):
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """For each signature file, create a windows lib.
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sig_files: Array of strings with the paths to each signature file.
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out_dir: String holding path to directory where the generated libs go.
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    intermediate_dir: String holding path to directory generated intermdiate
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      artifacts.
10252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    machine: String holding the machine type, 'X86' or 'X64'.
10265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    export_macro: A preprocessor macro used to annotate stub symbols with
10275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                  an EXPORT marking, to control visibility.
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for input_path in sig_files:
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    infile = open(input_path, 'r')
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      signatures = ParseSignatures(infile)
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      module_name = ExtractModuleName(os.path.basename(input_path))
10345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      for sig in signatures:
10355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        sig['export'] = export_macro
10362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CreateWindowsLib(module_name, signatures, intermediate_dir, out_dir,
10372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       machine)
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    finally:
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      infile.close()
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CreateWindowsDefForSigFiles(sig_files, out_dir, module_name):
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """For all signature files, create a single windows def file.
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sig_files: Array of strings with the paths to each signature file.
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out_dir: String holding path to directory where the generated def goes.
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    module_name: Name of the output DLL or LIB which will link in the def file.
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signatures = []
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for input_path in sig_files:
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    infile = open(input_path, 'r')
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      signatures += ParseSignatures(infile)
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    finally:
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      infile.close()
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def_file_path = os.path.join(
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      out_dir, os.path.splitext(os.path.basename(module_name))[0] + '.def')
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  outfile = open(def_file_path, 'w')
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WriteWindowsDefFile(module_name, signatures, outfile)
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  finally:
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.close()
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CreatePosixStubsForSigFiles(sig_files, stub_name, out_dir,
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                intermediate_dir, path_from_source,
10705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                extra_stub_header, export_macro):
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Create a posix stub library with a module for each signature file.
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sig_files: Array of strings with the paths to each signature file.
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stub_name: String with the basename of the generated stub file.
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out_dir: String holding path to directory for the .h files.
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    intermediate_dir: String holding path to directory for the .cc files.
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path_from_source: String with relative path of generated files from the
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      project root.
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extra_stub_header: String with path to file of extra lines to insert
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       into the generated header for the stub library.
10825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    export_macro: A preprocessor macro used to annotate stub symbols with
10835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                  an EXPORT marking, to control visibility.
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header_base_name = stub_name + '.h'
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header_path = os.path.join(out_dir, header_base_name)
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  impl_path = os.path.join(intermediate_dir, stub_name + '.cc')
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  module_names = [ExtractModuleName(path) for path in sig_files]
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  namespace = path_from_source.replace('/', '_').lower()
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header_guard = '%s_' % namespace.upper()
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header_include_path = os.path.join(path_from_source, header_base_name)
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # First create the implementation file.
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  impl_file = open(impl_path, 'w')
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Open the file, and create the preamble which consists of a file
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # header plus any necessary includes.
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PosixStubWriter.WriteImplementationPreamble(header_include_path,
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                impl_file)
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if extra_stub_header is not None:
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extra_header_file = open(extra_stub_header, 'r')
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      try:
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        impl_file.write('\n')
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for line in extra_header_file:
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          impl_file.write(line)
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        impl_file.write('\n')
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      finally:
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extra_header_file.close()
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # For each signature file, generate the stub population functions
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # for that file.  Each file represents one module.
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for input_path in sig_files:
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name = ExtractModuleName(input_path)
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      infile = open(input_path, 'r')
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      try:
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        signatures = ParseSignatures(infile)
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      finally:
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        infile.close()
11205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      writer = PosixStubWriter(name, export_macro, signatures)
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      writer.WriteImplementationContents(namespace, impl_file)
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Lastly, output the umbrella function for the file.
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PosixStubWriter.WriteUmbrellaInitializer(module_names, namespace,
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             impl_file)
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  finally:
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    impl_file.close()
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Then create the associated header file.
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header_file = open(header_path, 'w')
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PosixStubWriter.WriteHeaderContents(module_names, namespace,
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        header_guard, header_file)
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  finally:
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header_file.close()
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main():
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options, args = ParseOptions()
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out_dir, intermediate_dir = CreateOutputDirectories(options)
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if options.type == FILE_TYPE_WIN_X86:
11435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CreateWindowsLibForSigFiles(args, out_dir, intermediate_dir, 'X86',
11445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                options.export_macro)
11452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  elif options.type == FILE_TYPE_WIN_X64:
11465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CreateWindowsLibForSigFiles(args, out_dir, intermediate_dir, 'X64',
11475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                options.export_macro)
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif options.type == FILE_TYPE_POSIX_STUB:
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreatePosixStubsForSigFiles(args, options.stubfile_name, out_dir,
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                intermediate_dir, options.path_from_source,
11515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                options.extra_stub_header, options.export_macro)
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif options.type == FILE_TYPE_WIN_DEF:
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreateWindowsDefForSigFiles(args, out_dir, options.module_name)
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  main()
1158