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