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. 28OS_ARCH_COMBOS = [ 29 ('apple', 'arm', 'ios32', [], 'S'), 30 ('apple', 'aarch64', 'ios64', [], 'S'), 31 ('apple', 'x86', 'macosx', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'), 32 ('apple', 'x86_64', 'macosx', [], 'S'), 33 ('linux', 'arm', 'linux32', [], 'S'), 34 ('linux', 'aarch64', 'linux64', [], 'S'), 35 ('linux', 'ppc64le', 'linux64le', [], 'S'), 36 ('linux', 'x86', 'elf', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'), 37 ('linux', 'x86_64', 'elf', [], 'S'), 38 ('win', 'x86', 'win32n', ['-DOPENSSL_IA32_SSE2'], 'asm'), 39 ('win', 'x86_64', 'nasm', [], 'asm'), 40 ('win', 'aarch64', 'win64', [], 'S'), 41] 42 43# NON_PERL_FILES enumerates assembly files that are not processed by the 44# perlasm system. 45NON_PERL_FILES = { 46 ('linux', 'arm'): [ 47 'src/crypto/curve25519/asm/x25519-asm-arm.S', 48 'src/crypto/poly1305/poly1305_arm_asm.S', 49 ], 50 ('linux', 'x86_64'): [ 51 'src/crypto/hrss/asm/poly_rq_mul.S', 52 ], 53} 54 55PREFIX = None 56EMBED_TEST_DATA = True 57 58 59def PathOf(x): 60 return x if not PREFIX else os.path.join(PREFIX, x) 61 62 63class Android(object): 64 65 def __init__(self): 66 self.header = \ 67"""# Copyright (C) 2015 The Android Open Source Project 68# 69# Licensed under the Apache License, Version 2.0 (the "License"); 70# you may not use this file except in compliance with the License. 71# You may obtain a copy of the License at 72# 73# http://www.apache.org/licenses/LICENSE-2.0 74# 75# Unless required by applicable law or agreed to in writing, software 76# distributed under the License is distributed on an "AS IS" BASIS, 77# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 78# See the License for the specific language governing permissions and 79# limitations under the License. 80 81# This file is created by generate_build_files.py. Do not edit manually. 82""" 83 84 def PrintVariableSection(self, out, name, files): 85 out.write('%s := \\\n' % name) 86 for f in sorted(files): 87 out.write(' %s\\\n' % f) 88 out.write('\n') 89 90 def WriteFiles(self, files, asm_outputs): 91 # New Android.bp format 92 with open('sources.bp', 'w+') as blueprint: 93 blueprint.write(self.header.replace('#', '//')) 94 95 # Separate out BCM files to allow different compilation rules (specific to Android FIPS) 96 bcm_c_files = files['bcm_crypto'] 97 non_bcm_c_files = [file for file in files['crypto'] if file not in bcm_c_files] 98 non_bcm_asm = self.FilterBcmAsm(asm_outputs, False) 99 bcm_asm = self.FilterBcmAsm(asm_outputs, True) 100 101 self.PrintDefaults(blueprint, 'libcrypto_sources', non_bcm_c_files, non_bcm_asm) 102 self.PrintDefaults(blueprint, 'libcrypto_bcm_sources', bcm_c_files, bcm_asm) 103 self.PrintDefaults(blueprint, 'libssl_sources', files['ssl']) 104 self.PrintDefaults(blueprint, 'bssl_sources', files['tool']) 105 self.PrintDefaults(blueprint, 'boringssl_test_support_sources', files['test_support']) 106 self.PrintDefaults(blueprint, 'boringssl_crypto_test_sources', files['crypto_test']) 107 self.PrintDefaults(blueprint, 'boringssl_ssl_test_sources', files['ssl_test']) 108 109 # Legacy Android.mk format, only used by Trusty in new branches 110 with open('sources.mk', 'w+') as makefile: 111 makefile.write(self.header) 112 makefile.write('\n') 113 self.PrintVariableSection(makefile, 'crypto_sources', files['crypto']) 114 115 for ((osname, arch), asm_files) in asm_outputs: 116 if osname != 'linux': 117 continue 118 self.PrintVariableSection( 119 makefile, '%s_%s_sources' % (osname, arch), asm_files) 120 121 def PrintDefaults(self, blueprint, name, files, asm_outputs={}): 122 """Print a cc_defaults section from a list of C files and optionally assembly outputs""" 123 blueprint.write('\n') 124 blueprint.write('cc_defaults {\n') 125 blueprint.write(' name: "%s",\n' % name) 126 blueprint.write(' srcs: [\n') 127 for f in sorted(files): 128 blueprint.write(' "%s",\n' % f) 129 blueprint.write(' ],\n') 130 131 if asm_outputs: 132 blueprint.write(' target: {\n') 133 for ((osname, arch), asm_files) in asm_outputs: 134 if osname != 'linux' or arch == 'ppc64le': 135 continue 136 if arch == 'aarch64': 137 arch = 'arm64' 138 139 blueprint.write(' linux_%s: {\n' % arch) 140 blueprint.write(' srcs: [\n') 141 for f in sorted(asm_files): 142 blueprint.write(' "%s",\n' % f) 143 blueprint.write(' ],\n') 144 blueprint.write(' },\n') 145 blueprint.write(' },\n') 146 147 blueprint.write('}\n') 148 149 def FilterBcmAsm(self, asm, want_bcm): 150 """Filter a list of assembly outputs based on whether they belong in BCM 151 152 Args: 153 asm: Assembly file lists to filter 154 want_bcm: If true then include BCM files, otherwise do not 155 156 Returns: 157 A copy of |asm| with files filtered according to |want_bcm| 158 """ 159 return [(archinfo, filter(lambda p: ("/crypto/fipsmodule/" in p) == want_bcm, files)) 160 for (archinfo, files) in asm] 161 162 163class AndroidCMake(object): 164 165 def __init__(self): 166 self.header = \ 167"""# Copyright (C) 2019 The Android Open Source Project 168# 169# Licensed under the Apache License, Version 2.0 (the "License"); 170# you may not use this file except in compliance with the License. 171# You may obtain a copy of the License at 172# 173# http://www.apache.org/licenses/LICENSE-2.0 174# 175# Unless required by applicable law or agreed to in writing, software 176# distributed under the License is distributed on an "AS IS" BASIS, 177# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 178# See the License for the specific language governing permissions and 179# limitations under the License. 180 181# This file is created by generate_build_files.py. Do not edit manually. 182# To specify a custom path prefix, set BORINGSSL_ROOT before including this 183# file, or use list(TRANSFORM ... PREPEND) from CMake 3.12. 184 185""" 186 187 def PrintVariableSection(self, out, name, files): 188 out.write('set(%s\n' % name) 189 for f in sorted(files): 190 # Ideally adding the prefix would be the caller's job, but 191 # list(TRANSFORM ... PREPEND) is only available starting CMake 3.12. When 192 # sources.cmake is the source of truth, we can ask Android to either write 193 # a CMake function or update to 3.12. 194 out.write(' ${BORINGSSL_ROOT}%s\n' % f) 195 out.write(')\n') 196 197 def WriteFiles(self, files, asm_outputs): 198 # The Android emulator uses a custom CMake buildsystem. 199 # 200 # TODO(davidben): Move our various source lists into sources.cmake and have 201 # Android consume that directly. 202 with open('android-sources.cmake', 'w+') as out: 203 out.write(self.header) 204 205 self.PrintVariableSection(out, 'crypto_sources', files['crypto']) 206 self.PrintVariableSection(out, 'ssl_sources', files['ssl']) 207 self.PrintVariableSection(out, 'tool_sources', files['tool']) 208 self.PrintVariableSection(out, 'test_support_sources', 209 files['test_support']) 210 self.PrintVariableSection(out, 'crypto_test_sources', 211 files['crypto_test']) 212 self.PrintVariableSection(out, 'ssl_test_sources', files['ssl_test']) 213 214 for ((osname, arch), asm_files) in asm_outputs: 215 self.PrintVariableSection( 216 out, 'crypto_sources_%s_%s' % (osname, arch), asm_files) 217 218 219class Bazel(object): 220 """Bazel outputs files suitable for including in Bazel files.""" 221 222 def __init__(self): 223 self.firstSection = True 224 self.header = \ 225"""# This file is created by generate_build_files.py. Do not edit manually. 226 227""" 228 229 def PrintVariableSection(self, out, name, files): 230 if not self.firstSection: 231 out.write('\n') 232 self.firstSection = False 233 234 out.write('%s = [\n' % name) 235 for f in sorted(files): 236 out.write(' "%s",\n' % PathOf(f)) 237 out.write(']\n') 238 239 def WriteFiles(self, files, asm_outputs): 240 with open('BUILD.generated.bzl', 'w+') as out: 241 out.write(self.header) 242 243 self.PrintVariableSection(out, 'ssl_headers', files['ssl_headers']) 244 self.PrintVariableSection(out, 'fips_fragments', files['fips_fragments']) 245 self.PrintVariableSection( 246 out, 'ssl_internal_headers', files['ssl_internal_headers']) 247 self.PrintVariableSection(out, 'ssl_sources', files['ssl']) 248 self.PrintVariableSection(out, 'crypto_headers', files['crypto_headers']) 249 self.PrintVariableSection( 250 out, 'crypto_internal_headers', files['crypto_internal_headers']) 251 self.PrintVariableSection(out, 'crypto_sources', files['crypto']) 252 self.PrintVariableSection(out, 'tool_sources', files['tool']) 253 self.PrintVariableSection(out, 'tool_headers', files['tool_headers']) 254 255 for ((osname, arch), asm_files) in asm_outputs: 256 self.PrintVariableSection( 257 out, 'crypto_sources_%s_%s' % (osname, arch), asm_files) 258 259 with open('BUILD.generated_tests.bzl', 'w+') as out: 260 out.write(self.header) 261 262 out.write('test_support_sources = [\n') 263 for filename in sorted(files['test_support'] + 264 files['test_support_headers'] + 265 files['crypto_internal_headers'] + 266 files['ssl_internal_headers']): 267 if os.path.basename(filename) == 'malloc.cc': 268 continue 269 out.write(' "%s",\n' % PathOf(filename)) 270 271 out.write(']\n') 272 273 self.PrintVariableSection(out, 'crypto_test_sources', 274 files['crypto_test']) 275 self.PrintVariableSection(out, 'ssl_test_sources', files['ssl_test']) 276 self.PrintVariableSection(out, 'crypto_test_data', 277 files['crypto_test_data']) 278 self.PrintVariableSection(out, 'urandom_test_sources', 279 files['urandom_test']) 280 281 282class Eureka(object): 283 284 def __init__(self): 285 self.header = \ 286"""# Copyright (C) 2017 The Android Open Source Project 287# 288# Licensed under the Apache License, Version 2.0 (the "License"); 289# you may not use this file except in compliance with the License. 290# You may obtain a copy of the License at 291# 292# http://www.apache.org/licenses/LICENSE-2.0 293# 294# Unless required by applicable law or agreed to in writing, software 295# distributed under the License is distributed on an "AS IS" BASIS, 296# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 297# See the License for the specific language governing permissions and 298# limitations under the License. 299 300# This file is created by generate_build_files.py. Do not edit manually. 301 302""" 303 304 def PrintVariableSection(self, out, name, files): 305 out.write('%s := \\\n' % name) 306 for f in sorted(files): 307 out.write(' %s\\\n' % f) 308 out.write('\n') 309 310 def WriteFiles(self, files, asm_outputs): 311 # Legacy Android.mk format 312 with open('eureka.mk', 'w+') as makefile: 313 makefile.write(self.header) 314 315 self.PrintVariableSection(makefile, 'crypto_sources', files['crypto']) 316 self.PrintVariableSection(makefile, 'ssl_sources', files['ssl']) 317 self.PrintVariableSection(makefile, 'tool_sources', files['tool']) 318 319 for ((osname, arch), asm_files) in asm_outputs: 320 if osname != 'linux': 321 continue 322 self.PrintVariableSection( 323 makefile, '%s_%s_sources' % (osname, arch), asm_files) 324 325 326class GN(object): 327 328 def __init__(self): 329 self.firstSection = True 330 self.header = \ 331"""# Copyright (c) 2016 The Chromium Authors. All rights reserved. 332# Use of this source code is governed by a BSD-style license that can be 333# found in the LICENSE file. 334 335# This file is created by generate_build_files.py. Do not edit manually. 336 337""" 338 339 def PrintVariableSection(self, out, name, files): 340 if not self.firstSection: 341 out.write('\n') 342 self.firstSection = False 343 344 out.write('%s = [\n' % name) 345 for f in sorted(files): 346 out.write(' "%s",\n' % f) 347 out.write(']\n') 348 349 def WriteFiles(self, files, asm_outputs): 350 with open('BUILD.generated.gni', 'w+') as out: 351 out.write(self.header) 352 353 self.PrintVariableSection(out, 'crypto_sources', 354 files['crypto'] + 355 files['crypto_internal_headers']) 356 self.PrintVariableSection(out, 'crypto_headers', 357 files['crypto_headers']) 358 self.PrintVariableSection(out, 'ssl_sources', 359 files['ssl'] + files['ssl_internal_headers']) 360 self.PrintVariableSection(out, 'ssl_headers', files['ssl_headers']) 361 self.PrintVariableSection(out, 'tool_sources', 362 files['tool'] + files['tool_headers']) 363 364 for ((osname, arch), asm_files) in asm_outputs: 365 self.PrintVariableSection( 366 out, 'crypto_sources_%s_%s' % (osname, arch), asm_files) 367 368 fuzzers = [os.path.splitext(os.path.basename(fuzzer))[0] 369 for fuzzer in files['fuzz']] 370 self.PrintVariableSection(out, 'fuzzers', fuzzers) 371 372 with open('BUILD.generated_tests.gni', 'w+') as out: 373 self.firstSection = True 374 out.write(self.header) 375 376 self.PrintVariableSection(out, 'test_support_sources', 377 files['test_support'] + 378 files['test_support_headers']) 379 self.PrintVariableSection(out, 'crypto_test_sources', 380 files['crypto_test']) 381 self.PrintVariableSection(out, 'crypto_test_data', 382 files['crypto_test_data']) 383 self.PrintVariableSection(out, 'ssl_test_sources', files['ssl_test']) 384 385 386class GYP(object): 387 388 def __init__(self): 389 self.header = \ 390"""# Copyright (c) 2016 The Chromium Authors. All rights reserved. 391# Use of this source code is governed by a BSD-style license that can be 392# found in the LICENSE file. 393 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, asm_outputs): 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 415 for ((osname, arch), asm_files) in asm_outputs: 416 self.PrintVariableSection(gypi, 'boringssl_%s_%s_sources' % 417 (osname, arch), asm_files) 418 419 gypi.write(' }\n}\n') 420 421class CMake(object): 422 423 def __init__(self): 424 self.header = \ 425R'''# Copyright (c) 2019 The Chromium Authors. All rights reserved. 426# Use of this source code is governed by a BSD-style license that can be 427# found in the LICENSE file. 428 429# This file is created by generate_build_files.py. Do not edit manually. 430 431cmake_minimum_required(VERSION 3.5) 432 433project(BoringSSL LANGUAGES C CXX) 434 435if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 436 set(CLANG 1) 437endif() 438 439if(CMAKE_COMPILER_IS_GNUCXX OR CLANG) 440 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fvisibility=hidden -fno-common -fno-exceptions -fno-rtti") 441 if(APPLE) 442 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 443 endif() 444 445 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fno-common -std=c11") 446endif() 447 448# pthread_rwlock_t requires a feature flag. 449if(NOT WIN32) 450 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_XOPEN_SOURCE=700") 451endif() 452 453if(WIN32) 454 add_definitions(-D_HAS_EXCEPTIONS=0) 455 add_definitions(-DWIN32_LEAN_AND_MEAN) 456 add_definitions(-DNOMINMAX) 457 # Allow use of fopen. 458 add_definitions(-D_CRT_SECURE_NO_WARNINGS) 459 # VS 2017 and higher supports STL-only warning suppressions. 460 # A bug in CMake < 3.13.0 may cause the space in this value to 461 # cause issues when building with NASM. In that case, update CMake. 462 add_definitions("-D_STL_EXTRA_DISABLED_WARNINGS=4774 4987") 463endif() 464 465add_definitions(-DBORINGSSL_IMPLEMENTATION) 466 467# CMake's iOS support uses Apple's multiple-architecture toolchain. It takes an 468# architecture list from CMAKE_OSX_ARCHITECTURES, leaves CMAKE_SYSTEM_PROCESSOR 469# alone, and expects all architecture-specific logic to be conditioned within 470# the source files rather than the build. This does not work for our assembly 471# files, so we fix CMAKE_SYSTEM_PROCESSOR and only support single-architecture 472# builds. 473if(NOT OPENSSL_NO_ASM AND CMAKE_OSX_ARCHITECTURES) 474 list(LENGTH CMAKE_OSX_ARCHITECTURES NUM_ARCHES) 475 if(NOT NUM_ARCHES EQUAL 1) 476 message(FATAL_ERROR "Universal binaries not supported.") 477 endif() 478 list(GET CMAKE_OSX_ARCHITECTURES 0 CMAKE_SYSTEM_PROCESSOR) 479endif() 480 481if(OPENSSL_NO_ASM) 482 add_definitions(-DOPENSSL_NO_ASM) 483 set(ARCH "generic") 484elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") 485 set(ARCH "x86_64") 486elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64") 487 set(ARCH "x86_64") 488elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") 489 # cmake reports AMD64 on Windows, but we might be building for 32-bit. 490 if(CMAKE_SIZEOF_VOID_P EQUAL 8) 491 set(ARCH "x86_64") 492 else() 493 set(ARCH "x86") 494 endif() 495elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86") 496 set(ARCH "x86") 497elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "i386") 498 set(ARCH "x86") 499elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "i686") 500 set(ARCH "x86") 501elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") 502 set(ARCH "aarch64") 503elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") 504 set(ARCH "aarch64") 505# Apple A12 Bionic chipset which is added in iPhone XS/XS Max/XR uses arm64e architecture. 506elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64e") 507 set(ARCH "aarch64") 508elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm*") 509 set(ARCH "arm") 510elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "mips") 511 # Just to avoid the “unknown processor” error. 512 set(ARCH "generic") 513elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le") 514 set(ARCH "ppc64le") 515else() 516 message(FATAL_ERROR "Unknown processor:" ${CMAKE_SYSTEM_PROCESSOR}) 517endif() 518 519if(NOT OPENSSL_NO_ASM) 520 if(UNIX) 521 enable_language(ASM) 522 523 # Clang's integerated assembler does not support debug symbols. 524 if(NOT CMAKE_ASM_COMPILER_ID MATCHES "Clang") 525 set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,-g") 526 endif() 527 528 # CMake does not add -isysroot and -arch flags to assembly. 529 if(APPLE) 530 if(CMAKE_OSX_SYSROOT) 531 set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -isysroot \"${CMAKE_OSX_SYSROOT}\"") 532 endif() 533 foreach(arch ${CMAKE_OSX_ARCHITECTURES}) 534 set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -arch ${arch}") 535 endforeach() 536 endif() 537 else() 538 set(CMAKE_ASM_NASM_FLAGS "${CMAKE_ASM_NASM_FLAGS} -gcv8") 539 enable_language(ASM_NASM) 540 endif() 541endif() 542 543if(BUILD_SHARED_LIBS) 544 add_definitions(-DBORINGSSL_SHARED_LIBRARY) 545 # Enable position-independent code globally. This is needed because 546 # some library targets are OBJECT libraries. 547 set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) 548endif() 549 550include_directories(src/include) 551 552''' 553 554 def PrintLibrary(self, out, name, files): 555 out.write('add_library(\n') 556 out.write(' %s\n\n' % name) 557 558 for f in sorted(files): 559 out.write(' %s\n' % PathOf(f)) 560 561 out.write(')\n\n') 562 563 def PrintExe(self, out, name, files, libs): 564 out.write('add_executable(\n') 565 out.write(' %s\n\n' % name) 566 567 for f in sorted(files): 568 out.write(' %s\n' % PathOf(f)) 569 570 out.write(')\n\n') 571 out.write('target_link_libraries(%s %s)\n\n' % (name, ' '.join(libs))) 572 573 def PrintSection(self, out, name, files): 574 out.write('set(\n') 575 out.write(' %s\n\n' % name) 576 for f in sorted(files): 577 out.write(' %s\n' % PathOf(f)) 578 out.write(')\n\n') 579 580 def WriteFiles(self, files, asm_outputs): 581 with open('CMakeLists.txt', 'w+') as cmake: 582 cmake.write(self.header) 583 584 for ((osname, arch), asm_files) in asm_outputs: 585 self.PrintSection(cmake, 'CRYPTO_%s_%s_SOURCES' % (osname, arch), 586 asm_files) 587 588 cmake.write( 589R'''if(APPLE) 590 set(CRYPTO_ARCH_SOURCES ${CRYPTO_apple_${ARCH}_SOURCES}) 591elseif(UNIX) 592 set(CRYPTO_ARCH_SOURCES ${CRYPTO_linux_${ARCH}_SOURCES}) 593elseif(WIN32) 594 set(CRYPTO_ARCH_SOURCES ${CRYPTO_win_${ARCH}_SOURCES}) 595endif() 596 597''') 598 599 self.PrintLibrary(cmake, 'crypto', 600 files['crypto'] + ['${CRYPTO_ARCH_SOURCES}']) 601 self.PrintLibrary(cmake, 'ssl', files['ssl']) 602 self.PrintExe(cmake, 'bssl', files['tool'], ['ssl', 'crypto']) 603 604 cmake.write( 605R'''if(NOT WIN32 AND NOT ANDROID) 606 target_link_libraries(crypto pthread) 607endif() 608 609if(WIN32) 610 target_link_libraries(bssl ws2_32) 611endif() 612 613''') 614 615class JSON(object): 616 def WriteFiles(self, files, asm_outputs): 617 sources = dict(files) 618 for ((osname, arch), asm_files) in asm_outputs: 619 sources['crypto_%s_%s' % (osname, arch)] = asm_files 620 with open('sources.json', 'w+') as f: 621 json.dump(sources, f, sort_keys=True, indent=2) 622 623def FindCMakeFiles(directory): 624 """Returns list of all CMakeLists.txt files recursively in directory.""" 625 cmakefiles = [] 626 627 for (path, _, filenames) in os.walk(directory): 628 for filename in filenames: 629 if filename == 'CMakeLists.txt': 630 cmakefiles.append(os.path.join(path, filename)) 631 632 return cmakefiles 633 634def OnlyFIPSFragments(path, dent, is_dir): 635 return is_dir or (path.startswith( 636 os.path.join('src', 'crypto', 'fipsmodule', '')) and 637 NoTests(path, dent, is_dir)) 638 639def NoTestsNorFIPSFragments(path, dent, is_dir): 640 return (NoTests(path, dent, is_dir) and 641 (is_dir or not OnlyFIPSFragments(path, dent, is_dir))) 642 643def NoTests(path, dent, is_dir): 644 """Filter function that can be passed to FindCFiles in order to remove test 645 sources.""" 646 if is_dir: 647 return dent != 'test' 648 return 'test.' not in dent 649 650 651def OnlyTests(path, dent, is_dir): 652 """Filter function that can be passed to FindCFiles in order to remove 653 non-test sources.""" 654 if is_dir: 655 return dent != 'test' 656 return '_test.' in dent 657 658 659def AllFiles(path, dent, is_dir): 660 """Filter function that can be passed to FindCFiles in order to include all 661 sources.""" 662 return True 663 664 665def NoTestRunnerFiles(path, dent, is_dir): 666 """Filter function that can be passed to FindCFiles or FindHeaderFiles in 667 order to exclude test runner files.""" 668 # NOTE(martinkr): This prevents .h/.cc files in src/ssl/test/runner, which 669 # are in their own subpackage, from being included in boringssl/BUILD files. 670 return not is_dir or dent != 'runner' 671 672 673def NotGTestSupport(path, dent, is_dir): 674 return 'gtest' not in dent and 'abi_test' not in dent 675 676 677def SSLHeaderFiles(path, dent, is_dir): 678 return dent in ['ssl.h', 'tls1.h', 'ssl23.h', 'ssl3.h', 'dtls1.h', 'srtp.h'] 679 680 681def FindCFiles(directory, filter_func): 682 """Recurses through directory and returns a list of paths to all the C source 683 files that pass filter_func.""" 684 cfiles = [] 685 686 for (path, dirnames, filenames) in os.walk(directory): 687 for filename in filenames: 688 if not filename.endswith('.c') and not filename.endswith('.cc'): 689 continue 690 if not filter_func(path, filename, False): 691 continue 692 cfiles.append(os.path.join(path, filename)) 693 694 for (i, dirname) in enumerate(dirnames): 695 if not filter_func(path, dirname, True): 696 del dirnames[i] 697 698 cfiles.sort() 699 return cfiles 700 701 702def FindHeaderFiles(directory, filter_func): 703 """Recurses through directory and returns a list of paths to all the header files that pass filter_func.""" 704 hfiles = [] 705 706 for (path, dirnames, filenames) in os.walk(directory): 707 for filename in filenames: 708 if not filename.endswith('.h'): 709 continue 710 if not filter_func(path, filename, False): 711 continue 712 hfiles.append(os.path.join(path, filename)) 713 714 for (i, dirname) in enumerate(dirnames): 715 if not filter_func(path, dirname, True): 716 del dirnames[i] 717 718 hfiles.sort() 719 return hfiles 720 721 722def ExtractPerlAsmFromCMakeFile(cmakefile): 723 """Parses the contents of the CMakeLists.txt file passed as an argument and 724 returns a list of all the perlasm() directives found in the file.""" 725 perlasms = [] 726 with open(cmakefile) as f: 727 for line in f: 728 line = line.strip() 729 if not line.startswith('perlasm('): 730 continue 731 if not line.endswith(')'): 732 raise ValueError('Bad perlasm line in %s' % cmakefile) 733 # Remove "perlasm(" from start and ")" from end 734 params = line[8:-1].split() 735 if len(params) < 2: 736 raise ValueError('Bad perlasm line in %s' % cmakefile) 737 perlasms.append({ 738 'extra_args': params[2:], 739 'input': os.path.join(os.path.dirname(cmakefile), params[1]), 740 'output': os.path.join(os.path.dirname(cmakefile), params[0]), 741 }) 742 743 return perlasms 744 745 746def ReadPerlAsmOperations(): 747 """Returns a list of all perlasm() directives found in CMake config files in 748 src/.""" 749 perlasms = [] 750 cmakefiles = FindCMakeFiles('src') 751 752 for cmakefile in cmakefiles: 753 perlasms.extend(ExtractPerlAsmFromCMakeFile(cmakefile)) 754 755 return perlasms 756 757 758def PerlAsm(output_filename, input_filename, perlasm_style, extra_args): 759 """Runs the a perlasm script and puts the output into output_filename.""" 760 base_dir = os.path.dirname(output_filename) 761 if not os.path.isdir(base_dir): 762 os.makedirs(base_dir) 763 subprocess.check_call( 764 ['perl', input_filename, perlasm_style] + extra_args + [output_filename]) 765 766 767def ArchForAsmFilename(filename): 768 """Returns the architectures that a given asm file should be compiled for 769 based on substrings in the filename.""" 770 771 if 'x86_64' in filename or 'avx2' in filename: 772 return ['x86_64'] 773 elif ('x86' in filename and 'x86_64' not in filename) or '586' in filename: 774 return ['x86'] 775 elif 'armx' in filename: 776 return ['arm', 'aarch64'] 777 elif 'armv8' in filename: 778 return ['aarch64'] 779 elif 'arm' in filename: 780 return ['arm'] 781 elif 'ppc' in filename: 782 return ['ppc64le'] 783 else: 784 raise ValueError('Unknown arch for asm filename: ' + filename) 785 786 787def WriteAsmFiles(perlasms): 788 """Generates asm files from perlasm directives for each supported OS x 789 platform combination.""" 790 asmfiles = {} 791 792 for osarch in OS_ARCH_COMBOS: 793 (osname, arch, perlasm_style, extra_args, asm_ext) = osarch 794 key = (osname, arch) 795 outDir = '%s-%s' % key 796 797 for perlasm in perlasms: 798 filename = os.path.basename(perlasm['input']) 799 output = perlasm['output'] 800 if not output.startswith('src'): 801 raise ValueError('output missing src: %s' % output) 802 output = os.path.join(outDir, output[4:]) 803 if output.endswith('-armx.${ASM_EXT}'): 804 output = output.replace('-armx', 805 '-armx64' if arch == 'aarch64' else '-armx32') 806 output = output.replace('${ASM_EXT}', asm_ext) 807 808 if arch in ArchForAsmFilename(filename): 809 PerlAsm(output, perlasm['input'], perlasm_style, 810 perlasm['extra_args'] + extra_args) 811 asmfiles.setdefault(key, []).append(output) 812 813 for (key, non_perl_asm_files) in NON_PERL_FILES.items(): 814 asmfiles.setdefault(key, []).extend(non_perl_asm_files) 815 816 for files in asmfiles.values(): 817 files.sort() 818 819 return asmfiles 820 821 822def ExtractVariablesFromCMakeFile(cmakefile): 823 """Parses the contents of the CMakeLists.txt file passed as an argument and 824 returns a dictionary of exported source lists.""" 825 variables = {} 826 in_set_command = False 827 set_command = [] 828 with open(cmakefile) as f: 829 for line in f: 830 if '#' in line: 831 line = line[:line.index('#')] 832 line = line.strip() 833 834 if not in_set_command: 835 if line.startswith('set('): 836 in_set_command = True 837 set_command = [] 838 elif line == ')': 839 in_set_command = False 840 if not set_command: 841 raise ValueError('Empty set command') 842 variables[set_command[0]] = set_command[1:] 843 else: 844 set_command.extend([c for c in line.split(' ') if c]) 845 846 if in_set_command: 847 raise ValueError('Unfinished set command') 848 return variables 849 850 851def main(platforms): 852 cmake = ExtractVariablesFromCMakeFile(os.path.join('src', 'sources.cmake')) 853 crypto_c_files = (FindCFiles(os.path.join('src', 'crypto'), NoTestsNorFIPSFragments) + 854 FindCFiles(os.path.join('src', 'third_party', 'fiat'), NoTestsNorFIPSFragments)) 855 fips_fragments = FindCFiles(os.path.join('src', 'crypto', 'fipsmodule'), OnlyFIPSFragments) 856 ssl_source_files = FindCFiles(os.path.join('src', 'ssl'), NoTests) 857 tool_c_files = FindCFiles(os.path.join('src', 'tool'), NoTests) 858 tool_h_files = FindHeaderFiles(os.path.join('src', 'tool'), AllFiles) 859 860 # BCM shared library C files 861 bcm_crypto_c_files = [ 862 os.path.join('src', 'crypto', 'fipsmodule', 'bcm.c') 863 ] 864 865 # Generate err_data.c 866 with open('err_data.c', 'w+') as err_data: 867 subprocess.check_call(['go', 'run', 'err_data_generate.go'], 868 cwd=os.path.join('src', 'crypto', 'err'), 869 stdout=err_data) 870 crypto_c_files.append('err_data.c') 871 crypto_c_files.sort() 872 873 test_support_c_files = FindCFiles(os.path.join('src', 'crypto', 'test'), 874 NotGTestSupport) 875 test_support_h_files = ( 876 FindHeaderFiles(os.path.join('src', 'crypto', 'test'), AllFiles) + 877 FindHeaderFiles(os.path.join('src', 'ssl', 'test'), NoTestRunnerFiles)) 878 879 crypto_test_files = [] 880 if EMBED_TEST_DATA: 881 # Generate crypto_test_data.cc 882 with open('crypto_test_data.cc', 'w+') as out: 883 subprocess.check_call( 884 ['go', 'run', 'util/embed_test_data.go'] + cmake['CRYPTO_TEST_DATA'], 885 cwd='src', 886 stdout=out) 887 crypto_test_files += ['crypto_test_data.cc'] 888 889 crypto_test_files += FindCFiles(os.path.join('src', 'crypto'), OnlyTests) 890 crypto_test_files += [ 891 'src/crypto/test/abi_test.cc', 892 'src/crypto/test/file_test_gtest.cc', 893 'src/crypto/test/gtest_main.cc', 894 ] 895 # urandom_test.cc is in a separate binary so that it can be test PRNG 896 # initialisation. 897 crypto_test_files = [ 898 file for file in crypto_test_files 899 if not file.endswith('/urandom_test.cc') 900 ] 901 crypto_test_files.sort() 902 903 ssl_test_files = FindCFiles(os.path.join('src', 'ssl'), OnlyTests) 904 ssl_test_files += [ 905 'src/crypto/test/abi_test.cc', 906 'src/crypto/test/gtest_main.cc', 907 ] 908 ssl_test_files.sort() 909 910 urandom_test_files = [ 911 'src/crypto/fipsmodule/rand/urandom_test.cc', 912 ] 913 914 fuzz_c_files = FindCFiles(os.path.join('src', 'fuzz'), NoTests) 915 916 ssl_h_files = FindHeaderFiles(os.path.join('src', 'include', 'openssl'), 917 SSLHeaderFiles) 918 919 def NotSSLHeaderFiles(path, filename, is_dir): 920 return not SSLHeaderFiles(path, filename, is_dir) 921 crypto_h_files = FindHeaderFiles(os.path.join('src', 'include', 'openssl'), 922 NotSSLHeaderFiles) 923 924 ssl_internal_h_files = FindHeaderFiles(os.path.join('src', 'ssl'), NoTests) 925 crypto_internal_h_files = ( 926 FindHeaderFiles(os.path.join('src', 'crypto'), NoTests) + 927 FindHeaderFiles(os.path.join('src', 'third_party', 'fiat'), NoTests)) 928 929 files = { 930 'bcm_crypto': bcm_crypto_c_files, 931 'crypto': crypto_c_files, 932 'crypto_headers': crypto_h_files, 933 'crypto_internal_headers': crypto_internal_h_files, 934 'crypto_test': crypto_test_files, 935 'crypto_test_data': sorted('src/' + x for x in cmake['CRYPTO_TEST_DATA']), 936 'fips_fragments': fips_fragments, 937 'fuzz': fuzz_c_files, 938 'ssl': ssl_source_files, 939 'ssl_headers': ssl_h_files, 940 'ssl_internal_headers': ssl_internal_h_files, 941 'ssl_test': ssl_test_files, 942 'tool': tool_c_files, 943 'tool_headers': tool_h_files, 944 'test_support': test_support_c_files, 945 'test_support_headers': test_support_h_files, 946 'urandom_test': urandom_test_files, 947 } 948 949 asm_outputs = sorted(WriteAsmFiles(ReadPerlAsmOperations()).items()) 950 951 for platform in platforms: 952 platform.WriteFiles(files, asm_outputs) 953 954 return 0 955 956ALL_PLATFORMS = { 957 'android': Android, 958 'android-cmake': AndroidCMake, 959 'bazel': Bazel, 960 'cmake': CMake, 961 'eureka': Eureka, 962 'gn': GN, 963 'gyp': GYP, 964 'json': JSON, 965} 966 967if __name__ == '__main__': 968 parser = optparse.OptionParser(usage='Usage: %%prog [--prefix=<path>] [%s]' % 969 '|'.join(sorted(ALL_PLATFORMS.keys()))) 970 parser.add_option('--prefix', dest='prefix', 971 help='For Bazel, prepend argument to all source files') 972 parser.add_option( 973 '--embed_test_data', type='choice', dest='embed_test_data', 974 action='store', default="true", choices=["true", "false"], 975 help='For Bazel or GN, don\'t embed data files in crypto_test_data.cc') 976 options, args = parser.parse_args(sys.argv[1:]) 977 PREFIX = options.prefix 978 EMBED_TEST_DATA = (options.embed_test_data == "true") 979 980 if not args: 981 parser.print_help() 982 sys.exit(1) 983 984 platforms = [] 985 for s in args: 986 platform = ALL_PLATFORMS.get(s) 987 if platform is None: 988 parser.print_help() 989 sys.exit(1) 990 platforms.append(platform()) 991 992 sys.exit(main(platforms)) 993