blob: bee46ca6cc56a65bc8847b73661a7513bc2dd871 [file] [log] [blame]
Adam Langley9e1a6602015-05-05 17:47:53 -07001# 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
15"""Enumerates the BoringSSL source in src/ and either generates two gypi files
16 (boringssl.gypi and boringssl_tests.gypi) for Chromium, or generates
17 source-list files for Android."""
18
19import os
20import subprocess
21import sys
22
23
24# OS_ARCH_COMBOS maps from OS and platform to the OpenSSL assembly "style" for
25# that platform and the extension used by asm files.
26OS_ARCH_COMBOS = [
27 ('linux', 'arm', 'linux32', [], 'S'),
28 ('linux', 'aarch64', 'linux64', [], 'S'),
29 ('linux', 'x86', 'elf', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'),
30 ('linux', 'x86_64', 'elf', [], 'S'),
31 ('mac', 'x86', 'macosx', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'),
32 ('mac', 'x86_64', 'macosx', [], 'S'),
33 ('win', 'x86', 'win32n', ['-DOPENSSL_IA32_SSE2'], 'asm'),
34 ('win', 'x86_64', 'nasm', [], 'asm'),
35]
36
37# NON_PERL_FILES enumerates assembly files that are not processed by the
38# perlasm system.
39NON_PERL_FILES = {
40 ('linux', 'arm'): [
41 'src/crypto/poly1305/poly1305_arm_asm.S',
42 'src/crypto/chacha/chacha_vec_arm.S',
43 'src/crypto/cpu-arm-asm.S',
44 ],
45}
46
47
48class Chromium(object):
49
50 def __init__(self):
51 self.header = \
52"""# Copyright (c) 2014 The Chromium Authors. All rights reserved.
53# Use of this source code is governed by a BSD-style license that can be
54# found in the LICENSE file.
55
56# This file is created by generate_build_files.py. Do not edit manually.
57
58"""
59
60 def PrintVariableSection(self, out, name, files):
61 out.write(' \'%s\': [\n' % name)
62 for f in sorted(files):
63 out.write(' \'%s\',\n' % f)
64 out.write(' ],\n')
65
66 def WriteFiles(self, files, asm_outputs):
67 with open('boringssl.gypi', 'w+') as gypi:
68 gypi.write(self.header + '{\n \'variables\': {\n')
69
70 self.PrintVariableSection(
Adam Langley049ef412015-06-09 18:20:57 -070071 gypi, 'boringssl_ssl_sources', files['ssl'])
72 self.PrintVariableSection(
73 gypi, 'boringssl_crypto_sources', files['crypto'])
Adam Langley9e1a6602015-05-05 17:47:53 -070074
75 for ((osname, arch), asm_files) in asm_outputs:
76 self.PrintVariableSection(gypi, 'boringssl_%s_%s_sources' %
77 (osname, arch), asm_files)
78
79 gypi.write(' }\n}\n')
80
81 with open('boringssl_tests.gypi', 'w+') as test_gypi:
82 test_gypi.write(self.header + '{\n \'targets\': [\n')
83
84 test_names = []
85 for test in sorted(files['test']):
86 test_name = 'boringssl_%s' % os.path.splitext(os.path.basename(test))[0]
87 test_gypi.write(""" {
88 'target_name': '%s',
89 'type': 'executable',
90 'dependencies': [
91 'boringssl.gyp:boringssl',
92 ],
93 'sources': [
94 '%s',
David Benjamin26073832015-05-11 20:52:48 -040095 '<@(boringssl_test_support_sources)',
Adam Langley9e1a6602015-05-05 17:47:53 -070096 ],
97 # TODO(davidben): Fix size_t truncations in BoringSSL.
98 # https://crbug.com/429039
99 'msvs_disabled_warnings': [ 4267, ],
100 },\n""" % (test_name, test))
101 test_names.append(test_name)
102
103 test_names.sort()
104
David Benjamin26073832015-05-11 20:52:48 -0400105 test_gypi.write(' ],\n \'variables\': {\n')
106
107 self.PrintVariableSection(
108 test_gypi, 'boringssl_test_support_sources', files['test_support'])
109
110 test_gypi.write(' \'boringssl_test_targets\': [\n')
Adam Langley9e1a6602015-05-05 17:47:53 -0700111
112 for test in test_names:
113 test_gypi.write(""" '%s',\n""" % test)
114
115 test_gypi.write(' ],\n }\n}\n')
116
117
118class Android(object):
119
120 def __init__(self):
121 self.header = \
122"""# Copyright (C) 2015 The Android Open Source Project
123#
124# Licensed under the Apache License, Version 2.0 (the "License");
125# you may not use this file except in compliance with the License.
126# You may obtain a copy of the License at
127#
128# http://www.apache.org/licenses/LICENSE-2.0
129#
130# Unless required by applicable law or agreed to in writing, software
131# distributed under the License is distributed on an "AS IS" BASIS,
132# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133# See the License for the specific language governing permissions and
134# limitations under the License.
135
136"""
137
Adam Langley049ef412015-06-09 18:20:57 -0700138 def ExtraFiles(self):
139 return ['android_compat_hacks.c', 'android_compat_keywrap.c']
140
Adam Langley9e1a6602015-05-05 17:47:53 -0700141 def PrintVariableSection(self, out, name, files):
142 out.write('%s := \\\n' % name)
143 for f in sorted(files):
144 out.write(' %s\\\n' % f)
145 out.write('\n')
146
147 def WriteFiles(self, files, asm_outputs):
148 with open('sources.mk', 'w+') as makefile:
149 makefile.write(self.header)
150
Adam Langley049ef412015-06-09 18:20:57 -0700151 files['crypto'].extend(self.ExtraFiles())
Adam Langley9e1a6602015-05-05 17:47:53 -0700152 self.PrintVariableSection(makefile, 'crypto_sources', files['crypto'])
153 self.PrintVariableSection(makefile, 'ssl_sources', files['ssl'])
154 self.PrintVariableSection(makefile, 'tool_sources', files['tool'])
155
156 for ((osname, arch), asm_files) in asm_outputs:
157 self.PrintVariableSection(
158 makefile, '%s_%s_sources' % (osname, arch), asm_files)
159
160
Adam Langley049ef412015-06-09 18:20:57 -0700161class AndroidStandalone(Android):
162 """AndroidStandalone is for Android builds outside of the Android-system, i.e.
163
164 for applications that wish wish to ship BoringSSL.
165 """
166
167 def ExtraFiles(self):
168 return []
169
170
171class Bazel(object):
172 """Bazel outputs files suitable for including in Bazel files."""
173
174 def __init__(self):
175 self.firstSection = True
176 self.header = \
177"""# This file is created by generate_build_files.py. Do not edit manually.
178
179"""
180
181 def PrintVariableSection(self, out, name, files):
182 if not self.firstSection:
183 out.write('\n')
184 self.firstSection = False
185
186 out.write('%s = [\n' % name)
187 for f in sorted(files):
188 out.write(' "%s",\n' % f)
189 out.write(']\n')
190
191 def WriteFiles(self, files, asm_outputs):
192 with open('BUILD.generated', 'w+') as out:
193 out.write(self.header)
194
195 self.PrintVariableSection(out, 'ssl_headers', files['ssl_headers'])
196 self.PrintVariableSection(
197 out, 'ssl_internal_headers', files['ssl_internal_headers'])
198 self.PrintVariableSection(out, 'ssl_sources', files['ssl'])
199 self.PrintVariableSection(out, 'crypto_headers', files['crypto_headers'])
200 self.PrintVariableSection(
201 out, 'crypto_internal_headers', files['crypto_internal_headers'])
202 self.PrintVariableSection(out, 'crypto_sources', files['crypto'])
203 self.PrintVariableSection(out, 'tool_sources', files['tool'])
204
205 for ((osname, arch), asm_files) in asm_outputs:
206 if osname is not 'linux':
207 continue
208 self.PrintVariableSection(
209 out, 'crypto_sources_%s' % arch, asm_files)
210
211
Adam Langley9e1a6602015-05-05 17:47:53 -0700212def FindCMakeFiles(directory):
213 """Returns list of all CMakeLists.txt files recursively in directory."""
214 cmakefiles = []
215
216 for (path, _, filenames) in os.walk(directory):
217 for filename in filenames:
218 if filename == 'CMakeLists.txt':
219 cmakefiles.append(os.path.join(path, filename))
220
221 return cmakefiles
222
223
224def NoTests(dent, is_dir):
225 """Filter function that can be passed to FindCFiles in order to remove test
226 sources."""
227 if is_dir:
228 return dent != 'test'
229 return 'test.' not in dent and not dent.startswith('example_')
230
231
232def OnlyTests(dent, is_dir):
233 """Filter function that can be passed to FindCFiles in order to remove
234 non-test sources."""
235 if is_dir:
David Benjamin26073832015-05-11 20:52:48 -0400236 return dent != 'test'
Adam Langley9e1a6602015-05-05 17:47:53 -0700237 return '_test.' in dent or dent.startswith('example_')
238
239
David Benjamin26073832015-05-11 20:52:48 -0400240def AllFiles(dent, is_dir):
241 """Filter function that can be passed to FindCFiles in order to include all
242 sources."""
243 return True
244
245
Adam Langley049ef412015-06-09 18:20:57 -0700246def SSLHeaderFiles(dent, is_dir):
247 return dent in ['ssl.h', 'tls1.h', 'ssl23.h', 'ssl3.h', 'dtls1.h']
248
249
Adam Langley9e1a6602015-05-05 17:47:53 -0700250def 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
255 for (path, dirnames, filenames) in os.walk(directory):
256 for filename in filenames:
257 if not filename.endswith('.c') and not filename.endswith('.cc'):
258 continue
259 if not filter_func(filename, False):
260 continue
261 cfiles.append(os.path.join(path, filename))
262
263 for (i, dirname) in enumerate(dirnames):
264 if not filter_func(dirname, True):
265 del dirnames[i]
266
267 return cfiles
268
269
Adam Langley049ef412015-06-09 18:20:57 -0700270def FindHeaderFiles(directory, filter_func):
271 """Recurses through directory and returns a list of paths to all the header files that pass filter_func."""
272 hfiles = []
273
274 for (path, dirnames, filenames) in os.walk(directory):
275 for filename in filenames:
276 if not filename.endswith('.h'):
277 continue
278 if not filter_func(filename, False):
279 continue
280 hfiles.append(os.path.join(path, filename))
281
282 return hfiles
283
284
Adam Langley9e1a6602015-05-05 17:47:53 -0700285def ExtractPerlAsmFromCMakeFile(cmakefile):
286 """Parses the contents of the CMakeLists.txt file passed as an argument and
287 returns a list of all the perlasm() directives found in the file."""
288 perlasms = []
289 with open(cmakefile) as f:
290 for line in f:
291 line = line.strip()
292 if not line.startswith('perlasm('):
293 continue
294 if not line.endswith(')'):
295 raise ValueError('Bad perlasm line in %s' % cmakefile)
296 # Remove "perlasm(" from start and ")" from end
297 params = line[8:-1].split()
298 if len(params) < 2:
299 raise ValueError('Bad perlasm line in %s' % cmakefile)
300 perlasms.append({
301 'extra_args': params[2:],
302 'input': os.path.join(os.path.dirname(cmakefile), params[1]),
303 'output': os.path.join(os.path.dirname(cmakefile), params[0]),
304 })
305
306 return perlasms
307
308
309def ReadPerlAsmOperations():
310 """Returns a list of all perlasm() directives found in CMake config files in
311 src/."""
312 perlasms = []
313 cmakefiles = FindCMakeFiles('src')
314
315 for cmakefile in cmakefiles:
316 perlasms.extend(ExtractPerlAsmFromCMakeFile(cmakefile))
317
318 return perlasms
319
320
321def PerlAsm(output_filename, input_filename, perlasm_style, extra_args):
322 """Runs the a perlasm script and puts the output into output_filename."""
323 base_dir = os.path.dirname(output_filename)
324 if not os.path.isdir(base_dir):
325 os.makedirs(base_dir)
326 output = subprocess.check_output(
327 ['perl', input_filename, perlasm_style] + extra_args)
328 with open(output_filename, 'w+') as out_file:
329 out_file.write(output)
330
331
332def ArchForAsmFilename(filename):
333 """Returns the architectures that a given asm file should be compiled for
334 based on substrings in the filename."""
335
336 if 'x86_64' in filename or 'avx2' in filename:
337 return ['x86_64']
338 elif ('x86' in filename and 'x86_64' not in filename) or '586' in filename:
339 return ['x86']
340 elif 'armx' in filename:
341 return ['arm', 'aarch64']
342 elif 'armv8' in filename:
343 return ['aarch64']
344 elif 'arm' in filename:
345 return ['arm']
346 else:
347 raise ValueError('Unknown arch for asm filename: ' + filename)
348
349
350def WriteAsmFiles(perlasms):
351 """Generates asm files from perlasm directives for each supported OS x
352 platform combination."""
353 asmfiles = {}
354
355 for osarch in OS_ARCH_COMBOS:
356 (osname, arch, perlasm_style, extra_args, asm_ext) = osarch
357 key = (osname, arch)
358 outDir = '%s-%s' % key
359
360 for perlasm in perlasms:
361 filename = os.path.basename(perlasm['input'])
362 output = perlasm['output']
363 if not output.startswith('src'):
364 raise ValueError('output missing src: %s' % output)
365 output = os.path.join(outDir, output[4:])
366 output = output.replace('${ASM_EXT}', asm_ext)
367
368 if arch in ArchForAsmFilename(filename):
369 PerlAsm(output, perlasm['input'], perlasm_style,
370 perlasm['extra_args'] + extra_args)
371 asmfiles.setdefault(key, []).append(output)
372
373 for (key, non_perl_asm_files) in NON_PERL_FILES.iteritems():
374 asmfiles.setdefault(key, []).extend(non_perl_asm_files)
375
376 return asmfiles
377
378
Adam Langley049ef412015-06-09 18:20:57 -0700379def main(platforms):
Adam Langley9e1a6602015-05-05 17:47:53 -0700380 crypto_c_files = FindCFiles(os.path.join('src', 'crypto'), NoTests)
381 ssl_c_files = FindCFiles(os.path.join('src', 'ssl'), NoTests)
382 tool_cc_files = FindCFiles(os.path.join('src', 'tool'), NoTests)
383
384 # Generate err_data.c
385 with open('err_data.c', 'w+') as err_data:
386 subprocess.check_call(['go', 'run', 'err_data_generate.go'],
387 cwd=os.path.join('src', 'crypto', 'err'),
388 stdout=err_data)
389 crypto_c_files.append('err_data.c')
390
David Benjamin26073832015-05-11 20:52:48 -0400391 test_support_cc_files = FindCFiles(os.path.join('src', 'crypto', 'test'),
392 AllFiles)
393
Adam Langley9e1a6602015-05-05 17:47:53 -0700394 test_c_files = FindCFiles(os.path.join('src', 'crypto'), OnlyTests)
395 test_c_files += FindCFiles(os.path.join('src', 'ssl'), OnlyTests)
396
Adam Langley049ef412015-06-09 18:20:57 -0700397 ssl_h_files = (
398 FindHeaderFiles(
399 os.path.join('src', 'include', 'openssl'),
400 SSLHeaderFiles))
401
402 def NotSSLHeaderFiles(filename, is_dir):
403 return not SSLHeaderFiles(filename, is_dir)
404 crypto_h_files = (
405 FindHeaderFiles(
406 os.path.join('src', 'include', 'openssl'),
407 NotSSLHeaderFiles))
408
409 ssl_internal_h_files = FindHeaderFiles(os.path.join('src', 'ssl'), NoTests)
410 crypto_internal_h_files = FindHeaderFiles(
411 os.path.join('src', 'crypto'), NoTests)
412
Adam Langley9e1a6602015-05-05 17:47:53 -0700413 files = {
414 'crypto': crypto_c_files,
Adam Langley049ef412015-06-09 18:20:57 -0700415 'crypto_headers': crypto_h_files,
416 'crypto_internal_headers': crypto_internal_h_files,
Adam Langley9e1a6602015-05-05 17:47:53 -0700417 'ssl': ssl_c_files,
Adam Langley049ef412015-06-09 18:20:57 -0700418 'ssl_headers': ssl_h_files,
419 'ssl_internal_headers': ssl_internal_h_files,
Adam Langley9e1a6602015-05-05 17:47:53 -0700420 'tool': tool_cc_files,
421 'test': test_c_files,
David Benjamin26073832015-05-11 20:52:48 -0400422 'test_support': test_support_cc_files,
Adam Langley9e1a6602015-05-05 17:47:53 -0700423 }
424
425 asm_outputs = sorted(WriteAsmFiles(ReadPerlAsmOperations()).iteritems())
426
Adam Langley049ef412015-06-09 18:20:57 -0700427 for platform in platforms:
428 platform.WriteFiles(files, asm_outputs)
Adam Langley9e1a6602015-05-05 17:47:53 -0700429
430 return 0
431
432
433def Usage():
Adam Langley049ef412015-06-09 18:20:57 -0700434 print 'Usage: python %s [chromium|android|android-standalone|bazel]' % sys.argv[0]
Adam Langley9e1a6602015-05-05 17:47:53 -0700435 sys.exit(1)
436
437
438if __name__ == '__main__':
Adam Langley049ef412015-06-09 18:20:57 -0700439 if len(sys.argv) < 2:
Adam Langley9e1a6602015-05-05 17:47:53 -0700440 Usage()
441
Adam Langley049ef412015-06-09 18:20:57 -0700442 platforms = []
443 for s in sys.argv[1:]:
444 if s == 'chromium' or s == 'gyp':
445 platforms.append(Chromium())
446 elif s == 'android':
447 platforms.append(Android())
448 elif s == 'android-standalone':
449 platforms.append(AndroidStandalone())
450 elif s == 'bazel':
451 platforms.append(Bazel())
452 else:
453 Usage()
Adam Langley9e1a6602015-05-05 17:47:53 -0700454
Adam Langley049ef412015-06-09 18:20:57 -0700455 sys.exit(main(platforms))