1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can b
3 # found in the LICENSE file.
5 """Enumerates the BoringSSL source in src/ and generates two gypi files:
6 boringssl.gypi and boringssl_tests.gypi."""
13 # OS_ARCH_COMBOS maps from OS and platform to the OpenSSL assembly "style" for
14 # that platform and the extension used by asm files.
16 ('linux', 'arm', 'elf', [''], 'S'),
17 ('linux', 'x86', 'elf', ['-fPIC'], 'S'),
18 ('linux', 'x86_64', 'elf', [''], 'S'),
19 ('mac', 'x86', 'macosx', ['-fPIC'], 'S'),
20 ('mac', 'x86_64', 'macosx', [''], 'S'),
21 ('win', 'x86_64', 'masm', [''], 'asm'),
24 # NON_PERL_FILES enumerates assembly files that are not processed by the
28 'src/crypto/poly1305/poly1305_arm_asm.S',
29 'src/crypto/chacha/chacha_vec_arm.S',
33 FILE_HEADER
= """# Copyright (c) 2014 The Chromium Authors. All rights reserved.
34 # Use of this source code is governed by a BSD-style license that can be
35 # found in the LICENSE file.
37 # This file is created by update_gypi_and_asm.py. Do not edit manually.
42 def FindCMakeFiles(directory
):
43 """Returns list of all CMakeLists.txt files recursively in directory."""
46 for (path
, _
, filenames
) in os
.walk(directory
):
47 for filename
in filenames
:
48 if filename
== 'CMakeLists.txt':
49 cmakefiles
.append(os
.path
.join(path
, filename
))
54 def NoTests(dent
, is_dir
):
55 """Filter function that can be passed to FindCFiles in order to remove test
59 return 'test.' not in dent
and not dent
.startswith('example_')
62 def OnlyTests(dent
, is_dir
):
63 """Filter function that can be passed to FindCFiles in order to remove
67 return '_test.' in dent
or dent
.startswith('example_')
70 def FindCFiles(directory
, filter_func
):
71 """Recurses through directory and returns a list of paths to all the C source
72 files that pass filter_func."""
75 for (path
, dirnames
, filenames
) in os
.walk(directory
):
76 for filename
in filenames
:
77 if filename
.endswith('.c') and filter_func(filename
, False):
78 cfiles
.append(os
.path
.join(path
, filename
))
81 for (i
, dirname
) in enumerate(dirnames
):
82 if not filter_func(dirname
, True):
88 def ExtractPerlAsmFromCMakeFile(cmakefile
):
89 """Parses the contents of the CMakeLists.txt file passed as an argument and
90 returns a list of all the perlasm() directives found in the file."""
92 with
open(cmakefile
) as f
:
95 if not line
.startswith('perlasm('):
97 if not line
.endswith(')'):
98 raise ValueError('Bad perlasm line in %s' % cmakefile
)
99 # Remove "perlasm(" from start and ")" from end
100 params
= line
[8:-1].split()
102 raise ValueError('Bad perlasm line in %s' % cmakefile
)
104 'extra_args': params
[2:],
105 'input': os
.path
.join(os
.path
.dirname(cmakefile
), params
[1]),
106 'output': os
.path
.join(os
.path
.dirname(cmakefile
), params
[0]),
112 def ReadPerlAsmOperations():
113 """Returns a list of all perlasm() directives found in CMake config files in
116 cmakefiles
= FindCMakeFiles('src')
118 for cmakefile
in cmakefiles
:
119 perlasms
.extend(ExtractPerlAsmFromCMakeFile(cmakefile
))
124 def PerlAsm(output_filename
, input_filename
, perlasm_style
, extra_args
):
125 """Runs the a perlasm script and puts the output into output_filename."""
126 base_dir
= os
.path
.dirname(output_filename
)
127 if not os
.path
.isdir(base_dir
):
128 os
.makedirs(base_dir
)
129 output
= subprocess
.check_output(
130 ['perl', input_filename
, perlasm_style
] + extra_args
)
131 with
open(output_filename
, 'w+') as out_file
:
132 out_file
.write(output
)
135 def ArchForAsmFilename(filename
):
136 """Returns the architecture that a given asm file should be compiled for
137 based on substrings in the filename."""
139 if 'x86_64' in filename
or 'avx2' in filename
:
141 elif ('x86' in filename
and 'x86_64' not in filename
) or '586' in filename
:
143 elif 'arm' in filename
:
146 raise ValueError('Unknown arch for asm filename: ' + filename
)
149 def WriteAsmFiles(perlasms
):
150 """Generates asm files from perlasm directives for each supported OS x
151 platform combination."""
154 for osarch
in OS_ARCH_COMBOS
:
155 (osname
, arch
, perlasm_style
, extra_args
, asm_ext
) = osarch
157 outDir
= '%s-%s' % key
159 for perlasm
in perlasms
:
160 filename
= os
.path
.basename(perlasm
['input'])
161 output
= perlasm
['output']
162 if not output
.startswith('src'):
163 raise ValueError('output missing src: %s' % output
)
164 output
= os
.path
.join(outDir
, output
[4:])
165 output
= output
.replace('${ASM_EXT}', asm_ext
)
167 if arch
== ArchForAsmFilename(filename
):
168 PerlAsm(output
, perlasm
['input'], perlasm_style
,
169 perlasm
['extra_args'] + extra_args
)
170 asmfiles
.setdefault(key
, []).append(output
)
172 for (key
, non_perl_asm_files
) in NON_PERL_FILES
.iteritems():
173 asmfiles
.setdefault(key
, []).extend(non_perl_asm_files
)
178 def PrintVariableSection(out
, name
, files
):
179 out
.write(' \'%s\': [\n' % name
)
180 for f
in sorted(files
):
181 out
.write(' \'%s\',\n' % f
)
186 crypto_c_files
= FindCFiles(os
.path
.join('src', 'crypto'), NoTests
)
187 ssl_c_files
= FindCFiles(os
.path
.join('src', 'ssl'), NoTests
)
189 with
open('boringssl.gypi', 'w+') as gypi
:
190 gypi
.write(FILE_HEADER
+ '{\n \'variables\': {\n')
192 PrintVariableSection(
193 gypi
, 'boringssl_lib_sources', crypto_c_files
+ ssl_c_files
)
195 perlasms
= ReadPerlAsmOperations()
197 for ((osname
, arch
), asm_files
) in sorted(
198 WriteAsmFiles(perlasms
).iteritems()):
199 PrintVariableSection(gypi
, 'boringssl_%s_%s_sources' %
200 (osname
, arch
), asm_files
)
202 gypi
.write(' }\n}\n')
204 test_c_files
= FindCFiles(os
.path
.join('src', 'crypto'), OnlyTests
)
205 test_c_files
+= FindCFiles(os
.path
.join('src', 'ssl'), OnlyTests
)
207 with
open('boringssl_tests.gypi', 'w+') as test_gypi
:
208 test_gypi
.write(FILE_HEADER
+ '{\n \'targets\': [\n')
211 for test
in sorted(test_c_files
):
212 test_name
= 'boringssl_%s' % os
.path
.splitext(os
.path
.basename(test
))[0]
213 test_gypi
.write(""" {
215 'type': 'executable',
217 'boringssl.gyp:boringssl',
222 },\n""" % (test_name
, test
))
223 test_names
.append(test_name
)
227 test_gypi
.write(""" ],
229 'boringssl_test_targets': [\n""")
231 for test
in test_names
:
232 test_gypi
.write(""" '%s',\n""" % test
)
234 test_gypi
.write(' ],\n }\n}\n')
239 if __name__
== '__main__':