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 ('ios', 'arm', 'ios32', [], 'S'), 30 ('ios', 'aarch64', 'ios64', [], 'S'), 31 ('linux', 'arm', 'linux32', [], 'S'), 32 ('linux', 'aarch64', 'linux64', [], 'S'), 33 ('linux', 'ppc64le', 'linux64le', [], 'S'), 34 ('linux', 'x86', 'elf', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'), 35 ('linux', 'x86_64', 'elf', [], 'S'), 36 ('mac', 'x86', 'macosx', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'), 37 ('mac', 'x86_64', 'macosx', [], '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.0) 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++11 -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") 446 if((CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR CLANG) 447 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11") 448 else() 449 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") 450 endif() 451endif() 452 453# pthread_rwlock_t requires a feature flag. 454if(NOT WIN32) 455 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_XOPEN_SOURCE=700") 456endif() 457 458if(WIN32) 459 add_definitions(-D_HAS_EXCEPTIONS=0) 460 add_definitions(-DWIN32_LEAN_AND_MEAN) 461 add_definitions(-DNOMINMAX) 462 # Allow use of fopen. 463 add_definitions(-D_CRT_SECURE_NO_WARNINGS) 464 # VS 2017 and higher supports STL-only warning suppressions. 465 # A bug in CMake < 3.13.0 may cause the space in this value to 466 # cause issues when building with NASM. In that case, update CMake. 467 add_definitions("-D_STL_EXTRA_DISABLED_WARNINGS=4774 4987") 468endif() 469 470add_definitions(-DBORINGSSL_IMPLEMENTATION) 471 472# CMake's iOS support uses Apple's multiple-architecture toolchain. It takes an 473# architecture list from CMAKE_OSX_ARCHITECTURES, leaves CMAKE_SYSTEM_PROCESSOR 474# alone, and expects all architecture-specific logic to be conditioned within 475# the source files rather than the build. This does not work for our assembly 476# files, so we fix CMAKE_SYSTEM_PROCESSOR and only support single-architecture 477# builds. 478if(NOT OPENSSL_NO_ASM AND CMAKE_OSX_ARCHITECTURES) 479 list(LENGTH CMAKE_OSX_ARCHITECTURES NUM_ARCHES) 480 if(NOT ${NUM_ARCHES} EQUAL 1) 481 message(FATAL_ERROR "Universal binaries not supported.") 482 endif() 483 list(GET CMAKE_OSX_ARCHITECTURES 0 CMAKE_SYSTEM_PROCESSOR) 484endif() 485 486if(OPENSSL_NO_ASM) 487 add_definitions(-DOPENSSL_NO_ASM) 488 set(ARCH "generic") 489elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") 490 set(ARCH "x86_64") 491elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "amd64") 492 set(ARCH "x86_64") 493elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64") 494 # cmake reports AMD64 on Windows, but we might be building for 32-bit. 495 if(CMAKE_SIZEOF_VOID_P EQUAL 8) 496 set(ARCH "x86_64") 497 else() 498 set(ARCH "x86") 499 endif() 500elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86") 501 set(ARCH "x86") 502elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i386") 503 set(ARCH "x86") 504elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686") 505 set(ARCH "x86") 506elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") 507 set(ARCH "aarch64") 508elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64") 509 set(ARCH "aarch64") 510# Apple A12 Bionic chipset which is added in iPhone XS/XS Max/XR uses arm64e architecture. 511elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64e") 512 set(ARCH "aarch64") 513elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm*") 514 set(ARCH "arm") 515elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "mips") 516 # Just to avoid the “unknown processor” error. 517 set(ARCH "generic") 518elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le") 519 set(ARCH "ppc64le") 520else() 521 message(FATAL_ERROR "Unknown processor:" ${CMAKE_SYSTEM_PROCESSOR}) 522endif() 523 524if(NOT OPENSSL_NO_ASM) 525 if(UNIX) 526 enable_language(ASM) 527 528 # Clang's integerated assembler does not support debug symbols. 529 if(NOT CMAKE_ASM_COMPILER_ID MATCHES "Clang") 530 set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,-g") 531 endif() 532 533 # CMake does not add -isysroot and -arch flags to assembly. 534 if(APPLE) 535 if(CMAKE_OSX_SYSROOT) 536 set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -isysroot \"${CMAKE_OSX_SYSROOT}\"") 537 endif() 538 foreach(arch ${CMAKE_OSX_ARCHITECTURES}) 539 set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -arch ${arch}") 540 endforeach() 541 endif() 542 else() 543 set(CMAKE_ASM_NASM_FLAGS "${CMAKE_ASM_NASM_FLAGS} -gcv8") 544 enable_language(ASM_NASM) 545 endif() 546endif() 547 548if(BUILD_SHARED_LIBS) 549 add_definitions(-DBORINGSSL_SHARED_LIBRARY) 550 # Enable position-independent code globally. This is needed because 551 # some library targets are OBJECT libraries. 552 set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) 553endif() 554 555include_directories(src/include) 556 557''' 558 559 def PrintLibrary(self, out, name, files): 560 out.write('add_library(\n') 561 out.write(' %s\n\n' % name) 562 563 for f in sorted(files): 564 out.write(' %s\n' % PathOf(f)) 565 566 out.write(')\n\n') 567 568 def PrintExe(self, out, name, files, libs): 569 out.write('add_executable(\n') 570 out.write(' %s\n\n' % name) 571 572 for f in sorted(files): 573 out.write(' %s\n' % PathOf(f)) 574 575 out.write(')\n\n') 576 out.write('target_link_libraries(%s %s)\n\n' % (name, ' '.join(libs))) 577 578 def PrintSection(self, out, name, files): 579 out.write('set(\n') 580 out.write(' %s\n\n' % name) 581 for f in sorted(files): 582 out.write(' %s\n' % PathOf(f)) 583 out.write(')\n\n') 584 585 def WriteFiles(self, files, asm_outputs): 586 with open('CMakeLists.txt', 'w+') as cmake: 587 cmake.write(self.header) 588 589 for ((osname, arch), asm_files) in asm_outputs: 590 self.PrintSection(cmake, 'CRYPTO_%s_%s_SOURCES' % (osname, arch), 591 asm_files) 592 593 cmake.write( 594R'''if(APPLE AND ${ARCH} STREQUAL "aarch64") 595 set(CRYPTO_ARCH_SOURCES ${CRYPTO_ios_aarch64_SOURCES}) 596elseif(APPLE AND ${ARCH} STREQUAL "arm") 597 set(CRYPTO_ARCH_SOURCES ${CRYPTO_ios_arm_SOURCES}) 598elseif(APPLE) 599 set(CRYPTO_ARCH_SOURCES ${CRYPTO_mac_${ARCH}_SOURCES}) 600elseif(UNIX) 601 set(CRYPTO_ARCH_SOURCES ${CRYPTO_linux_${ARCH}_SOURCES}) 602elseif(WIN32) 603 set(CRYPTO_ARCH_SOURCES ${CRYPTO_win_${ARCH}_SOURCES}) 604endif() 605 606''') 607 608 self.PrintLibrary(cmake, 'crypto', 609 files['crypto'] + ['${CRYPTO_ARCH_SOURCES}']) 610 self.PrintLibrary(cmake, 'ssl', files['ssl']) 611 self.PrintExe(cmake, 'bssl', files['tool'], ['ssl', 'crypto']) 612 613 cmake.write( 614R'''if(NOT WIN32 AND NOT ANDROID) 615 target_link_libraries(crypto pthread) 616endif() 617 618if(WIN32) 619 target_link_libraries(bssl ws2_32) 620endif() 621 622''') 623 624class JSON(object): 625 def WriteFiles(self, files, asm_outputs): 626 sources = dict(files) 627 for ((osname, arch), asm_files) in asm_outputs: 628 sources['crypto_%s_%s' % (osname, arch)] = asm_files 629 with open('sources.json', 'w+') as f: 630 json.dump(sources, f, sort_keys=True, indent=2) 631 632def FindCMakeFiles(directory): 633 """Returns list of all CMakeLists.txt files recursively in directory.""" 634 cmakefiles = [] 635 636 for (path, _, filenames) in os.walk(directory): 637 for filename in filenames: 638 if filename == 'CMakeLists.txt': 639 cmakefiles.append(os.path.join(path, filename)) 640 641 return cmakefiles 642 643def OnlyFIPSFragments(path, dent, is_dir): 644 return is_dir or (path.startswith( 645 os.path.join('src', 'crypto', 'fipsmodule', '')) and 646 NoTests(path, dent, is_dir)) 647 648def NoTestsNorFIPSFragments(path, dent, is_dir): 649 return (NoTests(path, dent, is_dir) and 650 (is_dir or not OnlyFIPSFragments(path, dent, is_dir))) 651 652def NoTests(path, dent, is_dir): 653 """Filter function that can be passed to FindCFiles in order to remove test 654 sources.""" 655 if is_dir: 656 return dent != 'test' 657 return 'test.' not in dent 658 659 660def OnlyTests(path, dent, is_dir): 661 """Filter function that can be passed to FindCFiles in order to remove 662 non-test sources.""" 663 if is_dir: 664 return dent != 'test' 665 return '_test.' in dent 666 667 668def AllFiles(path, dent, is_dir): 669 """Filter function that can be passed to FindCFiles in order to include all 670 sources.""" 671 return True 672 673 674def NoTestRunnerFiles(path, dent, is_dir): 675 """Filter function that can be passed to FindCFiles or FindHeaderFiles in 676 order to exclude test runner files.""" 677 # NOTE(martinkr): This prevents .h/.cc files in src/ssl/test/runner, which 678 # are in their own subpackage, from being included in boringssl/BUILD files. 679 return not is_dir or dent != 'runner' 680 681 682def NotGTestSupport(path, dent, is_dir): 683 return 'gtest' not in dent and 'abi_test' not in dent 684 685 686def SSLHeaderFiles(path, dent, is_dir): 687 return dent in ['ssl.h', 'tls1.h', 'ssl23.h', 'ssl3.h', 'dtls1.h', 'srtp.h'] 688 689 690def FindCFiles(directory, filter_func): 691 """Recurses through directory and returns a list of paths to all the C source 692 files that pass filter_func.""" 693 cfiles = [] 694 695 for (path, dirnames, filenames) in os.walk(directory): 696 for filename in filenames: 697 if not filename.endswith('.c') and not filename.endswith('.cc'): 698 continue 699 if not filter_func(path, filename, False): 700 continue 701 cfiles.append(os.path.join(path, filename)) 702 703 for (i, dirname) in enumerate(dirnames): 704 if not filter_func(path, dirname, True): 705 del dirnames[i] 706 707 cfiles.sort() 708 return cfiles 709 710 711def FindHeaderFiles(directory, filter_func): 712 """Recurses through directory and returns a list of paths to all the header files that pass filter_func.""" 713 hfiles = [] 714 715 for (path, dirnames, filenames) in os.walk(directory): 716 for filename in filenames: 717 if not filename.endswith('.h'): 718 continue 719 if not filter_func(path, filename, False): 720 continue 721 hfiles.append(os.path.join(path, filename)) 722 723 for (i, dirname) in enumerate(dirnames): 724 if not filter_func(path, dirname, True): 725 del dirnames[i] 726 727 hfiles.sort() 728 return hfiles 729 730 731def ExtractPerlAsmFromCMakeFile(cmakefile): 732 """Parses the contents of the CMakeLists.txt file passed as an argument and 733 returns a list of all the perlasm() directives found in the file.""" 734 perlasms = [] 735 with open(cmakefile) as f: 736 for line in f: 737 line = line.strip() 738 if not line.startswith('perlasm('): 739 continue 740 if not line.endswith(')'): 741 raise ValueError('Bad perlasm line in %s' % cmakefile) 742 # Remove "perlasm(" from start and ")" from end 743 params = line[8:-1].split() 744 if len(params) < 2: 745 raise ValueError('Bad perlasm line in %s' % cmakefile) 746 perlasms.append({ 747 'extra_args': params[2:], 748 'input': os.path.join(os.path.dirname(cmakefile), params[1]), 749 'output': os.path.join(os.path.dirname(cmakefile), params[0]), 750 }) 751 752 return perlasms 753 754 755def ReadPerlAsmOperations(): 756 """Returns a list of all perlasm() directives found in CMake config files in 757 src/.""" 758 perlasms = [] 759 cmakefiles = FindCMakeFiles('src') 760 761 for cmakefile in cmakefiles: 762 perlasms.extend(ExtractPerlAsmFromCMakeFile(cmakefile)) 763 764 return perlasms 765 766 767def PerlAsm(output_filename, input_filename, perlasm_style, extra_args): 768 """Runs the a perlasm script and puts the output into output_filename.""" 769 base_dir = os.path.dirname(output_filename) 770 if not os.path.isdir(base_dir): 771 os.makedirs(base_dir) 772 subprocess.check_call( 773 ['perl', input_filename, perlasm_style] + extra_args + [output_filename]) 774 775 776def ArchForAsmFilename(filename): 777 """Returns the architectures that a given asm file should be compiled for 778 based on substrings in the filename.""" 779 780 if 'x86_64' in filename or 'avx2' in filename: 781 return ['x86_64'] 782 elif ('x86' in filename and 'x86_64' not in filename) or '586' in filename: 783 return ['x86'] 784 elif 'armx' in filename: 785 return ['arm', 'aarch64'] 786 elif 'armv8' in filename: 787 return ['aarch64'] 788 elif 'arm' in filename: 789 return ['arm'] 790 elif 'ppc' in filename: 791 return ['ppc64le'] 792 else: 793 raise ValueError('Unknown arch for asm filename: ' + filename) 794 795 796def WriteAsmFiles(perlasms): 797 """Generates asm files from perlasm directives for each supported OS x 798 platform combination.""" 799 asmfiles = {} 800 801 for osarch in OS_ARCH_COMBOS: 802 (osname, arch, perlasm_style, extra_args, asm_ext) = osarch 803 key = (osname, arch) 804 outDir = '%s-%s' % key 805 806 for perlasm in perlasms: 807 filename = os.path.basename(perlasm['input']) 808 output = perlasm['output'] 809 if not output.startswith('src'): 810 raise ValueError('output missing src: %s' % output) 811 output = os.path.join(outDir, output[4:]) 812 if output.endswith('-armx.${ASM_EXT}'): 813 output = output.replace('-armx', 814 '-armx64' if arch == 'aarch64' else '-armx32') 815 output = output.replace('${ASM_EXT}', asm_ext) 816 817 if arch in ArchForAsmFilename(filename): 818 PerlAsm(output, perlasm['input'], perlasm_style, 819 perlasm['extra_args'] + extra_args) 820 asmfiles.setdefault(key, []).append(output) 821 822 for (key, non_perl_asm_files) in NON_PERL_FILES.iteritems(): 823 asmfiles.setdefault(key, []).extend(non_perl_asm_files) 824 825 for files in asmfiles.itervalues(): 826 files.sort() 827 828 return asmfiles 829 830 831def ExtractVariablesFromCMakeFile(cmakefile): 832 """Parses the contents of the CMakeLists.txt file passed as an argument and 833 returns a dictionary of exported source lists.""" 834 variables = {} 835 in_set_command = False 836 set_command = [] 837 with open(cmakefile) as f: 838 for line in f: 839 if '#' in line: 840 line = line[:line.index('#')] 841 line = line.strip() 842 843 if not in_set_command: 844 if line.startswith('set('): 845 in_set_command = True 846 set_command = [] 847 elif line == ')': 848 in_set_command = False 849 if not set_command: 850 raise ValueError('Empty set command') 851 variables[set_command[0]] = set_command[1:] 852 else: 853 set_command.extend([c for c in line.split(' ') if c]) 854 855 if in_set_command: 856 raise ValueError('Unfinished set command') 857 return variables 858 859 860def main(platforms): 861 cmake = ExtractVariablesFromCMakeFile(os.path.join('src', 'sources.cmake')) 862 crypto_c_files = (FindCFiles(os.path.join('src', 'crypto'), NoTestsNorFIPSFragments) + 863 FindCFiles(os.path.join('src', 'third_party', 'fiat'), NoTestsNorFIPSFragments)) 864 fips_fragments = FindCFiles(os.path.join('src', 'crypto', 'fipsmodule'), OnlyFIPSFragments) 865 ssl_source_files = FindCFiles(os.path.join('src', 'ssl'), NoTests) 866 tool_c_files = FindCFiles(os.path.join('src', 'tool'), NoTests) 867 tool_h_files = FindHeaderFiles(os.path.join('src', 'tool'), AllFiles) 868 869 # BCM shared library C files 870 bcm_crypto_c_files = [ 871 os.path.join('src', 'crypto', 'fipsmodule', 'bcm.c') 872 ] 873 874 # Generate err_data.c 875 with open('err_data.c', 'w+') as err_data: 876 subprocess.check_call(['go', 'run', 'err_data_generate.go'], 877 cwd=os.path.join('src', 'crypto', 'err'), 878 stdout=err_data) 879 crypto_c_files.append('err_data.c') 880 crypto_c_files.sort() 881 882 test_support_c_files = FindCFiles(os.path.join('src', 'crypto', 'test'), 883 NotGTestSupport) 884 test_support_h_files = ( 885 FindHeaderFiles(os.path.join('src', 'crypto', 'test'), AllFiles) + 886 FindHeaderFiles(os.path.join('src', 'ssl', 'test'), NoTestRunnerFiles)) 887 888 crypto_test_files = [] 889 if EMBED_TEST_DATA: 890 # Generate crypto_test_data.cc 891 with open('crypto_test_data.cc', 'w+') as out: 892 subprocess.check_call( 893 ['go', 'run', 'util/embed_test_data.go'] + cmake['CRYPTO_TEST_DATA'], 894 cwd='src', 895 stdout=out) 896 crypto_test_files += ['crypto_test_data.cc'] 897 898 crypto_test_files += FindCFiles(os.path.join('src', 'crypto'), OnlyTests) 899 crypto_test_files += [ 900 'src/crypto/test/abi_test.cc', 901 'src/crypto/test/file_test_gtest.cc', 902 'src/crypto/test/gtest_main.cc', 903 ] 904 # urandom_test.cc is in a separate binary so that it can be test PRNG 905 # initialisation. 906 crypto_test_files = [ 907 file for file in crypto_test_files 908 if not file.endswith('/urandom_test.cc') 909 ] 910 crypto_test_files.sort() 911 912 ssl_test_files = FindCFiles(os.path.join('src', 'ssl'), OnlyTests) 913 ssl_test_files += [ 914 'src/crypto/test/abi_test.cc', 915 'src/crypto/test/gtest_main.cc', 916 ] 917 ssl_test_files.sort() 918 919 urandom_test_files = [ 920 'src/crypto/fipsmodule/rand/urandom_test.cc', 921 ] 922 923 fuzz_c_files = FindCFiles(os.path.join('src', 'fuzz'), NoTests) 924 925 ssl_h_files = FindHeaderFiles(os.path.join('src', 'include', 'openssl'), 926 SSLHeaderFiles) 927 928 def NotSSLHeaderFiles(path, filename, is_dir): 929 return not SSLHeaderFiles(path, filename, is_dir) 930 crypto_h_files = FindHeaderFiles(os.path.join('src', 'include', 'openssl'), 931 NotSSLHeaderFiles) 932 933 ssl_internal_h_files = FindHeaderFiles(os.path.join('src', 'ssl'), NoTests) 934 crypto_internal_h_files = ( 935 FindHeaderFiles(os.path.join('src', 'crypto'), NoTests) + 936 FindHeaderFiles(os.path.join('src', 'third_party', 'fiat'), NoTests)) 937 938 files = { 939 'bcm_crypto': bcm_crypto_c_files, 940 'crypto': crypto_c_files, 941 'crypto_headers': crypto_h_files, 942 'crypto_internal_headers': crypto_internal_h_files, 943 'crypto_test': crypto_test_files, 944 'crypto_test_data': sorted('src/' + x for x in cmake['CRYPTO_TEST_DATA']), 945 'fips_fragments': fips_fragments, 946 'fuzz': fuzz_c_files, 947 'ssl': ssl_source_files, 948 'ssl_headers': ssl_h_files, 949 'ssl_internal_headers': ssl_internal_h_files, 950 'ssl_test': ssl_test_files, 951 'tool': tool_c_files, 952 'tool_headers': tool_h_files, 953 'test_support': test_support_c_files, 954 'test_support_headers': test_support_h_files, 955 'urandom_test': urandom_test_files, 956 } 957 958 asm_outputs = sorted(WriteAsmFiles(ReadPerlAsmOperations()).iteritems()) 959 960 for platform in platforms: 961 platform.WriteFiles(files, asm_outputs) 962 963 return 0 964 965ALL_PLATFORMS = { 966 'android': Android, 967 'android-cmake': AndroidCMake, 968 'bazel': Bazel, 969 'cmake': CMake, 970 'eureka': Eureka, 971 'gn': GN, 972 'gyp': GYP, 973 'json': JSON, 974} 975 976if __name__ == '__main__': 977 parser = optparse.OptionParser(usage='Usage: %%prog [--prefix=<path>] [%s]' % 978 '|'.join(sorted(ALL_PLATFORMS.keys()))) 979 parser.add_option('--prefix', dest='prefix', 980 help='For Bazel, prepend argument to all source files') 981 parser.add_option( 982 '--embed_test_data', type='choice', dest='embed_test_data', 983 action='store', default="true", choices=["true", "false"], 984 help='For Bazel or GN, don\'t embed data files in crypto_test_data.cc') 985 options, args = parser.parse_args(sys.argv[1:]) 986 PREFIX = options.prefix 987 EMBED_TEST_DATA = (options.embed_test_data == "true") 988 989 if not args: 990 parser.print_help() 991 sys.exit(1) 992 993 platforms = [] 994 for s in args: 995 platform = ALL_PLATFORMS.get(s) 996 if platform is None: 997 parser.print_help() 998 sys.exit(1) 999 platforms.append(platform()) 1000 1001 sys.exit(main(platforms)) 1002