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 26# OS_ARCH_COMBOS maps from OS and platform to the OpenSSL assembly "style" for 27# that platform and the extension used by asm files. 28# 29# TODO(https://crbug.com/boringssl/542): This probably should be a map, but some 30# downstream scripts import this to find what folders to add/remove from git. 31OS_ARCH_COMBOS = [ 32 ('apple', 'arm', 'ios32', [], 'S'), 33 ('apple', 'aarch64', 'ios64', [], 'S'), 34 ('apple', 'x86', 'macosx', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'), 35 ('apple', 'x86_64', 'macosx', [], 'S'), 36 ('linux', 'arm', 'linux32', [], 'S'), 37 ('linux', 'aarch64', 'linux64', [], 'S'), 38 ('linux', 'x86', 'elf', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'), 39 ('linux', 'x86_64', 'elf', [], 'S'), 40 ('win', 'x86', 'win32n', ['-DOPENSSL_IA32_SSE2'], 'asm'), 41 ('win', 'x86_64', 'nasm', [], 'asm'), 42 ('win', 'aarch64', 'win64', [], 'S'), 43] 44 45# NON_PERL_FILES enumerates assembly files that are not processed by the 46# perlasm system. 47NON_PERL_FILES = { 48 ('apple', 'x86_64'): [ 49 'src/third_party/fiat/asm/fiat_curve25519_adx_mul.S', 50 'src/third_party/fiat/asm/fiat_curve25519_adx_square.S', 51 'src/third_party/fiat/asm/fiat_p256_adx_mul.S', 52 'src/third_party/fiat/asm/fiat_p256_adx_sqr.S', 53 ], 54 ('linux', 'arm'): [ 55 'src/crypto/curve25519/asm/x25519-asm-arm.S', 56 'src/crypto/poly1305/poly1305_arm_asm.S', 57 ], 58 ('linux', 'x86_64'): [ 59 'src/crypto/hrss/asm/poly_rq_mul.S', 60 'src/third_party/fiat/asm/fiat_curve25519_adx_mul.S', 61 'src/third_party/fiat/asm/fiat_curve25519_adx_square.S', 62 'src/third_party/fiat/asm/fiat_p256_adx_mul.S', 63 'src/third_party/fiat/asm/fiat_p256_adx_sqr.S', 64 ], 65} 66 67PREFIX = None 68EMBED_TEST_DATA = True 69 70 71def PathOf(x): 72 return x if not PREFIX else os.path.join(PREFIX, x) 73 74 75LICENSE_TEMPLATE = """Copyright (c) 2015, Google Inc. 76 77Permission to use, copy, modify, and/or distribute this software for any 78purpose with or without fee is hereby granted, provided that the above 79copyright notice and this permission notice appear in all copies. 80 81THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 82WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 83MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 84SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 85WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 86OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 87CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.""".split("\n") 88 89def LicenseHeader(comment): 90 lines = [] 91 for line in LICENSE_TEMPLATE: 92 if not line: 93 lines.append(comment) 94 else: 95 lines.append("%s %s" % (comment, line)) 96 lines.append("") 97 return "\n".join(lines) 98 99 100class Android(object): 101 102 def __init__(self): 103 self.header = LicenseHeader("#") + """ 104# This file is created by generate_build_files.py. Do not edit manually. 105""" 106 107 def PrintVariableSection(self, out, name, files): 108 out.write('%s := \\\n' % name) 109 for f in sorted(files): 110 out.write(' %s\\\n' % f) 111 out.write('\n') 112 113 def WriteFiles(self, files): 114 # New Android.bp format 115 with open('sources.bp', 'w+') as blueprint: 116 blueprint.write(self.header.replace('#', '//')) 117 118 # Separate out BCM files to allow different compilation rules (specific to Android FIPS) 119 bcm_c_files = files['bcm_crypto'] 120 non_bcm_c_files = [file for file in files['crypto'] if file not in bcm_c_files] 121 non_bcm_asm = self.FilterBcmAsm(files['crypto_asm'], False) 122 bcm_asm = self.FilterBcmAsm(files['crypto_asm'], True) 123 124 self.PrintDefaults(blueprint, 'libcrypto_sources', non_bcm_c_files, non_bcm_asm) 125 self.PrintDefaults(blueprint, 'libcrypto_bcm_sources', bcm_c_files, bcm_asm) 126 self.PrintDefaults(blueprint, 'libssl_sources', files['ssl']) 127 self.PrintDefaults(blueprint, 'bssl_sources', files['tool']) 128 self.PrintDefaults(blueprint, 'boringssl_test_support_sources', files['test_support']) 129 self.PrintDefaults(blueprint, 'boringssl_crypto_test_sources', files['crypto_test']) 130 self.PrintDefaults(blueprint, 'boringssl_ssl_test_sources', files['ssl_test']) 131 self.PrintDefaults(blueprint, 'libpki_sources', files['pki']) 132 133 # Legacy Android.mk format, only used by Trusty in new branches 134 with open('sources.mk', 'w+') as makefile: 135 makefile.write(self.header) 136 makefile.write('\n') 137 self.PrintVariableSection(makefile, 'crypto_sources', files['crypto']) 138 self.PrintVariableSection(makefile, 'crypto_sources_asm', 139 files['crypto_asm']) 140 141 def PrintDefaults(self, blueprint, name, files, asm_files=[]): 142 """Print a cc_defaults section from a list of C files and optionally assembly outputs""" 143 if asm_files: 144 blueprint.write('\n') 145 blueprint.write('%s_asm = [\n' % name) 146 for f in sorted(asm_files): 147 blueprint.write(' "%s",\n' % f) 148 blueprint.write(']\n') 149 150 blueprint.write('\n') 151 blueprint.write('cc_defaults {\n') 152 blueprint.write(' name: "%s",\n' % name) 153 blueprint.write(' srcs: [\n') 154 for f in sorted(files): 155 blueprint.write(' "%s",\n' % f) 156 blueprint.write(' ],\n') 157 158 if asm_files: 159 blueprint.write(' target: {\n') 160 # Only emit asm for Linux. On Windows, BoringSSL requires NASM, which is 161 # not available in AOSP. On Darwin, the assembly works fine, but it 162 # conflicts with Android's FIPS build. See b/294399371. 163 blueprint.write(' linux: {\n') 164 blueprint.write(' srcs: %s_asm,\n' % name) 165 blueprint.write(' },\n') 166 blueprint.write(' darwin: {\n') 167 blueprint.write(' cflags: ["-DOPENSSL_NO_ASM"],\n') 168 blueprint.write(' },\n') 169 blueprint.write(' windows: {\n') 170 blueprint.write(' cflags: ["-DOPENSSL_NO_ASM"],\n') 171 blueprint.write(' },\n') 172 blueprint.write(' },\n') 173 174 blueprint.write('}\n') 175 176 def FilterBcmAsm(self, asm, want_bcm): 177 """Filter a list of assembly outputs based on whether they belong in BCM 178 179 Args: 180 asm: Assembly file list to filter 181 want_bcm: If true then include BCM files, otherwise do not 182 183 Returns: 184 A copy of |asm| with files filtered according to |want_bcm| 185 """ 186 # TODO(https://crbug.com/boringssl/542): Rather than filtering by filename, 187 # use the variable listed in the CMake perlasm line, available in 188 # ExtractPerlAsmFromCMakeFile. 189 return filter(lambda p: ("/crypto/fipsmodule/" in p) == want_bcm, asm) 190 191 192class AndroidCMake(object): 193 194 def __init__(self): 195 self.header = LicenseHeader("#") + """ 196# This file is created by generate_build_files.py. Do not edit manually. 197# To specify a custom path prefix, set BORINGSSL_ROOT before including this 198# file, or use list(TRANSFORM ... PREPEND) from CMake 3.12. 199 200""" 201 202 def PrintVariableSection(self, out, name, files): 203 out.write('set(%s\n' % name) 204 for f in sorted(files): 205 # Ideally adding the prefix would be the caller's job, but 206 # list(TRANSFORM ... PREPEND) is only available starting CMake 3.12. When 207 # sources.cmake is the source of truth, we can ask Android to either write 208 # a CMake function or update to 3.12. 209 out.write(' ${BORINGSSL_ROOT}%s\n' % f) 210 out.write(')\n') 211 212 def WriteFiles(self, files): 213 # The Android emulator uses a custom CMake buildsystem. 214 # 215 # TODO(crbug.com/boringssl/542): Move our various source lists into 216 # sources.cmake and have Android consume that directly. 217 with open('android-sources.cmake', 'w+') as out: 218 out.write(self.header) 219 220 self.PrintVariableSection(out, 'crypto_sources', files['crypto']) 221 self.PrintVariableSection(out, 'crypto_sources_asm', files['crypto_asm']) 222 self.PrintVariableSection(out, 'crypto_sources_nasm', 223 files['crypto_nasm']) 224 self.PrintVariableSection(out, 'ssl_sources', files['ssl']) 225 self.PrintVariableSection(out, 'tool_sources', files['tool']) 226 self.PrintVariableSection(out, 'test_support_sources', 227 files['test_support']) 228 self.PrintVariableSection(out, 'crypto_test_sources', 229 files['crypto_test']) 230 self.PrintVariableSection(out, 'ssl_test_sources', files['ssl_test']) 231 232 233class Bazel(object): 234 """Bazel outputs files suitable for including in Bazel files.""" 235 236 def __init__(self): 237 self.firstSection = True 238 self.header = \ 239"""# This file is created by generate_build_files.py. Do not edit manually. 240 241""" 242 243 def PrintVariableSection(self, out, name, files): 244 if not self.firstSection: 245 out.write('\n') 246 self.firstSection = False 247 248 out.write('%s = [\n' % name) 249 for f in sorted(files): 250 out.write(' "%s",\n' % PathOf(f)) 251 out.write(']\n') 252 253 def WriteFiles(self, files): 254 with open('BUILD.generated.bzl', 'w+') as out: 255 out.write(self.header) 256 257 self.PrintVariableSection(out, 'ssl_headers', files['ssl_headers']) 258 self.PrintVariableSection(out, 'fips_fragments', files['fips_fragments']) 259 self.PrintVariableSection( 260 out, 'ssl_internal_headers', files['ssl_internal_headers']) 261 self.PrintVariableSection(out, 'ssl_sources', files['ssl']) 262 self.PrintVariableSection(out, 'crypto_headers', files['crypto_headers']) 263 self.PrintVariableSection( 264 out, 'crypto_internal_headers', files['crypto_internal_headers']) 265 self.PrintVariableSection(out, 'crypto_sources', files['crypto']) 266 self.PrintVariableSection(out, 'crypto_sources_asm', files['crypto_asm']) 267 self.PrintVariableSection(out, 'crypto_sources_nasm', files['crypto_nasm']) 268 self.PrintVariableSection( 269 out, 'pki_internal_headers', files['pki_internal_headers']) 270 self.PrintVariableSection(out, 'pki_sources', files['pki']) 271 self.PrintVariableSection(out, 'tool_sources', files['tool']) 272 self.PrintVariableSection(out, 'tool_headers', files['tool_headers']) 273 274 with open('BUILD.generated_tests.bzl', 'w+') as out: 275 out.write(self.header) 276 277 out.write('test_support_sources = [\n') 278 for filename in sorted(files['test_support'] + 279 files['test_support_headers'] + 280 files['crypto_internal_headers'] + 281 files['pki_internal_headers'] + 282 files['ssl_internal_headers']): 283 out.write(' "%s",\n' % PathOf(filename)) 284 285 out.write(']\n') 286 287 self.PrintVariableSection(out, 'crypto_test_sources', 288 files['crypto_test']) 289 self.PrintVariableSection(out, 'ssl_test_sources', files['ssl_test']) 290 self.PrintVariableSection(out, 'pki_test_sources', 291 files['pki_test']) 292 self.PrintVariableSection(out, 'crypto_test_data', 293 files['crypto_test_data']) 294 self.PrintVariableSection(out, 'pki_test_data', 295 files['pki_test_data']) 296 self.PrintVariableSection(out, 'urandom_test_sources', 297 files['urandom_test']) 298 299 300class Eureka(object): 301 302 def __init__(self): 303 self.header = LicenseHeader("#") + """ 304# This file is created by generate_build_files.py. Do not edit manually. 305 306""" 307 308 def PrintVariableSection(self, out, name, files): 309 out.write('%s := \\\n' % name) 310 for f in sorted(files): 311 out.write(' %s\\\n' % f) 312 out.write('\n') 313 314 def WriteFiles(self, files): 315 # Legacy Android.mk format 316 with open('eureka.mk', 'w+') as makefile: 317 makefile.write(self.header) 318 319 self.PrintVariableSection(makefile, 'crypto_sources', files['crypto']) 320 self.PrintVariableSection(makefile, 'crypto_sources_asm', 321 files['crypto_asm']) 322 self.PrintVariableSection(makefile, 'crypto_sources_nasm', 323 files['crypto_nasm']) 324 self.PrintVariableSection(makefile, 'ssl_sources', files['ssl']) 325 self.PrintVariableSection(makefile, 'tool_sources', files['tool']) 326 327 328class GN(object): 329 330 def __init__(self): 331 self.firstSection = True 332 self.header = LicenseHeader("#") + """ 333# This file is created by generate_build_files.py. Do not edit manually. 334 335""" 336 337 def PrintVariableSection(self, out, name, files): 338 if not self.firstSection: 339 out.write('\n') 340 self.firstSection = False 341 342 out.write('%s = [\n' % name) 343 for f in sorted(files): 344 out.write(' "%s",\n' % f) 345 out.write(']\n') 346 347 def WriteFiles(self, files): 348 with open('BUILD.generated.gni', 'w+') as out: 349 out.write(self.header) 350 351 self.PrintVariableSection(out, 'crypto_sources', 352 files['crypto'] + 353 files['crypto_internal_headers']) 354 self.PrintVariableSection(out, 'crypto_sources_asm', files['crypto_asm']) 355 self.PrintVariableSection(out, 'crypto_sources_nasm', 356 files['crypto_nasm']) 357 self.PrintVariableSection(out, 'crypto_headers', 358 files['crypto_headers']) 359 self.PrintVariableSection(out, 'ssl_sources', 360 files['ssl'] + files['ssl_internal_headers']) 361 self.PrintVariableSection(out, 'ssl_headers', files['ssl_headers']) 362 self.PrintVariableSection(out, 'pki_sources', 363 files['pki']) 364 self.PrintVariableSection(out, 'pki_internal_headers', 365 files['pki_internal_headers']) 366 self.PrintVariableSection(out, 'tool_sources', 367 files['tool'] + files['tool_headers']) 368 369 fuzzers = [os.path.splitext(os.path.basename(fuzzer))[0] 370 for fuzzer in files['fuzz']] 371 self.PrintVariableSection(out, 'fuzzers', fuzzers) 372 373 with open('BUILD.generated_tests.gni', 'w+') as out: 374 self.firstSection = True 375 out.write(self.header) 376 377 self.PrintVariableSection(out, 'test_support_sources', 378 files['test_support'] + 379 files['test_support_headers']) 380 self.PrintVariableSection(out, 'crypto_test_sources', 381 files['crypto_test']) 382 self.PrintVariableSection(out, 'crypto_test_data', 383 files['crypto_test_data']) 384 self.PrintVariableSection(out, 'pki_test_data', 385 files['pki_test_data']) 386 self.PrintVariableSection(out, 'ssl_test_sources', files['ssl_test']) 387 self.PrintVariableSection(out, 'pki_test_sources', files['pki_test']) 388 389 390class GYP(object): 391 392 def __init__(self): 393 self.header = LicenseHeader("#") + """ 394# This file is created by generate_build_files.py. Do not edit manually. 395 396""" 397 398 def PrintVariableSection(self, out, name, files): 399 out.write(' \'%s\': [\n' % name) 400 for f in sorted(files): 401 out.write(' \'%s\',\n' % f) 402 out.write(' ],\n') 403 404 def WriteFiles(self, files): 405 with open('boringssl.gypi', 'w+') as gypi: 406 gypi.write(self.header + '{\n \'variables\': {\n') 407 408 self.PrintVariableSection(gypi, 'boringssl_ssl_sources', 409 files['ssl'] + files['ssl_headers'] + 410 files['ssl_internal_headers']) 411 self.PrintVariableSection(gypi, 'boringssl_crypto_sources', 412 files['crypto'] + files['crypto_headers'] + 413 files['crypto_internal_headers']) 414 self.PrintVariableSection(gypi, 'boringssl_crypto_asm_sources', 415 files['crypto_asm']) 416 self.PrintVariableSection(gypi, 'boringssl_crypto_nasm_sources', 417 files['crypto_nasm']) 418 419 gypi.write(' }\n}\n') 420 421class CMake(object): 422 423 def __init__(self): 424 self.header = LicenseHeader("#") + R''' 425# This file is created by generate_build_files.py. Do not edit manually. 426 427cmake_minimum_required(VERSION 3.12) 428 429project(BoringSSL LANGUAGES C CXX) 430 431set(CMAKE_CXX_STANDARD 14) 432set(CMAKE_CXX_STANDARD_REQUIRED ON) 433set(CMAKE_C_STANDARD 11) 434set(CMAKE_C_STANDARD_REQUIRED ON) 435if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 436 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fno-common -fno-exceptions -fno-rtti") 437 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fno-common") 438endif() 439 440# pthread_rwlock_t requires a feature flag on glibc. 441if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 442 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_XOPEN_SOURCE=700") 443endif() 444 445if(WIN32) 446 add_definitions(-D_HAS_EXCEPTIONS=0) 447 add_definitions(-DWIN32_LEAN_AND_MEAN) 448 add_definitions(-DNOMINMAX) 449 # Allow use of fopen. 450 add_definitions(-D_CRT_SECURE_NO_WARNINGS) 451endif() 452 453add_definitions(-DBORINGSSL_IMPLEMENTATION) 454 455if(OPENSSL_NO_ASM) 456 add_definitions(-DOPENSSL_NO_ASM) 457else() 458 # On x86 and x86_64 Windows, we use the NASM output. 459 if(WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|x86_64|amd64|x86|i[3-6]86") 460 enable_language(ASM_NASM) 461 set(OPENSSL_NASM TRUE) 462 set(CMAKE_ASM_NASM_FLAGS "${CMAKE_ASM_NASM_FLAGS} -gcv8") 463 else() 464 enable_language(ASM) 465 set(OPENSSL_ASM TRUE) 466 # Work around https://gitlab.kitware.com/cmake/cmake/-/issues/20771 in older 467 # CMake versions. 468 if(APPLE AND CMAKE_VERSION VERSION_LESS 3.19) 469 if(CMAKE_OSX_SYSROOT) 470 set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -isysroot \"${CMAKE_OSX_SYSROOT}\"") 471 endif() 472 foreach(arch ${CMAKE_OSX_ARCHITECTURES}) 473 set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -arch ${arch}") 474 endforeach() 475 endif() 476 if(NOT WIN32) 477 set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,--noexecstack") 478 endif() 479 # Clang's integerated assembler does not support debug symbols. 480 if(NOT CMAKE_ASM_COMPILER_ID MATCHES "Clang") 481 set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,-g") 482 endif() 483 endif() 484endif() 485 486if(BUILD_SHARED_LIBS) 487 add_definitions(-DBORINGSSL_SHARED_LIBRARY) 488 # Enable position-independent code globally. This is needed because 489 # some library targets are OBJECT libraries. 490 set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) 491endif() 492 493''' 494 495 def PrintLibrary(self, out, name, files, libs=[]): 496 out.write('add_library(\n') 497 out.write(' %s\n\n' % name) 498 499 for f in sorted(files): 500 out.write(' %s\n' % PathOf(f)) 501 502 out.write(')\n\n') 503 if libs: 504 out.write('target_link_libraries(%s %s)\n\n' % (name, ' '.join(libs))) 505 506 def PrintExe(self, out, name, files, libs): 507 out.write('add_executable(\n') 508 out.write(' %s\n\n' % name) 509 510 for f in sorted(files): 511 out.write(' %s\n' % PathOf(f)) 512 513 out.write(')\n\n') 514 out.write('target_link_libraries(%s %s)\n\n' % (name, ' '.join(libs))) 515 516 def PrintVariable(self, out, name, files): 517 out.write('set(\n') 518 out.write(' %s\n\n' % name) 519 for f in sorted(files): 520 out.write(' %s\n' % PathOf(f)) 521 out.write(')\n\n') 522 523 def WriteFiles(self, files): 524 with open('CMakeLists.txt', 'w+') as cmake: 525 cmake.write(self.header) 526 527 self.PrintVariable(cmake, 'CRYPTO_SOURCES_ASM', files['crypto_asm']) 528 self.PrintVariable(cmake, 'CRYPTO_SOURCES_NASM', files['crypto_nasm']) 529 530 cmake.write( 531R'''if(OPENSSL_ASM) 532 list(APPEND CRYPTO_SOURCES_ASM_USED ${CRYPTO_SOURCES_ASM}) 533endif() 534if(OPENSSL_NASM) 535 list(APPEND CRYPTO_SOURCES_ASM_USED ${CRYPTO_SOURCES_NASM}) 536endif() 537 538''') 539 540 self.PrintLibrary(cmake, 'crypto', 541 files['crypto'] + ['${CRYPTO_SOURCES_ASM_USED}']) 542 cmake.write('target_include_directories(crypto PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/include>)\n\n') 543 self.PrintLibrary(cmake, 'ssl', files['ssl'], ['crypto']) 544 self.PrintExe(cmake, 'bssl', files['tool'], ['ssl', 'crypto']) 545 546 cmake.write( 547R'''if(NOT ANDROID) 548 find_package(Threads REQUIRED) 549 target_link_libraries(crypto Threads::Threads) 550endif() 551 552if(WIN32) 553 target_link_libraries(crypto ws2_32) 554endif() 555 556''') 557 558class JSON(object): 559 def WriteFiles(self, files): 560 with open('sources.json', 'w+') as f: 561 json.dump(files, f, sort_keys=True, indent=2) 562 563def FindCMakeFiles(directory): 564 """Returns list of all CMakeLists.txt files recursively in directory.""" 565 cmakefiles = [] 566 567 for (path, _, filenames) in os.walk(directory): 568 for filename in filenames: 569 if filename == 'CMakeLists.txt': 570 cmakefiles.append(os.path.join(path, filename)) 571 572 return cmakefiles 573 574def OnlyFIPSFragments(path, dent, is_dir): 575 return is_dir or (path.startswith( 576 os.path.join('src', 'crypto', 'fipsmodule', '')) and 577 NoTests(path, dent, is_dir)) 578 579def NoTestsNorFIPSFragments(path, dent, is_dir): 580 return (NoTests(path, dent, is_dir) and 581 (is_dir or not OnlyFIPSFragments(path, dent, is_dir))) 582 583def NoTests(path, dent, is_dir): 584 """Filter function that can be passed to FindCFiles in order to remove test 585 sources.""" 586 if is_dir: 587 return dent != 'test' 588 return 'test.' not in dent 589 590 591def AllFiles(path, dent, is_dir): 592 """Filter function that can be passed to FindCFiles in order to include all 593 sources.""" 594 return True 595 596 597def NoTestRunnerFiles(path, dent, is_dir): 598 """Filter function that can be passed to FindCFiles or FindHeaderFiles in 599 order to exclude test runner files.""" 600 # NOTE(martinkr): This prevents .h/.cc files in src/ssl/test/runner, which 601 # are in their own subpackage, from being included in boringssl/BUILD files. 602 return not is_dir or dent != 'runner' 603 604 605def SSLHeaderFiles(path, dent, is_dir): 606 return dent in ['ssl.h', 'tls1.h', 'ssl23.h', 'ssl3.h', 'dtls1.h', 'srtp.h'] 607 608 609def FindCFiles(directory, filter_func): 610 """Recurses through directory and returns a list of paths to all the C source 611 files that pass filter_func.""" 612 cfiles = [] 613 614 for (path, dirnames, filenames) in os.walk(directory): 615 for filename in filenames: 616 if not filename.endswith('.c') and not filename.endswith('.cc'): 617 continue 618 if not filter_func(path, filename, False): 619 continue 620 cfiles.append(os.path.join(path, filename)) 621 622 for (i, dirname) in enumerate(dirnames): 623 if not filter_func(path, dirname, True): 624 del dirnames[i] 625 626 cfiles.sort() 627 return cfiles 628 629 630def FindHeaderFiles(directory, filter_func): 631 """Recurses through directory and returns a list of paths to all the header files that pass filter_func.""" 632 hfiles = [] 633 634 for (path, dirnames, filenames) in os.walk(directory): 635 for filename in filenames: 636 if not filename.endswith('.h'): 637 continue 638 if not filter_func(path, filename, False): 639 continue 640 hfiles.append(os.path.join(path, filename)) 641 642 for (i, dirname) in enumerate(dirnames): 643 if not filter_func(path, dirname, True): 644 del dirnames[i] 645 646 hfiles.sort() 647 return hfiles 648 649 650def ExtractPerlAsmFromCMakeFile(cmakefile): 651 """Parses the contents of the CMakeLists.txt file passed as an argument and 652 returns a list of all the perlasm() directives found in the file.""" 653 perlasms = [] 654 with open(cmakefile) as f: 655 for line in f: 656 line = line.strip() 657 if not line.startswith('perlasm('): 658 continue 659 if not line.endswith(')'): 660 raise ValueError('Bad perlasm line in %s' % cmakefile) 661 # Remove "perlasm(" from start and ")" from end 662 params = line[8:-1].split() 663 if len(params) < 4: 664 raise ValueError('Bad perlasm line in %s' % cmakefile) 665 perlasms.append({ 666 'arch': params[1], 667 'output': os.path.join(os.path.dirname(cmakefile), params[2]), 668 'input': os.path.join(os.path.dirname(cmakefile), params[3]), 669 'extra_args': params[4:], 670 }) 671 672 return perlasms 673 674 675def ReadPerlAsmOperations(): 676 """Returns a list of all perlasm() directives found in CMake config files in 677 src/.""" 678 perlasms = [] 679 cmakefiles = FindCMakeFiles('src') 680 681 for cmakefile in cmakefiles: 682 perlasms.extend(ExtractPerlAsmFromCMakeFile(cmakefile)) 683 684 return perlasms 685 686 687def PerlAsm(output_filename, input_filename, perlasm_style, extra_args): 688 """Runs the a perlasm script and puts the output into output_filename.""" 689 base_dir = os.path.dirname(output_filename) 690 if not os.path.isdir(base_dir): 691 os.makedirs(base_dir) 692 subprocess.check_call( 693 ['perl', input_filename, perlasm_style] + extra_args + [output_filename]) 694 695 696def WriteAsmFiles(perlasms): 697 """Generates asm files from perlasm directives for each supported OS x 698 platform combination.""" 699 asmfiles = {} 700 701 for perlasm in perlasms: 702 for (osname, arch, perlasm_style, extra_args, asm_ext) in OS_ARCH_COMBOS: 703 if arch != perlasm['arch']: 704 continue 705 # TODO(https://crbug.com/boringssl/542): Now that we incorporate osname in 706 # the output filename, the asm files can just go in a single directory. 707 # For now, we keep them in target-specific directories to avoid breaking 708 # downstream scripts. 709 key = (osname, arch) 710 outDir = '%s-%s' % key 711 output = perlasm['output'] 712 if not output.startswith('src'): 713 raise ValueError('output missing src: %s' % output) 714 output = os.path.join(outDir, output[4:]) 715 output = '%s-%s.%s' % (output, osname, asm_ext) 716 PerlAsm(output, perlasm['input'], perlasm_style, 717 extra_args + perlasm['extra_args']) 718 asmfiles.setdefault(key, []).append(output) 719 720 for (key, non_perl_asm_files) in NON_PERL_FILES.items(): 721 asmfiles.setdefault(key, []).extend(non_perl_asm_files) 722 723 for files in asmfiles.values(): 724 files.sort() 725 726 return asmfiles 727 728 729def ExtractVariablesFromCMakeFile(cmakefile): 730 """Parses the contents of the CMakeLists.txt file passed as an argument and 731 returns a dictionary of exported source lists.""" 732 variables = {} 733 in_set_command = False 734 set_command = [] 735 with open(cmakefile) as f: 736 for line in f: 737 if '#' in line: 738 line = line[:line.index('#')] 739 line = line.strip() 740 741 if not in_set_command: 742 if line.startswith('set('): 743 in_set_command = True 744 set_command = [] 745 elif line == ')': 746 in_set_command = False 747 if not set_command: 748 raise ValueError('Empty set command') 749 variables[set_command[0]] = set_command[1:] 750 else: 751 set_command.extend([c for c in line.split(' ') if c]) 752 753 if in_set_command: 754 raise ValueError('Unfinished set command') 755 return variables 756 757 758def PrefixWithSrc(files): 759 return ['src/' + x for x in files] 760 761 762def main(platforms): 763 cmake = ExtractVariablesFromCMakeFile(os.path.join('src', 'sources.cmake')) 764 crypto_c_files = (FindCFiles(os.path.join('src', 'crypto'), NoTestsNorFIPSFragments) + 765 FindCFiles(os.path.join('src', 'third_party', 'fiat'), NoTestsNorFIPSFragments)) 766 fips_fragments = FindCFiles(os.path.join('src', 'crypto', 'fipsmodule'), OnlyFIPSFragments) 767 ssl_source_files = FindCFiles(os.path.join('src', 'ssl'), NoTests) 768 tool_h_files = FindHeaderFiles(os.path.join('src', 'tool'), AllFiles) 769 770 # BCM shared library C files 771 bcm_crypto_c_files = [ 772 os.path.join('src', 'crypto', 'fipsmodule', 'bcm.c') 773 ] 774 775 # Generate err_data.c 776 with open('err_data.c', 'w+') as err_data: 777 subprocess.check_call(['go', 'run', 'err_data_generate.go'], 778 cwd=os.path.join('src', 'crypto', 'err'), 779 stdout=err_data) 780 crypto_c_files.append('err_data.c') 781 crypto_c_files.sort() 782 783 test_support_h_files = ( 784 FindHeaderFiles(os.path.join('src', 'crypto', 'test'), AllFiles) + 785 FindHeaderFiles(os.path.join('src', 'ssl', 'test'), NoTestRunnerFiles)) 786 787 crypto_test_files = [] 788 if EMBED_TEST_DATA: 789 # Generate crypto_test_data.cc 790 with open('crypto_test_data.cc', 'w+') as out: 791 subprocess.check_call( 792 ['go', 'run', 'util/embed_test_data.go'] + cmake['CRYPTO_TEST_DATA'], 793 cwd='src', 794 stdout=out) 795 crypto_test_files.append('crypto_test_data.cc') 796 797 crypto_test_files += PrefixWithSrc(cmake['CRYPTO_TEST_SOURCES']) 798 crypto_test_files.sort() 799 800 fuzz_c_files = FindCFiles(os.path.join('src', 'fuzz'), NoTests) 801 802 ssl_h_files = FindHeaderFiles(os.path.join('src', 'include', 'openssl'), 803 SSLHeaderFiles) 804 805 pki_internal_h_files = FindHeaderFiles(os.path.join('src', 'pki'), AllFiles); 806 807 def NotSSLHeaderFiles(path, filename, is_dir): 808 return not SSLHeaderFiles(path, filename, is_dir) 809 crypto_h_files = FindHeaderFiles(os.path.join('src', 'include', 'openssl'), 810 NotSSLHeaderFiles) 811 812 ssl_internal_h_files = FindHeaderFiles(os.path.join('src', 'ssl'), NoTests) 813 crypto_internal_h_files = ( 814 FindHeaderFiles(os.path.join('src', 'crypto'), NoTests) + 815 FindHeaderFiles(os.path.join('src', 'third_party', 'fiat'), NoTests)) 816 817 asm_outputs = sorted(WriteAsmFiles(ReadPerlAsmOperations()).items()) 818 819 # Generate combined source lists for gas and nasm. Some files appear in 820 # multiple per-platform lists, so we de-duplicate. 821 # 822 # TODO(https://crbug.com/boringssl/542): It would be simpler to build the 823 # combined source lists directly. This is a remnant of the previous assembly 824 # strategy. When we move to pre-generated assembly files, this will be 825 # removed. 826 asm_sources = set() 827 nasm_sources = set() 828 for ((osname, arch), asm_files) in asm_outputs: 829 if (osname, arch) in (('win', 'x86'), ('win', 'x86_64')): 830 nasm_sources.update(asm_files) 831 else: 832 asm_sources.update(asm_files) 833 834 files = { 835 'bcm_crypto': bcm_crypto_c_files, 836 'crypto': crypto_c_files, 837 'crypto_asm': sorted(list(asm_sources)), 838 'crypto_nasm': sorted(list(nasm_sources)), 839 'crypto_headers': crypto_h_files, 840 'crypto_internal_headers': crypto_internal_h_files, 841 'crypto_test': crypto_test_files, 842 'crypto_test_data': sorted(PrefixWithSrc(cmake['CRYPTO_TEST_DATA'])), 843 'fips_fragments': fips_fragments, 844 'fuzz': fuzz_c_files, 845 'pki': PrefixWithSrc(cmake['PKI_SOURCES']), 846 'pki_internal_headers': sorted(list(pki_internal_h_files)), 847 'pki_test': PrefixWithSrc(cmake['PKI_TEST_SOURCES']), 848 'pki_test_data': PrefixWithSrc(cmake['PKI_TEST_DATA']), 849 'ssl': ssl_source_files, 850 'ssl_headers': ssl_h_files, 851 'ssl_internal_headers': ssl_internal_h_files, 852 'ssl_test': PrefixWithSrc(cmake['SSL_TEST_SOURCES']), 853 'tool': PrefixWithSrc(cmake['BSSL_SOURCES']), 854 'tool_headers': tool_h_files, 855 'test_support': PrefixWithSrc(cmake['TEST_SUPPORT_SOURCES']), 856 'test_support_headers': test_support_h_files, 857 'urandom_test': PrefixWithSrc(cmake['URANDOM_TEST_SOURCES']), 858 } 859 860 for platform in platforms: 861 platform.WriteFiles(files) 862 863 return 0 864 865ALL_PLATFORMS = { 866 'android': Android, 867 'android-cmake': AndroidCMake, 868 'bazel': Bazel, 869 'cmake': CMake, 870 'eureka': Eureka, 871 'gn': GN, 872 'gyp': GYP, 873 'json': JSON, 874} 875 876if __name__ == '__main__': 877 parser = optparse.OptionParser( 878 usage='Usage: %%prog [--prefix=<path>] [all|%s]' % 879 '|'.join(sorted(ALL_PLATFORMS.keys()))) 880 parser.add_option('--prefix', dest='prefix', 881 help='For Bazel, prepend argument to all source files') 882 parser.add_option( 883 '--embed_test_data', type='choice', dest='embed_test_data', 884 action='store', default="true", choices=["true", "false"], 885 help='For Bazel or GN, don\'t embed data files in crypto_test_data.cc') 886 options, args = parser.parse_args(sys.argv[1:]) 887 PREFIX = options.prefix 888 EMBED_TEST_DATA = (options.embed_test_data == "true") 889 890 if not args: 891 parser.print_help() 892 sys.exit(1) 893 894 if 'all' in args: 895 platforms = [platform() for platform in ALL_PLATFORMS.values()] 896 else: 897 platforms = [] 898 for s in args: 899 platform = ALL_PLATFORMS.get(s) 900 if platform is None: 901 parser.print_help() 902 sys.exit(1) 903 platforms.append(platform()) 904 905 sys.exit(main(platforms)) 906