1# coding=utf8
2
3# Copyright 2015 The BoringSSL Authors
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     https://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Enumerates source files for consumption by various build systems."""
18
19import optparse
20import os
21import subprocess
22import sys
23import json
24
25
26PREFIX = None
27
28
29def PathOf(x):
30  return x if not PREFIX else os.path.join(PREFIX, x)
31
32
33TARGET_PREFIX = ''
34
35
36LICENSE_TEMPLATE = """Copyright 2015 The BoringSSL Authors
37
38Licensed under the Apache License, Version 2.0 (the "License");
39you may not use this file except in compliance with the License.
40You may obtain a copy of the License at
41
42    https://www.apache.org/licenses/LICENSE-2.0
43
44Unless required by applicable law or agreed to in writing, software
45distributed under the License is distributed on an "AS IS" BASIS,
46WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
47See the License for the specific language governing permissions and
48limitations under the License.""".split("\n")
49
50def LicenseHeader(comment):
51  lines = []
52  for line in LICENSE_TEMPLATE:
53    if not line:
54      lines.append(comment)
55    else:
56      lines.append("%s %s" % (comment, line))
57  lines.append("")
58  return "\n".join(lines)
59
60
61class Android(object):
62
63  def __init__(self):
64    self.header = LicenseHeader("#") + """
65# This file is created by generate_build_files.py. Do not edit manually.
66"""
67
68  def PrintVariableSection(self, out, name, files):
69    name = f'{TARGET_PREFIX}{name}'
70    out.write('%s := \\\n' % name)
71    for f in sorted(files):
72      out.write('  %s\\\n' % f)
73    out.write('\n')
74
75  def WriteFiles(self, files):
76    # New Android.bp format
77    with open('sources.bp', 'w+') as blueprint:
78      blueprint.write(self.header.replace('#', '//'))
79
80      #  Separate out BCM files to allow different compilation rules (specific to Android FIPS)
81      bcm_c_files = files['bcm_crypto']
82      non_bcm_c_files = [file for file in files['crypto'] if file not in bcm_c_files]
83      non_bcm_asm = self.FilterBcmAsm(files['crypto_asm'], False)
84      bcm_asm = self.FilterBcmAsm(files['crypto_asm'], True)
85
86      self.PrintDefaults(blueprint, 'libcrypto_sources', non_bcm_c_files, asm_files=non_bcm_asm)
87      self.PrintDefaults(blueprint, 'libcrypto_bcm_sources', bcm_c_files, asm_files=bcm_asm)
88      self.PrintDefaults(blueprint, 'libssl_sources', files['ssl'])
89      self.PrintDefaults(blueprint, 'bssl_sources', files['tool'])
90      self.PrintDefaults(blueprint, 'boringssl_test_support_sources', files['test_support'])
91      self.PrintDefaults(blueprint, 'boringssl_crypto_test_sources', files['crypto_test'], data=files['crypto_test_data'])
92      self.PrintDefaults(blueprint, 'boringssl_ssl_test_sources', files['ssl_test'])
93      self.PrintDefaults(blueprint, 'libpki_sources', files['pki'])
94
95    # Legacy Android.mk format, only used by Trusty in new branches
96    with open('sources.mk', 'w+') as makefile:
97      makefile.write(self.header)
98      makefile.write('\n')
99      self.PrintVariableSection(makefile, 'crypto_sources', files['crypto'])
100      self.PrintVariableSection(makefile, 'crypto_sources_asm',
101                                files['crypto_asm'])
102
103  def PrintDefaults(self, blueprint, name, files, asm_files=[], data=[]):
104    """Print a cc_defaults section from a list of C files and optionally assembly outputs"""
105    name = f'{TARGET_PREFIX}{name}'
106    if asm_files:
107      blueprint.write('\n')
108      blueprint.write('%s_asm = [\n' % name)
109      for f in sorted(asm_files):
110        blueprint.write('    "%s",\n' % f)
111      blueprint.write(']\n')
112
113    blueprint.write('\n')
114    blueprint.write('cc_defaults {\n')
115    blueprint.write('    name: "%s",\n' % name)
116    blueprint.write('    srcs: [\n')
117    for f in sorted(files):
118      blueprint.write('        "%s",\n' % f)
119    blueprint.write('    ],\n')
120    if data:
121      blueprint.write('    data: [\n')
122      for f in sorted(data):
123        blueprint.write('        "%s",\n' % f)
124      blueprint.write('    ],\n')
125
126    if asm_files:
127      blueprint.write('    target: {\n')
128      # Only emit asm for Linux. On Windows, BoringSSL requires NASM, which is
129      # not available in AOSP. On Darwin, the assembly works fine, but it
130      # conflicts with Android's FIPS build. See b/294399371.
131      blueprint.write('        linux: {\n')
132      blueprint.write('            srcs: %s_asm,\n' % name)
133      blueprint.write('        },\n')
134      blueprint.write('        darwin: {\n')
135      blueprint.write('            cflags: ["-DOPENSSL_NO_ASM"],\n')
136      blueprint.write('        },\n')
137      blueprint.write('        windows: {\n')
138      blueprint.write('            cflags: ["-DOPENSSL_NO_ASM"],\n')
139      blueprint.write('        },\n')
140      blueprint.write('    },\n')
141
142    blueprint.write('}\n')
143
144  def FilterBcmAsm(self, asm, want_bcm):
145    """Filter a list of assembly outputs based on whether they belong in BCM
146
147    Args:
148      asm: Assembly file list to filter
149      want_bcm: If true then include BCM files, otherwise do not
150
151    Returns:
152      A copy of |asm| with files filtered according to |want_bcm|
153    """
154    # TODO(https://crbug.com/boringssl/542): Rather than filtering by filename,
155    # use the variable listed in the CMake perlasm line, available in
156    # ExtractPerlAsmFromCMakeFile.
157    return filter(lambda p: ("/crypto/fipsmodule/" in p) == want_bcm, asm)
158
159
160class AndroidCMake(object):
161
162  def __init__(self):
163    self.header = LicenseHeader("#") + """
164# This file is created by generate_build_files.py. Do not edit manually.
165# To specify a custom path prefix, set BORINGSSL_ROOT before including this
166# file, or use list(TRANSFORM ... PREPEND) from CMake 3.12.
167
168"""
169
170  def PrintVariableSection(self, out, name, files):
171    out.write('set(%s\n' % name)
172    for f in sorted(files):
173      # Ideally adding the prefix would be the caller's job, but
174      # list(TRANSFORM ... PREPEND) is only available starting CMake 3.12. When
175      # sources.cmake is the source of truth, we can ask Android to either write
176      # a CMake function or update to 3.12.
177      out.write('  ${BORINGSSL_ROOT}%s\n' % f)
178    out.write(')\n')
179
180  def WriteFiles(self, files):
181    # The Android emulator uses a custom CMake buildsystem.
182    #
183    # TODO(crbug.com/boringssl/542): Move our various source lists into
184    # sources.cmake and have Android consume that directly.
185    with open('android-sources.cmake', 'w+') as out:
186      out.write(self.header)
187
188      self.PrintVariableSection(out, 'crypto_sources', files['crypto'])
189      self.PrintVariableSection(out, 'crypto_sources_asm', files['crypto_asm'])
190      self.PrintVariableSection(out, 'crypto_sources_nasm',
191                                files['crypto_nasm'])
192      self.PrintVariableSection(out, 'ssl_sources', files['ssl'])
193      self.PrintVariableSection(out, 'tool_sources', files['tool'])
194      self.PrintVariableSection(out, 'test_support_sources',
195                                files['test_support'])
196      self.PrintVariableSection(out, 'crypto_test_sources',
197                                files['crypto_test'])
198      self.PrintVariableSection(out, 'crypto_test_data',
199                                files['crypto_test_data'])
200      self.PrintVariableSection(out, 'ssl_test_sources', files['ssl_test'])
201
202
203class Bazel(object):
204  """Bazel outputs files suitable for including in Bazel files."""
205
206  def __init__(self):
207    self.firstSection = True
208    self.header = \
209"""# This file is created by generate_build_files.py. Do not edit manually.
210
211"""
212
213  def PrintVariableSection(self, out, name, files):
214    if not self.firstSection:
215      out.write('\n')
216    self.firstSection = False
217
218    out.write('%s = [\n' % name)
219    for f in sorted(files):
220      out.write('    "%s",\n' % PathOf(f))
221    out.write(']\n')
222
223  def WriteFiles(self, files):
224    with open('BUILD.generated.bzl', 'w+') as out:
225      out.write(self.header)
226
227      self.PrintVariableSection(out, 'ssl_headers', files['ssl_headers'])
228      self.PrintVariableSection(out, 'fips_fragments', files['fips_fragments'])
229      self.PrintVariableSection(
230          out, 'ssl_internal_headers', files['ssl_internal_headers'])
231      self.PrintVariableSection(out, 'ssl_sources', files['ssl'])
232      self.PrintVariableSection(out, 'crypto_headers', files['crypto_headers'])
233      self.PrintVariableSection(
234          out, 'crypto_internal_headers', files['crypto_internal_headers'])
235      self.PrintVariableSection(out, 'crypto_sources', files['crypto'])
236      self.PrintVariableSection(out, 'crypto_sources_asm', files['crypto_asm'])
237      self.PrintVariableSection(out, 'crypto_sources_nasm', files['crypto_nasm'])
238      self.PrintVariableSection(out, 'pki_headers', files['pki_headers'])
239      self.PrintVariableSection(
240          out, 'pki_internal_headers', files['pki_internal_headers'])
241      self.PrintVariableSection(out, 'pki_sources', files['pki'])
242      self.PrintVariableSection(out, 'rust_bssl_sys', files['rust_bssl_sys'])
243      self.PrintVariableSection(out, 'rust_bssl_crypto', files['rust_bssl_crypto'])
244      self.PrintVariableSection(out, 'tool_sources', files['tool'])
245      self.PrintVariableSection(out, 'tool_headers', files['tool_headers'])
246
247    with open('BUILD.generated_tests.bzl', 'w+') as out:
248      out.write(self.header)
249
250      out.write('test_support_sources = [\n')
251      for filename in sorted(files['test_support'] +
252                             files['test_support_headers'] +
253                             files['crypto_internal_headers'] +
254                             files['pki_internal_headers'] +
255                             files['ssl_internal_headers']):
256        out.write('    "%s",\n' % PathOf(filename))
257
258      out.write(']\n')
259
260      self.PrintVariableSection(out, 'crypto_test_sources',
261                                files['crypto_test'])
262      self.PrintVariableSection(out, 'ssl_test_sources', files['ssl_test'])
263      self.PrintVariableSection(out, 'pki_test_sources',
264                                files['pki_test'])
265      self.PrintVariableSection(out, 'crypto_test_data',
266                                files['crypto_test_data'])
267      self.PrintVariableSection(out, 'pki_test_data',
268                                files['pki_test_data'])
269      self.PrintVariableSection(out, 'urandom_test_sources',
270                                files['urandom_test'])
271
272
273class Eureka(object):
274
275  def __init__(self):
276    self.header = LicenseHeader("#") + """
277# This file is created by generate_build_files.py. Do not edit manually.
278
279"""
280
281  def PrintVariableSection(self, out, name, files):
282    out.write('%s := \\\n' % name)
283    for f in sorted(files):
284      out.write('  %s\\\n' % f)
285    out.write('\n')
286
287  def WriteFiles(self, files):
288    # Legacy Android.mk format
289    with open('eureka.mk', 'w+') as makefile:
290      makefile.write(self.header)
291
292      self.PrintVariableSection(makefile, 'crypto_sources', files['crypto'])
293      self.PrintVariableSection(makefile, 'crypto_sources_asm',
294                                files['crypto_asm'])
295      self.PrintVariableSection(makefile, 'crypto_sources_nasm',
296                                files['crypto_nasm'])
297      self.PrintVariableSection(makefile, 'ssl_sources', files['ssl'])
298      self.PrintVariableSection(makefile, 'tool_sources', files['tool'])
299
300
301class GN(object):
302
303  def __init__(self):
304    self.firstSection = True
305    self.header = LicenseHeader("#") + """
306# This file is created by generate_build_files.py. Do not edit manually.
307
308"""
309
310  def PrintVariableSection(self, out, name, files):
311    if not self.firstSection:
312      out.write('\n')
313    self.firstSection = False
314
315    if len(files) == 0:
316      out.write('%s = []\n' % name)
317    elif len(files) == 1:
318      out.write('%s = [ "%s" ]\n' % (name, files[0]))
319    else:
320      out.write('%s = [\n' % name)
321      for f in sorted(files):
322        out.write('  "%s",\n' % f)
323      out.write(']\n')
324
325  def WriteFiles(self, files):
326    with open('BUILD.generated.gni', 'w+') as out:
327      out.write(self.header)
328
329      self.PrintVariableSection(out, 'crypto_sources',
330                                files['crypto'] +
331                                files['crypto_internal_headers'])
332      self.PrintVariableSection(out, 'crypto_sources_asm', files['crypto_asm'])
333      self.PrintVariableSection(out, 'crypto_sources_nasm',
334                                files['crypto_nasm'])
335      self.PrintVariableSection(out, 'crypto_headers', files['crypto_headers'])
336      self.PrintVariableSection(out, 'rust_bssl_sys', files['rust_bssl_sys'])
337      self.PrintVariableSection(out, 'rust_bssl_crypto',
338                                files['rust_bssl_crypto'])
339      self.PrintVariableSection(out, 'ssl_sources',
340                                files['ssl'] + files['ssl_internal_headers'])
341      self.PrintVariableSection(out, 'ssl_headers', files['ssl_headers'])
342      self.PrintVariableSection(out, 'pki_sources', files['pki'])
343      self.PrintVariableSection(out, 'pki_internal_headers',
344                                files['pki_internal_headers'])
345      self.PrintVariableSection(out, 'pki_headers', files['pki_headers'])
346      self.PrintVariableSection(out, 'tool_sources',
347                                files['tool'] + files['tool_headers'])
348
349      fuzzers = [os.path.splitext(os.path.basename(fuzzer))[0]
350                 for fuzzer in files['fuzz']]
351      self.PrintVariableSection(out, 'fuzzers', fuzzers)
352
353    with open('BUILD.generated_tests.gni', 'w+') as out:
354      self.firstSection = True
355      out.write(self.header)
356
357      self.PrintVariableSection(out, 'test_support_sources',
358                                files['test_support'] +
359                                files['test_support_headers'])
360      self.PrintVariableSection(out, 'crypto_test_sources',
361                                files['crypto_test'])
362      self.PrintVariableSection(out, 'crypto_test_data',
363                                files['crypto_test_data'])
364      self.PrintVariableSection(out, 'pki_test_data',
365                                files['pki_test_data'])
366      self.PrintVariableSection(out, 'ssl_test_sources', files['ssl_test'])
367      self.PrintVariableSection(out, 'pki_test_sources', files['pki_test'])
368
369
370class GYP(object):
371
372  def __init__(self):
373    self.header = LicenseHeader("#") + """
374# This file is created by generate_build_files.py. Do not edit manually.
375
376"""
377
378  def PrintVariableSection(self, out, name, files):
379    out.write('    \'%s\': [\n' % name)
380    for f in sorted(files):
381      out.write('      \'%s\',\n' % f)
382    out.write('    ],\n')
383
384  def WriteFiles(self, files):
385    with open('boringssl.gypi', 'w+') as gypi:
386      gypi.write(self.header + '{\n  \'variables\': {\n')
387
388      self.PrintVariableSection(gypi, 'boringssl_ssl_sources',
389                                files['ssl'] + files['ssl_headers'] +
390                                files['ssl_internal_headers'])
391      self.PrintVariableSection(gypi, 'boringssl_crypto_sources',
392                                files['crypto'] + files['crypto_headers'] +
393                                files['crypto_internal_headers'])
394      self.PrintVariableSection(gypi, 'boringssl_crypto_asm_sources',
395                                files['crypto_asm'])
396      self.PrintVariableSection(gypi, 'boringssl_crypto_nasm_sources',
397                                files['crypto_nasm'])
398
399      gypi.write('  }\n}\n')
400
401class CMake(object):
402
403  def __init__(self):
404    self.header = LicenseHeader("#") + R'''
405# This file is created by generate_build_files.py. Do not edit manually.
406
407cmake_minimum_required(VERSION 3.16)
408
409project(BoringSSL LANGUAGES C CXX)
410
411set(CMAKE_CXX_STANDARD 17)
412set(CMAKE_CXX_STANDARD_REQUIRED ON)
413set(CMAKE_C_STANDARD 11)
414set(CMAKE_C_STANDARD_REQUIRED ON)
415if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
416  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fno-common -fno-exceptions -fno-rtti")
417  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fno-common")
418endif()
419
420# pthread_rwlock_t requires a feature flag on glibc.
421if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
422  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_XOPEN_SOURCE=700")
423endif()
424
425if(WIN32)
426  add_definitions(-D_HAS_EXCEPTIONS=0)
427  add_definitions(-DWIN32_LEAN_AND_MEAN)
428  add_definitions(-DNOMINMAX)
429  # Allow use of fopen.
430  add_definitions(-D_CRT_SECURE_NO_WARNINGS)
431endif()
432
433add_definitions(-DBORINGSSL_IMPLEMENTATION)
434
435if(OPENSSL_NO_ASM)
436  add_definitions(-DOPENSSL_NO_ASM)
437else()
438  # On x86 and x86_64 Windows, we use the NASM output.
439  if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|x86_64|amd64|x86|i[3-6]86")
440    enable_language(ASM_NASM)
441    set(OPENSSL_NASM TRUE)
442    set(CMAKE_ASM_NASM_FLAGS "${CMAKE_ASM_NASM_FLAGS} -gcv8")
443  else()
444    enable_language(ASM)
445    set(OPENSSL_ASM TRUE)
446    # Work around https://gitlab.kitware.com/cmake/cmake/-/issues/20771 in older
447    # CMake versions.
448    if(APPLE AND CMAKE_VERSION VERSION_LESS 3.19)
449      if(CMAKE_OSX_SYSROOT)
450        set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -isysroot \"${CMAKE_OSX_SYSROOT}\"")
451      endif()
452      foreach(arch ${CMAKE_OSX_ARCHITECTURES})
453        set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -arch ${arch}")
454      endforeach()
455    endif()
456    if(NOT WIN32)
457      set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,--noexecstack")
458    endif()
459    # Clang's integerated assembler does not support debug symbols.
460    if(NOT CMAKE_ASM_COMPILER_ID MATCHES "Clang")
461      set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,-g")
462    endif()
463  endif()
464endif()
465
466if(BUILD_SHARED_LIBS)
467  add_definitions(-DBORINGSSL_SHARED_LIBRARY)
468  # Enable position-independent code globally. This is needed because
469  # some library targets are OBJECT libraries.
470  set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
471endif()
472
473'''
474
475  def PrintLibrary(self, out, name, files, libs=[]):
476    out.write('add_library(\n')
477    out.write('  %s\n\n' % name)
478
479    for f in sorted(files):
480      out.write('  %s\n' % PathOf(f))
481
482    out.write(')\n\n')
483    if libs:
484      out.write('target_link_libraries(%s %s)\n\n' % (name, ' '.join(libs)))
485
486  def PrintExe(self, out, name, files, libs):
487    out.write('add_executable(\n')
488    out.write('  %s\n\n' % name)
489
490    for f in sorted(files):
491      out.write('  %s\n' % PathOf(f))
492
493    out.write(')\n\n')
494    out.write('target_link_libraries(%s %s)\n\n' % (name, ' '.join(libs)))
495
496  def PrintVariable(self, out, name, files):
497    out.write('set(\n')
498    out.write('  %s\n\n' % name)
499    for f in sorted(files):
500      out.write('  %s\n' % PathOf(f))
501    out.write(')\n\n')
502
503  def WriteFiles(self, files):
504    with open('CMakeLists.txt', 'w+') as cmake:
505      cmake.write(self.header)
506
507      self.PrintVariable(cmake, 'CRYPTO_SOURCES_ASM', files['crypto_asm'])
508      self.PrintVariable(cmake, 'CRYPTO_SOURCES_NASM', files['crypto_nasm'])
509
510      cmake.write(
511R'''if(OPENSSL_ASM)
512  list(APPEND CRYPTO_SOURCES_ASM_USED ${CRYPTO_SOURCES_ASM})
513endif()
514if(OPENSSL_NASM)
515  list(APPEND CRYPTO_SOURCES_ASM_USED ${CRYPTO_SOURCES_NASM})
516endif()
517
518''')
519
520      self.PrintLibrary(cmake, 'crypto',
521          files['crypto'] + ['${CRYPTO_SOURCES_ASM_USED}'])
522      cmake.write('target_include_directories(crypto PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/include>)\n\n')
523      self.PrintLibrary(cmake, 'ssl', files['ssl'], ['crypto'])
524      self.PrintExe(cmake, 'bssl', files['tool'], ['ssl', 'crypto'])
525
526      cmake.write(
527R'''if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
528  find_package(Threads REQUIRED)
529  target_link_libraries(crypto Threads::Threads)
530endif()
531
532if(WIN32)
533  target_link_libraries(crypto ws2_32)
534endif()
535
536''')
537
538class JSON(object):
539  def WriteFiles(self, files):
540    with open('sources.json', 'w+') as f:
541      json.dump(files, f, sort_keys=True, indent=2)
542
543def NoTestsNorFIPSFragments(path, dent, is_dir):
544  return (NoTests(path, dent, is_dir) and
545      (is_dir or not OnlyFIPSFragments(path, dent, is_dir)))
546
547def NoTests(path, dent, is_dir):
548  """Filter function that can be passed to FindCFiles in order to remove test
549  sources."""
550  if is_dir:
551    return dent != 'test'
552  return 'test.' not in dent
553
554
555def AllFiles(path, dent, is_dir):
556  """Filter function that can be passed to FindCFiles in order to include all
557  sources."""
558  return True
559
560
561def NoTestRunnerFiles(path, dent, is_dir):
562  """Filter function that can be passed to FindCFiles or FindHeaderFiles in
563  order to exclude test runner files."""
564  # NOTE(martinkr): This prevents .h/.cc files in src/ssl/test/runner, which
565  # are in their own subpackage, from being included in boringssl/BUILD files.
566  return not is_dir or dent != 'runner'
567
568
569def FindCFiles(directory, filter_func):
570  """Recurses through directory and returns a list of paths to all the C source
571  files that pass filter_func."""
572  cfiles = []
573
574  for (path, dirnames, filenames) in os.walk(directory):
575    for filename in filenames:
576      if not filename.endswith('.c') and not filename.endswith('.cc'):
577        continue
578      if not filter_func(path, filename, False):
579        continue
580      cfiles.append(os.path.join(path, filename))
581
582    for (i, dirname) in enumerate(dirnames):
583      if not filter_func(path, dirname, True):
584        del dirnames[i]
585
586  cfiles.sort()
587  return cfiles
588
589
590def FindHeaderFiles(directory, filter_func):
591  """Recurses through directory and returns a list of paths to all the header files that pass filter_func."""
592  hfiles = []
593
594  for (path, dirnames, filenames) in os.walk(directory):
595    for filename in filenames:
596      if not filename.endswith('.h'):
597        continue
598      if not filter_func(path, filename, False):
599        continue
600      hfiles.append(os.path.join(path, filename))
601
602      for (i, dirname) in enumerate(dirnames):
603        if not filter_func(path, dirname, True):
604          del dirnames[i]
605
606  hfiles.sort()
607  return hfiles
608
609
610def PrefixWithSrc(files):
611  return ['src/' + x for x in files]
612
613
614def main(platforms):
615  with open(os.path.join('src', 'gen', 'sources.json')) as f:
616    sources = json.load(f)
617
618  # TODO(crbug.com/boringssl/542): generate_build_files.py historically reported
619  # all the assembly files as part of libcrypto. Merge them for now, but we
620  # should split them out later.
621  crypto = sorted(sources['bcm']['srcs'] + sources['crypto']['srcs'])
622  crypto_asm = sorted(sources['bcm']['asm'] + sources['crypto']['asm'] +
623                      sources['test_support']['asm'])
624  crypto_nasm = sorted(sources['bcm']['nasm'] + sources['crypto']['nasm'] +
625                       sources['test_support']['nasm'])
626
627  files = {
628      'bcm_crypto': PrefixWithSrc(sources['bcm']['srcs']),
629      'crypto': PrefixWithSrc(crypto),
630      'crypto_asm': PrefixWithSrc(crypto_asm),
631      'crypto_nasm': PrefixWithSrc(crypto_nasm),
632      'crypto_headers': PrefixWithSrc(sources['crypto']['hdrs']),
633      'crypto_internal_headers':
634          PrefixWithSrc(sources['crypto']['internal_hdrs']),
635      'crypto_test': PrefixWithSrc(sources['crypto_test']['srcs']),
636      'crypto_test_data': PrefixWithSrc(sources['crypto_test']['data']),
637      'fips_fragments': PrefixWithSrc(sources['bcm']['internal_hdrs']),
638      'fuzz': PrefixWithSrc(sources['fuzz']['srcs']),
639      'pki': PrefixWithSrc(sources['pki']['srcs']),
640      'pki_headers': PrefixWithSrc(sources['pki']['hdrs']),
641      'pki_internal_headers': PrefixWithSrc(sources['pki']['internal_hdrs']),
642      'pki_test': PrefixWithSrc(sources['pki_test']['srcs']),
643      'pki_test_data': PrefixWithSrc(sources['pki_test']['data']),
644      'rust_bssl_crypto': PrefixWithSrc(sources['rust_bssl_crypto']['srcs']),
645      'rust_bssl_sys': PrefixWithSrc(sources['rust_bssl_sys']['srcs']),
646      'ssl': PrefixWithSrc(sources['ssl']['srcs']),
647      'ssl_headers': PrefixWithSrc(sources['ssl']['hdrs']),
648      'ssl_internal_headers': PrefixWithSrc(sources['ssl']['internal_hdrs']),
649      'ssl_test': PrefixWithSrc(sources['ssl_test']['srcs']),
650      'tool': PrefixWithSrc(sources['bssl']['srcs']),
651      'tool_headers': PrefixWithSrc(sources['bssl']['internal_hdrs']),
652      'test_support': PrefixWithSrc(sources['test_support']['srcs']),
653      'test_support_headers':
654          PrefixWithSrc(sources['test_support']['internal_hdrs']),
655      'urandom_test': PrefixWithSrc(sources['urandom_test']['srcs']),
656  }
657
658  for platform in platforms:
659    platform.WriteFiles(files)
660
661  return 0
662
663ALL_PLATFORMS = {
664    'android': Android,
665    'android-cmake': AndroidCMake,
666    'bazel': Bazel,
667    'cmake': CMake,
668    'eureka': Eureka,
669    'gn': GN,
670    'gyp': GYP,
671    'json': JSON,
672}
673
674if __name__ == '__main__':
675  parser = optparse.OptionParser(
676      usage='Usage: %%prog [--prefix=<path>] [--target-prefix=<prefix>] [all|%s]' %
677      '|'.join(sorted(ALL_PLATFORMS.keys())))
678  parser.add_option('--prefix', dest='prefix',
679      help='For Bazel, prepend argument to all source files')
680  parser.add_option('--target-prefix', dest='target_prefix', default='',
681      help='For Android, prepend argument to all target names')
682  options, args = parser.parse_args(sys.argv[1:])
683  PREFIX = options.prefix
684  TARGET_PREFIX = options.target_prefix
685
686  if not args:
687    parser.print_help()
688    sys.exit(1)
689
690  if 'all' in args:
691    platforms = [platform() for platform in ALL_PLATFORMS.values()]
692  else:
693    platforms = []
694    for s in args:
695      platform = ALL_PLATFORMS.get(s)
696      if platform is None:
697        parser.print_help()
698        sys.exit(1)
699      platforms.append(platform())
700
701  sys.exit(main(platforms))
702