Home | History | Annotate | Download | only in util
      1 # Copyright (c) 2015, Google Inc.
      2 #
      3 # Permission to use, copy, modify, and/or distribute this software for any
      4 # purpose with or without fee is hereby granted, provided that the above
      5 # copyright notice and this permission notice appear in all copies.
      6 #
      7 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     10 # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     12 # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     13 # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     14 
     15 """Enumerates source files for consumption by various build systems."""
     16 
     17 import optparse
     18 import os
     19 import subprocess
     20 import sys
     21 import json
     22 
     23 
     24 # OS_ARCH_COMBOS maps from OS and platform to the OpenSSL assembly "style" for
     25 # that platform and the extension used by asm files.
     26 OS_ARCH_COMBOS = [
     27     ('linux', 'arm', 'linux32', [], 'S'),
     28     ('linux', 'aarch64', 'linux64', [], 'S'),
     29     ('linux', 'ppc64le', 'ppc64le', [], 'S'),
     30     ('linux', 'x86', 'elf', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'),
     31     ('linux', 'x86_64', 'elf', [], 'S'),
     32     ('mac', 'x86', 'macosx', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'),
     33     ('mac', 'x86_64', 'macosx', [], 'S'),
     34     ('win', 'x86', 'win32n', ['-DOPENSSL_IA32_SSE2'], 'asm'),
     35     ('win', 'x86_64', 'nasm', [], 'asm'),
     36 ]
     37 
     38 # NON_PERL_FILES enumerates assembly files that are not processed by the
     39 # perlasm system.
     40 NON_PERL_FILES = {
     41     ('linux', 'arm'): [
     42         'src/crypto/curve25519/asm/x25519-asm-arm.S',
     43         'src/crypto/poly1305/poly1305_arm_asm.S',
     44     ],
     45     ('linux', 'x86_64'): [
     46         'src/crypto/curve25519/asm/x25519-asm-x86_64.S',
     47     ],
     48     ('mac', 'x86_64'): [
     49         'src/crypto/curve25519/asm/x25519-asm-x86_64.S',
     50     ],
     51 }
     52 
     53 PREFIX = None
     54 
     55 
     56 def PathOf(x):
     57   return x if not PREFIX else os.path.join(PREFIX, x)
     58 
     59 
     60 class Android(object):
     61 
     62   def __init__(self):
     63     self.header = \
     64 """# Copyright (C) 2015 The Android Open Source Project
     65 #
     66 # Licensed under the Apache License, Version 2.0 (the "License");
     67 # you may not use this file except in compliance with the License.
     68 # You may obtain a copy of the License at
     69 #
     70 #      http://www.apache.org/licenses/LICENSE-2.0
     71 #
     72 # Unless required by applicable law or agreed to in writing, software
     73 # distributed under the License is distributed on an "AS IS" BASIS,
     74 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     75 # See the License for the specific language governing permissions and
     76 # limitations under the License.
     77 
     78 # This file is created by generate_build_files.py. Do not edit manually.
     79 
     80 """
     81 
     82   def PrintVariableSection(self, out, name, files):
     83     out.write('%s := \\\n' % name)
     84     for f in sorted(files):
     85       out.write('  %s\\\n' % f)
     86     out.write('\n')
     87 
     88   def WriteFiles(self, files, asm_outputs):
     89     # New Android.bp format
     90     with open('sources.bp', 'w+') as blueprint:
     91       blueprint.write(self.header.replace('#', '//'))
     92 
     93       blueprint.write('cc_defaults {\n')
     94       blueprint.write('    name: "libcrypto_sources",\n')
     95       blueprint.write('    srcs: [\n')
     96       for f in sorted(files['crypto']):
     97         blueprint.write('        "%s",\n' % f)
     98       blueprint.write('    ],\n')
     99       blueprint.write('    target: {\n')
    100 
    101       for ((osname, arch), asm_files) in asm_outputs:
    102         if osname != 'linux' or arch == 'ppc64le':
    103           continue
    104         if arch == 'aarch64':
    105           arch = 'arm64'
    106 
    107         blueprint.write('        android_%s: {\n' % arch)
    108         blueprint.write('            srcs: [\n')
    109         for f in sorted(asm_files):
    110           blueprint.write('                "%s",\n' % f)
    111         blueprint.write('            ],\n')
    112         blueprint.write('        },\n')
    113 
    114         if arch == 'x86' or arch == 'x86_64':
    115           blueprint.write('        linux_%s: {\n' % arch)
    116           blueprint.write('            srcs: [\n')
    117           for f in sorted(asm_files):
    118             blueprint.write('                "%s",\n' % f)
    119           blueprint.write('            ],\n')
    120           blueprint.write('        },\n')
    121 
    122       blueprint.write('    },\n')
    123       blueprint.write('}\n\n')
    124 
    125       blueprint.write('cc_defaults {\n')
    126       blueprint.write('    name: "libssl_sources",\n')
    127       blueprint.write('    srcs: [\n')
    128       for f in sorted(files['ssl']):
    129         blueprint.write('        "%s",\n' % f)
    130       blueprint.write('    ],\n')
    131       blueprint.write('}\n\n')
    132 
    133       blueprint.write('cc_defaults {\n')
    134       blueprint.write('    name: "bssl_sources",\n')
    135       blueprint.write('    srcs: [\n')
    136       for f in sorted(files['tool']):
    137         blueprint.write('        "%s",\n' % f)
    138       blueprint.write('    ],\n')
    139       blueprint.write('}\n\n')
    140 
    141       blueprint.write('cc_defaults {\n')
    142       blueprint.write('    name: "boringssl_test_support_sources",\n')
    143       blueprint.write('    srcs: [\n')
    144       for f in sorted(files['test_support']):
    145         blueprint.write('        "%s",\n' % f)
    146       blueprint.write('    ],\n')
    147       blueprint.write('}\n\n')
    148 
    149       blueprint.write('cc_defaults {\n')
    150       blueprint.write('    name: "boringssl_crypto_test_sources",\n')
    151       blueprint.write('    srcs: [\n')
    152       for f in sorted(files['crypto_test']):
    153         blueprint.write('        "%s",\n' % f)
    154       blueprint.write('    ],\n')
    155       blueprint.write('}\n\n')
    156 
    157       blueprint.write('cc_defaults {\n')
    158       blueprint.write('    name: "boringssl_ssl_test_sources",\n')
    159       blueprint.write('    srcs: [\n')
    160       for f in sorted(files['ssl_test']):
    161         blueprint.write('        "%s",\n' % f)
    162       blueprint.write('    ],\n')
    163       blueprint.write('}\n\n')
    164 
    165       blueprint.write('cc_defaults {\n')
    166       blueprint.write('    name: "boringssl_tests_sources",\n')
    167       blueprint.write('    srcs: [\n')
    168       for f in sorted(files['test']):
    169         blueprint.write('        "%s",\n' % f)
    170       blueprint.write('    ],\n')
    171       blueprint.write('}\n')
    172 
    173     # Legacy Android.mk format, only used by Trusty in new branches
    174     with open('sources.mk', 'w+') as makefile:
    175       makefile.write(self.header)
    176 
    177       self.PrintVariableSection(makefile, 'crypto_sources', files['crypto'])
    178 
    179       for ((osname, arch), asm_files) in asm_outputs:
    180         if osname != 'linux':
    181           continue
    182         self.PrintVariableSection(
    183             makefile, '%s_%s_sources' % (osname, arch), asm_files)
    184 
    185 
    186 class Bazel(object):
    187   """Bazel outputs files suitable for including in Bazel files."""
    188 
    189   def __init__(self):
    190     self.firstSection = True
    191     self.header = \
    192 """# This file is created by generate_build_files.py. Do not edit manually.
    193 
    194 """
    195 
    196   def PrintVariableSection(self, out, name, files):
    197     if not self.firstSection:
    198       out.write('\n')
    199     self.firstSection = False
    200 
    201     out.write('%s = [\n' % name)
    202     for f in sorted(files):
    203       out.write('    "%s",\n' % PathOf(f))
    204     out.write(']\n')
    205 
    206   def WriteFiles(self, files, asm_outputs):
    207     with open('BUILD.generated.bzl', 'w+') as out:
    208       out.write(self.header)
    209 
    210       self.PrintVariableSection(out, 'ssl_headers', files['ssl_headers'])
    211       self.PrintVariableSection(
    212           out, 'ssl_internal_headers', files['ssl_internal_headers'])
    213       self.PrintVariableSection(out, 'ssl_sources', files['ssl'])
    214       self.PrintVariableSection(out, 'ssl_c_sources', files['ssl_c'])
    215       self.PrintVariableSection(out, 'ssl_cc_sources', files['ssl_cc'])
    216       self.PrintVariableSection(out, 'crypto_headers', files['crypto_headers'])
    217       self.PrintVariableSection(
    218           out, 'crypto_internal_headers', files['crypto_internal_headers'])
    219       self.PrintVariableSection(out, 'crypto_sources', files['crypto'])
    220       self.PrintVariableSection(out, 'tool_sources', files['tool'])
    221       self.PrintVariableSection(out, 'tool_headers', files['tool_headers'])
    222 
    223       for ((osname, arch), asm_files) in asm_outputs:
    224         self.PrintVariableSection(
    225             out, 'crypto_sources_%s_%s' % (osname, arch), asm_files)
    226 
    227     with open('BUILD.generated_tests.bzl', 'w+') as out:
    228       out.write(self.header)
    229 
    230       out.write('test_support_sources = [\n')
    231       for filename in sorted(files['test_support'] +
    232                              files['test_support_headers'] +
    233                              files['crypto_internal_headers'] +
    234                              files['ssl_internal_headers']):
    235         if os.path.basename(filename) == 'malloc.cc':
    236           continue
    237         out.write('    "%s",\n' % PathOf(filename))
    238 
    239       out.write(']\n\n')
    240 
    241       self.PrintVariableSection(out, 'crypto_test_sources',
    242                                 files['crypto_test'])
    243       self.PrintVariableSection(out, 'ssl_test_sources', files['ssl_test'])
    244 
    245       out.write('def create_tests(copts, crypto, ssl):\n')
    246       name_counts = {}
    247       for test in files['tests']:
    248         name = os.path.basename(test[0])
    249         name_counts[name] = name_counts.get(name, 0) + 1
    250 
    251       first = True
    252       for test in files['tests']:
    253         name = os.path.basename(test[0])
    254         if name_counts[name] > 1:
    255           if '/' in test[1]:
    256             name += '_' + os.path.splitext(os.path.basename(test[1]))[0]
    257           else:
    258             name += '_' + test[1].replace('-', '_')
    259 
    260         if not first:
    261           out.write('\n')
    262         first = False
    263 
    264         src_prefix = 'src/' + test[0]
    265         for src in files['test']:
    266           if src.startswith(src_prefix):
    267             src = src
    268             break
    269         else:
    270           raise ValueError("Can't find source for %s" % test[0])
    271 
    272         out.write('  native.cc_test(\n')
    273         out.write('      name = "%s",\n' % name)
    274         out.write('      size = "small",\n')
    275         out.write('      srcs = ["%s"] + test_support_sources,\n' %
    276             PathOf(src))
    277 
    278         data_files = []
    279         if len(test) > 1:
    280 
    281           out.write('      args = [\n')
    282           for arg in test[1:]:
    283             if '/' in arg:
    284               out.write('          "$(location %s)",\n' %
    285                   PathOf(os.path.join('src', arg)))
    286               data_files.append('src/%s' % arg)
    287             else:
    288               out.write('          "%s",\n' % arg)
    289           out.write('      ],\n')
    290 
    291         out.write('      copts = copts + ["-DBORINGSSL_SHARED_LIBRARY"],\n')
    292 
    293         if len(data_files) > 0:
    294           out.write('      data = [\n')
    295           for filename in data_files:
    296             out.write('          "%s",\n' % PathOf(filename))
    297           out.write('      ],\n')
    298 
    299         if 'ssl/' in test[0]:
    300           out.write('      deps = [\n')
    301           out.write('          crypto,\n')
    302           out.write('          ssl,\n')
    303           out.write('      ],\n')
    304         else:
    305           out.write('      deps = [crypto],\n')
    306         out.write('  )\n')
    307 
    308 
    309 class GN(object):
    310 
    311   def __init__(self):
    312     self.firstSection = True
    313     self.header = \
    314 """# Copyright (c) 2016 The Chromium Authors. All rights reserved.
    315 # Use of this source code is governed by a BSD-style license that can be
    316 # found in the LICENSE file.
    317 
    318 # This file is created by generate_build_files.py. Do not edit manually.
    319 
    320 """
    321 
    322   def PrintVariableSection(self, out, name, files):
    323     if not self.firstSection:
    324       out.write('\n')
    325     self.firstSection = False
    326 
    327     out.write('%s = [\n' % name)
    328     for f in sorted(files):
    329       out.write('  "%s",\n' % f)
    330     out.write(']\n')
    331 
    332   def WriteFiles(self, files, asm_outputs):
    333     with open('BUILD.generated.gni', 'w+') as out:
    334       out.write(self.header)
    335 
    336       self.PrintVariableSection(out, 'crypto_sources',
    337                                 files['crypto'] + files['crypto_headers'] +
    338                                 files['crypto_internal_headers'])
    339       self.PrintVariableSection(out, 'ssl_sources',
    340                                 files['ssl'] + files['ssl_headers'] +
    341                                 files['ssl_internal_headers'])
    342 
    343       for ((osname, arch), asm_files) in asm_outputs:
    344         self.PrintVariableSection(
    345             out, 'crypto_sources_%s_%s' % (osname, arch), asm_files)
    346 
    347       fuzzers = [os.path.splitext(os.path.basename(fuzzer))[0]
    348                  for fuzzer in files['fuzz']]
    349       self.PrintVariableSection(out, 'fuzzers', fuzzers)
    350 
    351     with open('BUILD.generated_tests.gni', 'w+') as out:
    352       self.firstSection = True
    353       out.write(self.header)
    354 
    355       self.PrintVariableSection(out, 'test_support_sources',
    356                                 files['test_support'] +
    357                                 files['test_support_headers'])
    358       self.PrintVariableSection(out, 'crypto_test_sources',
    359                                 files['crypto_test'])
    360       self.PrintVariableSection(out, 'ssl_test_sources', files['ssl_test'])
    361       out.write('\n')
    362 
    363       out.write('template("create_tests") {\n')
    364 
    365       all_tests = []
    366       for test in sorted(files['test']):
    367         test_name = 'boringssl_%s' % os.path.splitext(os.path.basename(test))[0]
    368         all_tests.append(test_name)
    369 
    370         out.write('  executable("%s") {\n' % test_name)
    371         out.write('    sources = [\n')
    372         out.write('      "%s",\n' % test)
    373         out.write('    ]\n')
    374         out.write('    sources += test_support_sources\n')
    375         out.write('    if (defined(invoker.configs_exclude)) {\n')
    376         out.write('      configs -= invoker.configs_exclude\n')
    377         out.write('    }\n')
    378         out.write('    configs += invoker.configs\n')
    379         out.write('    deps = invoker.deps\n')
    380         out.write('  }\n')
    381         out.write('\n')
    382 
    383       out.write('  group(target_name) {\n')
    384       out.write('    deps = [\n')
    385       for test_name in sorted(all_tests):
    386         out.write('      ":%s",\n' % test_name)
    387       out.write('    ]\n')
    388       out.write('  }\n')
    389       out.write('}\n')
    390 
    391 
    392 class GYP(object):
    393 
    394   def __init__(self):
    395     self.header = \
    396 """# Copyright (c) 2016 The Chromium Authors. All rights reserved.
    397 # Use of this source code is governed by a BSD-style license that can be
    398 # found in the LICENSE file.
    399 
    400 # This file is created by generate_build_files.py. Do not edit manually.
    401 
    402 """
    403 
    404   def PrintVariableSection(self, out, name, files):
    405     out.write('    \'%s\': [\n' % name)
    406     for f in sorted(files):
    407       out.write('      \'%s\',\n' % f)
    408     out.write('    ],\n')
    409 
    410   def WriteFiles(self, files, asm_outputs):
    411     with open('boringssl.gypi', 'w+') as gypi:
    412       gypi.write(self.header + '{\n  \'variables\': {\n')
    413 
    414       self.PrintVariableSection(gypi, 'boringssl_ssl_sources',
    415                                 files['ssl'] + files['ssl_headers'] +
    416                                 files['ssl_internal_headers'])
    417       self.PrintVariableSection(gypi, 'boringssl_crypto_sources',
    418                                 files['crypto'] + files['crypto_headers'] +
    419                                 files['crypto_internal_headers'])
    420 
    421       for ((osname, arch), asm_files) in asm_outputs:
    422         self.PrintVariableSection(gypi, 'boringssl_%s_%s_sources' %
    423                                   (osname, arch), asm_files)
    424 
    425       gypi.write('  }\n}\n')
    426 
    427 
    428 def FindCMakeFiles(directory):
    429   """Returns list of all CMakeLists.txt files recursively in directory."""
    430   cmakefiles = []
    431 
    432   for (path, _, filenames) in os.walk(directory):
    433     for filename in filenames:
    434       if filename == 'CMakeLists.txt':
    435         cmakefiles.append(os.path.join(path, filename))
    436 
    437   return cmakefiles
    438 
    439 
    440 def NoTests(dent, is_dir):
    441   """Filter function that can be passed to FindCFiles in order to remove test
    442   sources."""
    443   if is_dir:
    444     return dent != 'test'
    445   return 'test.' not in dent and not dent.startswith('example_')
    446 
    447 
    448 def OnlyTests(dent, is_dir):
    449   """Filter function that can be passed to FindCFiles in order to remove
    450   non-test sources."""
    451   if is_dir:
    452     return dent != 'test'
    453   return '_test.' in dent or dent.startswith('example_')
    454 
    455 
    456 def AllFiles(dent, is_dir):
    457   """Filter function that can be passed to FindCFiles in order to include all
    458   sources."""
    459   return True
    460 
    461 
    462 def NotGTestMain(dent, is_dir):
    463   return dent != 'gtest_main.cc'
    464 
    465 
    466 def SSLHeaderFiles(dent, is_dir):
    467   return dent in ['ssl.h', 'tls1.h', 'ssl23.h', 'ssl3.h', 'dtls1.h']
    468 
    469 
    470 def FindCFiles(directory, filter_func):
    471   """Recurses through directory and returns a list of paths to all the C source
    472   files that pass filter_func."""
    473   cfiles = []
    474 
    475   for (path, dirnames, filenames) in os.walk(directory):
    476     for filename in filenames:
    477       if not filename.endswith('.c') and not filename.endswith('.cc'):
    478         continue
    479       if not filter_func(filename, False):
    480         continue
    481       cfiles.append(os.path.join(path, filename))
    482 
    483     for (i, dirname) in enumerate(dirnames):
    484       if not filter_func(dirname, True):
    485         del dirnames[i]
    486 
    487   return cfiles
    488 
    489 
    490 def FindHeaderFiles(directory, filter_func):
    491   """Recurses through directory and returns a list of paths to all the header files that pass filter_func."""
    492   hfiles = []
    493 
    494   for (path, dirnames, filenames) in os.walk(directory):
    495     for filename in filenames:
    496       if not filename.endswith('.h'):
    497         continue
    498       if not filter_func(filename, False):
    499         continue
    500       hfiles.append(os.path.join(path, filename))
    501 
    502       for (i, dirname) in enumerate(dirnames):
    503         if not filter_func(dirname, True):
    504           del dirnames[i]
    505 
    506   return hfiles
    507 
    508 
    509 def ExtractPerlAsmFromCMakeFile(cmakefile):
    510   """Parses the contents of the CMakeLists.txt file passed as an argument and
    511   returns a list of all the perlasm() directives found in the file."""
    512   perlasms = []
    513   with open(cmakefile) as f:
    514     for line in f:
    515       line = line.strip()
    516       if not line.startswith('perlasm('):
    517         continue
    518       if not line.endswith(')'):
    519         raise ValueError('Bad perlasm line in %s' % cmakefile)
    520       # Remove "perlasm(" from start and ")" from end
    521       params = line[8:-1].split()
    522       if len(params) < 2:
    523         raise ValueError('Bad perlasm line in %s' % cmakefile)
    524       perlasms.append({
    525           'extra_args': params[2:],
    526           'input': os.path.join(os.path.dirname(cmakefile), params[1]),
    527           'output': os.path.join(os.path.dirname(cmakefile), params[0]),
    528       })
    529 
    530   return perlasms
    531 
    532 
    533 def ReadPerlAsmOperations():
    534   """Returns a list of all perlasm() directives found in CMake config files in
    535   src/."""
    536   perlasms = []
    537   cmakefiles = FindCMakeFiles('src')
    538 
    539   for cmakefile in cmakefiles:
    540     perlasms.extend(ExtractPerlAsmFromCMakeFile(cmakefile))
    541 
    542   return perlasms
    543 
    544 
    545 def PerlAsm(output_filename, input_filename, perlasm_style, extra_args):
    546   """Runs the a perlasm script and puts the output into output_filename."""
    547   base_dir = os.path.dirname(output_filename)
    548   if not os.path.isdir(base_dir):
    549     os.makedirs(base_dir)
    550   subprocess.check_call(
    551       ['perl', input_filename, perlasm_style] + extra_args + [output_filename])
    552 
    553 
    554 def ArchForAsmFilename(filename):
    555   """Returns the architectures that a given asm file should be compiled for
    556   based on substrings in the filename."""
    557 
    558   if 'x86_64' in filename or 'avx2' in filename:
    559     return ['x86_64']
    560   elif ('x86' in filename and 'x86_64' not in filename) or '586' in filename:
    561     return ['x86']
    562   elif 'armx' in filename:
    563     return ['arm', 'aarch64']
    564   elif 'armv8' in filename:
    565     return ['aarch64']
    566   elif 'arm' in filename:
    567     return ['arm']
    568   elif 'ppc' in filename:
    569     return ['ppc64le']
    570   else:
    571     raise ValueError('Unknown arch for asm filename: ' + filename)
    572 
    573 
    574 def WriteAsmFiles(perlasms):
    575   """Generates asm files from perlasm directives for each supported OS x
    576   platform combination."""
    577   asmfiles = {}
    578 
    579   for osarch in OS_ARCH_COMBOS:
    580     (osname, arch, perlasm_style, extra_args, asm_ext) = osarch
    581     key = (osname, arch)
    582     outDir = '%s-%s' % key
    583 
    584     for perlasm in perlasms:
    585       filename = os.path.basename(perlasm['input'])
    586       output = perlasm['output']
    587       if not output.startswith('src'):
    588         raise ValueError('output missing src: %s' % output)
    589       output = os.path.join(outDir, output[4:])
    590       if output.endswith('-armx.${ASM_EXT}'):
    591         output = output.replace('-armx',
    592                                 '-armx64' if arch == 'aarch64' else '-armx32')
    593       output = output.replace('${ASM_EXT}', asm_ext)
    594 
    595       if arch in ArchForAsmFilename(filename):
    596         PerlAsm(output, perlasm['input'], perlasm_style,
    597                 perlasm['extra_args'] + extra_args)
    598         asmfiles.setdefault(key, []).append(output)
    599 
    600   for (key, non_perl_asm_files) in NON_PERL_FILES.iteritems():
    601     asmfiles.setdefault(key, []).extend(non_perl_asm_files)
    602 
    603   return asmfiles
    604 
    605 
    606 def IsGTest(path):
    607   with open(path) as f:
    608     return "#include <gtest/gtest.h>" in f.read()
    609 
    610 
    611 def main(platforms):
    612   crypto_c_files = FindCFiles(os.path.join('src', 'crypto'), NoTests)
    613   ssl_source_files = FindCFiles(os.path.join('src', 'ssl'), NoTests)
    614   tool_c_files = FindCFiles(os.path.join('src', 'tool'), NoTests)
    615   tool_h_files = FindHeaderFiles(os.path.join('src', 'tool'), AllFiles)
    616 
    617   # Generate err_data.c
    618   with open('err_data.c', 'w+') as err_data:
    619     subprocess.check_call(['go', 'run', 'err_data_generate.go'],
    620                           cwd=os.path.join('src', 'crypto', 'err'),
    621                           stdout=err_data)
    622   crypto_c_files.append('err_data.c')
    623 
    624   test_support_c_files = FindCFiles(os.path.join('src', 'crypto', 'test'),
    625                                     NotGTestMain)
    626   test_support_h_files = (
    627       FindHeaderFiles(os.path.join('src', 'crypto', 'test'), AllFiles) +
    628       FindHeaderFiles(os.path.join('src', 'ssl', 'test'), AllFiles))
    629 
    630   test_c_files = []
    631   crypto_test_files = ['src/crypto/test/gtest_main.cc']
    632   # TODO(davidben): Remove this loop once all tests are converted.
    633   for path in FindCFiles(os.path.join('src', 'crypto'), OnlyTests):
    634     if IsGTest(path):
    635       crypto_test_files.append(path)
    636     else:
    637       test_c_files.append(path)
    638 
    639   ssl_test_files = FindCFiles(os.path.join('src', 'ssl'), OnlyTests)
    640   ssl_test_files.append('src/crypto/test/gtest_main.cc')
    641 
    642   fuzz_c_files = FindCFiles(os.path.join('src', 'fuzz'), NoTests)
    643 
    644   ssl_h_files = (
    645       FindHeaderFiles(
    646           os.path.join('src', 'include', 'openssl'),
    647           SSLHeaderFiles))
    648 
    649   def NotSSLHeaderFiles(filename, is_dir):
    650     return not SSLHeaderFiles(filename, is_dir)
    651   crypto_h_files = (
    652       FindHeaderFiles(
    653           os.path.join('src', 'include', 'openssl'),
    654           NotSSLHeaderFiles))
    655 
    656   ssl_internal_h_files = FindHeaderFiles(os.path.join('src', 'ssl'), NoTests)
    657   crypto_internal_h_files = FindHeaderFiles(
    658       os.path.join('src', 'crypto'), NoTests)
    659 
    660   with open('src/util/all_tests.json', 'r') as f:
    661     tests = json.load(f)
    662   # For now, GTest-based tests are specified manually.
    663   tests = [test for test in tests if test[0] not in ['crypto/crypto_test',
    664                                                      'decrepit/decrepit_test',
    665                                                      'ssl/ssl_test']]
    666   test_binaries = set([test[0] for test in tests])
    667   test_sources = set([
    668       test.replace('.cc', '').replace('.c', '').replace(
    669           'src/',
    670           '')
    671       for test in test_c_files])
    672   if test_binaries != test_sources:
    673     print 'Test sources and configured tests do not match'
    674     a = test_binaries.difference(test_sources)
    675     if len(a) > 0:
    676       print 'These tests are configured without sources: ' + str(a)
    677     b = test_sources.difference(test_binaries)
    678     if len(b) > 0:
    679       print 'These test sources are not configured: ' + str(b)
    680 
    681   files = {
    682       'crypto': crypto_c_files,
    683       'crypto_headers': crypto_h_files,
    684       'crypto_internal_headers': crypto_internal_h_files,
    685       'crypto_test': sorted(crypto_test_files),
    686       'fuzz': fuzz_c_files,
    687       'ssl': ssl_source_files,
    688       'ssl_c': [s for s in ssl_source_files if s.endswith('.c')],
    689       'ssl_cc': [s for s in ssl_source_files if s.endswith('.cc')],
    690       'ssl_headers': ssl_h_files,
    691       'ssl_internal_headers': ssl_internal_h_files,
    692       'ssl_test': sorted(ssl_test_files),
    693       'tool': tool_c_files,
    694       'tool_headers': tool_h_files,
    695       'test': test_c_files,
    696       'test_support': test_support_c_files,
    697       'test_support_headers': test_support_h_files,
    698       'tests': tests,
    699   }
    700 
    701   asm_outputs = sorted(WriteAsmFiles(ReadPerlAsmOperations()).iteritems())
    702 
    703   for platform in platforms:
    704     platform.WriteFiles(files, asm_outputs)
    705 
    706   return 0
    707 
    708 
    709 if __name__ == '__main__':
    710   parser = optparse.OptionParser(usage='Usage: %prog [--prefix=<path>]'
    711       ' [android|bazel|gn|gyp]')
    712   parser.add_option('--prefix', dest='prefix',
    713       help='For Bazel, prepend argument to all source files')
    714   options, args = parser.parse_args(sys.argv[1:])
    715   PREFIX = options.prefix
    716 
    717   if not args:
    718     parser.print_help()
    719     sys.exit(1)
    720 
    721   platforms = []
    722   for s in args:
    723     if s == 'android':
    724       platforms.append(Android())
    725     elif s == 'bazel':
    726       platforms.append(Bazel())
    727     elif s == 'gn':
    728       platforms.append(GN())
    729     elif s == 'gyp':
    730       platforms.append(GYP())
    731     else:
    732       parser.print_help()
    733       sys.exit(1)
    734 
    735   sys.exit(main(platforms))
    736