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