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