Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

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