您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

551 行
17 KiB

  1. # Copyright (c) 2015, Google Inc.
  2. #
  3. # Permission to use, copy, modify, and/or distribute this software for any
  4. # purpose with or without fee is hereby granted, provided that the above
  5. # copyright notice and this permission notice appear in all copies.
  6. #
  7. # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. """Enumerates the BoringSSL source in src/ and either generates two gypi files
  15. (boringssl.gypi and boringssl_tests.gypi) for Chromium, or generates
  16. source-list files for Android."""
  17. import os
  18. import subprocess
  19. import sys
  20. import json
  21. # OS_ARCH_COMBOS maps from OS and platform to the OpenSSL assembly "style" for
  22. # that platform and the extension used by asm files.
  23. OS_ARCH_COMBOS = [
  24. ('linux', 'arm', 'linux32', [], 'S'),
  25. ('linux', 'aarch64', 'linux64', [], 'S'),
  26. ('linux', 'x86', 'elf', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'),
  27. ('linux', 'x86_64', 'elf', [], 'S'),
  28. ('mac', 'x86', 'macosx', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'),
  29. ('mac', 'x86_64', 'macosx', [], 'S'),
  30. ('win', 'x86', 'win32n', ['-DOPENSSL_IA32_SSE2'], 'asm'),
  31. ('win', 'x86_64', 'nasm', [], 'asm'),
  32. ]
  33. # NON_PERL_FILES enumerates assembly files that are not processed by the
  34. # perlasm system.
  35. NON_PERL_FILES = {
  36. ('linux', 'arm'): [
  37. 'src/crypto/chacha/chacha_vec_arm.S',
  38. 'src/crypto/cpu-arm-asm.S',
  39. 'src/crypto/curve25519/asm/x25519-arm.S',
  40. 'src/crypto/poly1305/poly1305_arm_asm.S',
  41. ],
  42. }
  43. class Chromium(object):
  44. def __init__(self):
  45. self.header = \
  46. """# Copyright (c) 2014 The Chromium Authors. All rights reserved.
  47. # Use of this source code is governed by a BSD-style license that can be
  48. # found in the LICENSE file.
  49. # This file is created by generate_build_files.py. Do not edit manually.
  50. """
  51. def PrintVariableSection(self, out, name, files):
  52. out.write(' \'%s\': [\n' % name)
  53. for f in sorted(files):
  54. out.write(' \'%s\',\n' % f)
  55. out.write(' ],\n')
  56. def WriteFiles(self, files, asm_outputs):
  57. with open('boringssl.gypi', 'w+') as gypi:
  58. gypi.write(self.header + '{\n \'variables\': {\n')
  59. self.PrintVariableSection(
  60. gypi, 'boringssl_ssl_sources', files['ssl'])
  61. self.PrintVariableSection(
  62. gypi, 'boringssl_crypto_sources', files['crypto'])
  63. for ((osname, arch), asm_files) in asm_outputs:
  64. self.PrintVariableSection(gypi, 'boringssl_%s_%s_sources' %
  65. (osname, arch), asm_files)
  66. gypi.write(' }\n}\n')
  67. with open('boringssl_tests.gypi', 'w+') as test_gypi:
  68. test_gypi.write(self.header + '{\n \'targets\': [\n')
  69. test_names = []
  70. for test in sorted(files['test']):
  71. test_name = 'boringssl_%s' % os.path.splitext(os.path.basename(test))[0]
  72. test_gypi.write(""" {
  73. 'target_name': '%s',
  74. 'type': 'executable',
  75. 'dependencies': [
  76. 'boringssl.gyp:boringssl',
  77. ],
  78. 'sources': [
  79. '%s',
  80. '<@(boringssl_test_support_sources)',
  81. ],
  82. # TODO(davidben): Fix size_t truncations in BoringSSL.
  83. # https://crbug.com/429039
  84. 'msvs_disabled_warnings': [ 4267, ],
  85. },\n""" % (test_name, test))
  86. test_names.append(test_name)
  87. test_names.sort()
  88. test_gypi.write(' ],\n \'variables\': {\n')
  89. self.PrintVariableSection(
  90. test_gypi, 'boringssl_test_support_sources', files['test_support'])
  91. test_gypi.write(' \'boringssl_test_targets\': [\n')
  92. for test in test_names:
  93. test_gypi.write(""" '%s',\n""" % test)
  94. test_gypi.write(' ],\n }\n}\n')
  95. class Android(object):
  96. def __init__(self):
  97. self.header = \
  98. """# Copyright (C) 2015 The Android Open Source Project
  99. #
  100. # Licensed under the Apache License, Version 2.0 (the "License");
  101. # you may not use this file except in compliance with the License.
  102. # You may obtain a copy of the License at
  103. #
  104. # http://www.apache.org/licenses/LICENSE-2.0
  105. #
  106. # Unless required by applicable law or agreed to in writing, software
  107. # distributed under the License is distributed on an "AS IS" BASIS,
  108. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  109. # See the License for the specific language governing permissions and
  110. # limitations under the License.
  111. """
  112. def ExtraFiles(self):
  113. return ['android_compat_hacks.c', 'android_compat_keywrap.c']
  114. def PrintVariableSection(self, out, name, files):
  115. out.write('%s := \\\n' % name)
  116. for f in sorted(files):
  117. out.write(' %s\\\n' % f)
  118. out.write('\n')
  119. def WriteFiles(self, files, asm_outputs):
  120. with open('sources.mk', 'w+') as makefile:
  121. makefile.write(self.header)
  122. files['crypto'].extend(self.ExtraFiles())
  123. self.PrintVariableSection(makefile, 'crypto_sources', files['crypto'])
  124. self.PrintVariableSection(makefile, 'ssl_sources', files['ssl'])
  125. self.PrintVariableSection(makefile, 'tool_sources', files['tool'])
  126. for ((osname, arch), asm_files) in asm_outputs:
  127. self.PrintVariableSection(
  128. makefile, '%s_%s_sources' % (osname, arch), asm_files)
  129. class AndroidStandalone(Android):
  130. """AndroidStandalone is for Android builds outside of the Android-system, i.e.
  131. for applications that wish wish to ship BoringSSL.
  132. """
  133. def ExtraFiles(self):
  134. return []
  135. class Bazel(object):
  136. """Bazel outputs files suitable for including in Bazel files."""
  137. def __init__(self):
  138. self.firstSection = True
  139. self.header = \
  140. """# This file is created by generate_build_files.py. Do not edit manually.
  141. """
  142. def PrintVariableSection(self, out, name, files):
  143. if not self.firstSection:
  144. out.write('\n')
  145. self.firstSection = False
  146. out.write('%s = [\n' % name)
  147. for f in sorted(files):
  148. out.write(' "%s",\n' % f)
  149. out.write(']\n')
  150. def WriteFiles(self, files, asm_outputs):
  151. with open('BUILD.generated.bzl', 'w+') as out:
  152. out.write(self.header)
  153. self.PrintVariableSection(out, 'ssl_headers', files['ssl_headers'])
  154. self.PrintVariableSection(
  155. out, 'ssl_internal_headers', files['ssl_internal_headers'])
  156. self.PrintVariableSection(out, 'ssl_sources', files['ssl'])
  157. self.PrintVariableSection(out, 'crypto_headers', files['crypto_headers'])
  158. self.PrintVariableSection(
  159. out, 'crypto_internal_headers', files['crypto_internal_headers'])
  160. self.PrintVariableSection(out, 'crypto_sources', files['crypto'])
  161. self.PrintVariableSection(out, 'tool_sources', files['tool'])
  162. for ((osname, arch), asm_files) in asm_outputs:
  163. self.PrintVariableSection(
  164. out, 'crypto_sources_%s_%s' % (osname, arch), asm_files)
  165. with open('BUILD.generated_tests.bzl', 'w+') as out:
  166. out.write(self.header)
  167. out.write('test_support_sources = [\n')
  168. for filename in files['test_support']:
  169. if os.path.basename(filename) == 'malloc.cc':
  170. continue
  171. out.write(' "%s",\n' % filename)
  172. out.write(']\n\n')
  173. out.write('def create_tests(copts):\n')
  174. out.write(' test_support_sources_complete = test_support_sources + \\\n')
  175. out.write(' native.glob(["src/crypto/test/*.h"])\n')
  176. name_counts = {}
  177. for test in files['tests']:
  178. name = os.path.basename(test[0])
  179. name_counts[name] = name_counts.get(name, 0) + 1
  180. first = True
  181. for test in files['tests']:
  182. name = os.path.basename(test[0])
  183. if name_counts[name] > 1:
  184. if '/' in test[1]:
  185. name += '_' + os.path.splitext(os.path.basename(test[1]))[0]
  186. else:
  187. name += '_' + test[1].replace('-', '_')
  188. if not first:
  189. out.write('\n')
  190. first = False
  191. src_prefix = 'src/' + test[0]
  192. for src in files['test']:
  193. if src.startswith(src_prefix):
  194. src = src
  195. break
  196. else:
  197. raise ValueError("Can't find source for %s" % test[0])
  198. out.write(' native.cc_test(\n')
  199. out.write(' name = "%s",\n' % name)
  200. out.write(' size = "small",\n')
  201. out.write(' srcs = ["%s"] + test_support_sources_complete,\n' % src)
  202. data_files = []
  203. if len(test) > 1:
  204. out.write(' args = [\n')
  205. for arg in test[1:]:
  206. if '/' in arg:
  207. out.write(' "$(location src/%s)",\n' % arg)
  208. data_files.append('src/%s' % arg)
  209. else:
  210. out.write(' "%s",\n' % arg)
  211. out.write(' ],\n')
  212. out.write(' copts = copts,\n')
  213. if len(data_files) > 0:
  214. out.write(' data = [\n')
  215. for filename in data_files:
  216. out.write(' "%s",\n' % filename)
  217. out.write(' ],\n')
  218. if 'ssl/' in test[0]:
  219. out.write(' deps = [\n')
  220. out.write(' ":crypto",\n')
  221. out.write(' ":ssl",\n')
  222. out.write(' ],\n')
  223. else:
  224. out.write(' deps = [":crypto"],\n')
  225. out.write(' )\n')
  226. def FindCMakeFiles(directory):
  227. """Returns list of all CMakeLists.txt files recursively in directory."""
  228. cmakefiles = []
  229. for (path, _, filenames) in os.walk(directory):
  230. for filename in filenames:
  231. if filename == 'CMakeLists.txt':
  232. cmakefiles.append(os.path.join(path, filename))
  233. return cmakefiles
  234. def NoTests(dent, is_dir):
  235. """Filter function that can be passed to FindCFiles in order to remove test
  236. sources."""
  237. if is_dir:
  238. return dent != 'test'
  239. return 'test.' not in dent and not dent.startswith('example_')
  240. def OnlyTests(dent, is_dir):
  241. """Filter function that can be passed to FindCFiles in order to remove
  242. non-test sources."""
  243. if is_dir:
  244. return dent != 'test'
  245. return '_test.' in dent or dent.startswith('example_')
  246. def AllFiles(dent, is_dir):
  247. """Filter function that can be passed to FindCFiles in order to include all
  248. sources."""
  249. return True
  250. def SSLHeaderFiles(dent, is_dir):
  251. return dent in ['ssl.h', 'tls1.h', 'ssl23.h', 'ssl3.h', 'dtls1.h']
  252. def FindCFiles(directory, filter_func):
  253. """Recurses through directory and returns a list of paths to all the C source
  254. files that pass filter_func."""
  255. cfiles = []
  256. for (path, dirnames, filenames) in os.walk(directory):
  257. for filename in filenames:
  258. if not filename.endswith('.c') and not filename.endswith('.cc'):
  259. continue
  260. if not filter_func(filename, False):
  261. continue
  262. cfiles.append(os.path.join(path, filename))
  263. for (i, dirname) in enumerate(dirnames):
  264. if not filter_func(dirname, True):
  265. del dirnames[i]
  266. return cfiles
  267. def FindHeaderFiles(directory, filter_func):
  268. """Recurses through directory and returns a list of paths to all the header files that pass filter_func."""
  269. hfiles = []
  270. for (path, dirnames, filenames) in os.walk(directory):
  271. for filename in filenames:
  272. if not filename.endswith('.h'):
  273. continue
  274. if not filter_func(filename, False):
  275. continue
  276. hfiles.append(os.path.join(path, filename))
  277. return hfiles
  278. def ExtractPerlAsmFromCMakeFile(cmakefile):
  279. """Parses the contents of the CMakeLists.txt file passed as an argument and
  280. returns a list of all the perlasm() directives found in the file."""
  281. perlasms = []
  282. with open(cmakefile) as f:
  283. for line in f:
  284. line = line.strip()
  285. if not line.startswith('perlasm('):
  286. continue
  287. if not line.endswith(')'):
  288. raise ValueError('Bad perlasm line in %s' % cmakefile)
  289. # Remove "perlasm(" from start and ")" from end
  290. params = line[8:-1].split()
  291. if len(params) < 2:
  292. raise ValueError('Bad perlasm line in %s' % cmakefile)
  293. perlasms.append({
  294. 'extra_args': params[2:],
  295. 'input': os.path.join(os.path.dirname(cmakefile), params[1]),
  296. 'output': os.path.join(os.path.dirname(cmakefile), params[0]),
  297. })
  298. return perlasms
  299. def ReadPerlAsmOperations():
  300. """Returns a list of all perlasm() directives found in CMake config files in
  301. src/."""
  302. perlasms = []
  303. cmakefiles = FindCMakeFiles('src')
  304. for cmakefile in cmakefiles:
  305. perlasms.extend(ExtractPerlAsmFromCMakeFile(cmakefile))
  306. return perlasms
  307. def PerlAsm(output_filename, input_filename, perlasm_style, extra_args):
  308. """Runs the a perlasm script and puts the output into output_filename."""
  309. base_dir = os.path.dirname(output_filename)
  310. if not os.path.isdir(base_dir):
  311. os.makedirs(base_dir)
  312. output = subprocess.check_output(
  313. ['perl', input_filename, perlasm_style] + extra_args)
  314. with open(output_filename, 'w+') as out_file:
  315. out_file.write(output)
  316. def ArchForAsmFilename(filename):
  317. """Returns the architectures that a given asm file should be compiled for
  318. based on substrings in the filename."""
  319. if 'x86_64' in filename or 'avx2' in filename:
  320. return ['x86_64']
  321. elif ('x86' in filename and 'x86_64' not in filename) or '586' in filename:
  322. return ['x86']
  323. elif 'armx' in filename:
  324. return ['arm', 'aarch64']
  325. elif 'armv8' in filename:
  326. return ['aarch64']
  327. elif 'arm' in filename:
  328. return ['arm']
  329. else:
  330. raise ValueError('Unknown arch for asm filename: ' + filename)
  331. def WriteAsmFiles(perlasms):
  332. """Generates asm files from perlasm directives for each supported OS x
  333. platform combination."""
  334. asmfiles = {}
  335. for osarch in OS_ARCH_COMBOS:
  336. (osname, arch, perlasm_style, extra_args, asm_ext) = osarch
  337. key = (osname, arch)
  338. outDir = '%s-%s' % key
  339. for perlasm in perlasms:
  340. filename = os.path.basename(perlasm['input'])
  341. output = perlasm['output']
  342. if not output.startswith('src'):
  343. raise ValueError('output missing src: %s' % output)
  344. output = os.path.join(outDir, output[4:])
  345. if output.endswith('-armx.${ASM_EXT}'):
  346. output = output.replace('-armx',
  347. '-armx64' if arch == 'aarch64' else '-armx32')
  348. output = output.replace('${ASM_EXT}', asm_ext)
  349. if arch in ArchForAsmFilename(filename):
  350. PerlAsm(output, perlasm['input'], perlasm_style,
  351. perlasm['extra_args'] + extra_args)
  352. asmfiles.setdefault(key, []).append(output)
  353. for (key, non_perl_asm_files) in NON_PERL_FILES.iteritems():
  354. asmfiles.setdefault(key, []).extend(non_perl_asm_files)
  355. return asmfiles
  356. def main(platforms):
  357. crypto_c_files = FindCFiles(os.path.join('src', 'crypto'), NoTests)
  358. ssl_c_files = FindCFiles(os.path.join('src', 'ssl'), NoTests)
  359. tool_cc_files = FindCFiles(os.path.join('src', 'tool'), NoTests)
  360. # Generate err_data.c
  361. with open('err_data.c', 'w+') as err_data:
  362. subprocess.check_call(['go', 'run', 'err_data_generate.go'],
  363. cwd=os.path.join('src', 'crypto', 'err'),
  364. stdout=err_data)
  365. crypto_c_files.append('err_data.c')
  366. test_support_cc_files = FindCFiles(os.path.join('src', 'crypto', 'test'),
  367. AllFiles)
  368. test_c_files = FindCFiles(os.path.join('src', 'crypto'), OnlyTests)
  369. test_c_files += FindCFiles(os.path.join('src', 'ssl'), OnlyTests)
  370. ssl_h_files = (
  371. FindHeaderFiles(
  372. os.path.join('src', 'include', 'openssl'),
  373. SSLHeaderFiles))
  374. def NotSSLHeaderFiles(filename, is_dir):
  375. return not SSLHeaderFiles(filename, is_dir)
  376. crypto_h_files = (
  377. FindHeaderFiles(
  378. os.path.join('src', 'include', 'openssl'),
  379. NotSSLHeaderFiles))
  380. ssl_internal_h_files = FindHeaderFiles(os.path.join('src', 'ssl'), NoTests)
  381. crypto_internal_h_files = FindHeaderFiles(
  382. os.path.join('src', 'crypto'), NoTests)
  383. with open('src/util/all_tests.json', 'r') as f:
  384. tests = json.load(f)
  385. test_binaries = set([test[0] for test in tests])
  386. test_sources = set([
  387. test.replace('.cc', '').replace('.c', '').replace(
  388. 'src/',
  389. '')
  390. for test in test_c_files])
  391. if test_binaries != test_sources:
  392. print 'Test sources and configured tests do not match'
  393. a = test_binaries.difference(test_sources)
  394. if len(a) > 0:
  395. print 'These tests are configured without sources: ' + str(a)
  396. b = test_sources.difference(test_binaries)
  397. if len(b) > 0:
  398. print 'These test sources are not configured: ' + str(b)
  399. files = {
  400. 'crypto': crypto_c_files,
  401. 'crypto_headers': crypto_h_files,
  402. 'crypto_internal_headers': crypto_internal_h_files,
  403. 'ssl': ssl_c_files,
  404. 'ssl_headers': ssl_h_files,
  405. 'ssl_internal_headers': ssl_internal_h_files,
  406. 'tool': tool_cc_files,
  407. 'test': test_c_files,
  408. 'test_support': test_support_cc_files,
  409. 'tests': tests,
  410. }
  411. asm_outputs = sorted(WriteAsmFiles(ReadPerlAsmOperations()).iteritems())
  412. for platform in platforms:
  413. platform.WriteFiles(files, asm_outputs)
  414. return 0
  415. def Usage():
  416. print 'Usage: python %s [chromium|android|android-standalone|bazel]' % sys.argv[0]
  417. sys.exit(1)
  418. if __name__ == '__main__':
  419. if len(sys.argv) < 2:
  420. Usage()
  421. platforms = []
  422. for s in sys.argv[1:]:
  423. if s == 'chromium' or s == 'gyp':
  424. platforms.append(Chromium())
  425. elif s == 'android':
  426. platforms.append(Android())
  427. elif s == 'android-standalone':
  428. platforms.append(AndroidStandalone())
  429. elif s == 'bazel':
  430. platforms.append(Bazel())
  431. else:
  432. Usage()
  433. sys.exit(main(platforms))