Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2017 The Chromium Authors. All rights reserved. | 2 # Copyright 2017 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 """A script to compile the integration tests with llvm's clang, | 5 """A script to compile the integration tests with llvm's clang, |
| 6 instrument the code with llvm's Asan, and link it to the syzyasan_rtl | 6 instrument the code with llvm's Asan, and link it to the syzyasan_rtl |
| 7 runtime environment. | 7 runtime environment. |
| 8 """ | 8 """ |
| 9 | 9 |
| 10 import optparse | 10 import optparse |
| 11 import os | 11 import os |
| 12 import re | 12 import re |
| 13 import subprocess | 13 import subprocess |
| 14 import sys | 14 import sys |
| 15 | 15 |
| 16 | 16 |
| 17 _SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) | 17 _SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) |
| 18 _SRC_DIR = os.path.abspath(os.path.join(_SCRIPT_DIR, os.pardir, os.pardir)) | 18 _SRC_DIR = os.path.abspath(os.path.join(_SCRIPT_DIR, os.pardir, os.pardir)) |
| 19 _CLANG_CL_PATH = os.path.join(_SRC_DIR, | 19 _CLANG_CL_PATH = os.path.join(_SRC_DIR, |
| 20 'third_party', 'llvm-build', 'Release+Asserts', 'bin', 'clang-cl.exe') | 20 'third_party', 'llvm-build', 'Release+Asserts', 'bin', 'clang-cl.exe') |
| 21 | 21 |
| 22 | 22 |
| 23 def compile_with_asan(clang_path, source_files, src_dir, object_files, | 23 def compile_with_asan(clang_path, source_files, src_dir, object_files, |
| 24 target_name): | 24 target_name, target_arch): |
| 25 """Compiles the files and instruments them with LLVM's ASAN. | 25 """Compiles the files and instruments them with LLVM's ASAN. |
| 26 The linking is done with the method link below. | 26 The linking is done with the method link below. |
| 27 | 27 |
| 28 Only compiles the files and instruments them with LLVM's Asan but does not | 28 Only compiles the files and instruments them with LLVM's Asan but does not |
| 29 link them. The linking is done separately in the method link. | 29 link them. The linking is done separately in the method link. |
| 30 | 30 |
| 31 Args: | 31 Args: |
| 32 clang_path: Path to the clang-cl compiler. | 32 clang_path: Path to the clang-cl compiler. |
| 33 source_files: The source files to be compiled. | 33 source_files: The source files to be compiled. |
| 34 src_dir: The repository where the syzygy src is located. | 34 src_dir: The repository where the syzygy src is located. |
| 35 object_files: The path where each object file should be generated. | 35 object_files: The path where each object file should be generated. |
| 36 target_name: The name of the target being build. | 36 target_name: The name of the target being build. |
| 37 target_arch: The target architecture ia32 for 32 bit and x64 for 64 bit. | |
| 37 """ | 38 """ |
| 38 | 39 |
| 40 # By default set the bittness flag to 32 bit. | |
|
Sébastien Marchand
2017/08/11 20:51:26
nit: bitness. (here and below)
| |
| 41 bittness_flag = '-m32' | |
|
Sébastien Marchand
2017/08/11 20:51:26
Don't default to 32 bits, use if-elif.
| |
| 42 if target_arch == 'x64': | |
| 43 bittness_flag = '-m64' | |
| 44 | |
| 39 compiler_flags = [ | 45 compiler_flags = [ |
| 40 '-c', | 46 '-c', |
| 41 '-m32', | 47 bittness_flag, |
| 42 '-fsanitize=address', | 48 '-fsanitize=address', |
| 43 '-mllvm', | 49 '-mllvm', |
| 44 '-asan-instrumentation-with-call-threshold=0', | 50 '-asan-instrumentation-with-call-threshold=0', |
| 45 '-mllvm', | 51 '-mllvm', |
| 46 '-asan-stack=0', | 52 '-asan-stack=0', |
| 47 '-DUNICODE', | 53 '-DUNICODE', |
| 48 '-D_UNICODE', | 54 '-D_UNICODE', |
| 49 '-DNOMINMAX', | 55 '-DNOMINMAX', |
| 50 '-D_CRT_SECURE_NO_WARNINGS', | 56 '-D_CRT_SECURE_NO_WARNINGS', |
| 51 '/Zi', | 57 '/Zi', |
| 52 '-I', | 58 '-I', |
| 53 src_dir, | 59 src_dir, |
| 54 ] | 60 ] |
| 55 | 61 |
| 56 compile_command_base = [clang_path] | 62 compile_command_base = [clang_path] |
| 57 compile_command_base.extend(compiler_flags) | 63 compile_command_base.extend(compiler_flags) |
| 58 | 64 |
| 59 for source_file, object_file in zip(source_files, object_files): | 65 for source_file, object_file in zip(source_files, object_files): |
| 60 compile_command = list(compile_command_base) | 66 compile_command = list(compile_command_base) |
| 61 compile_command.extend([source_file, '-o', object_file]) | 67 compile_command.extend([source_file, '-o', object_file]) |
| 62 ret = subprocess.call(compile_command) | 68 ret = subprocess.call(compile_command) |
| 63 if ret != 0: | 69 if ret != 0: |
| 64 print 'ERROR: Failed compiling %s using clang-cl.' % target_name | 70 print 'ERROR: Failed compiling %s using clang-cl.' % target_name |
| 65 return ret | 71 return ret |
| 66 return ret | 72 return ret |
| 67 | 73 |
| 68 | 74 |
| 69 def link(clang_path, object_files, build_dir, target_name, def_file): | 75 def link(clang_path, object_files, build_dir, target_name, def_file, |
| 76 target_arch): | |
| 70 """ Links the object files and produces the integration_tests_clang_dll.dll. | 77 """ Links the object files and produces the integration_tests_clang_dll.dll. |
| 71 | 78 |
| 72 Links the object files and produces the dll. The object files have to be | 79 Links the object files and produces the dll. The object files have to be |
| 73 produced by the compile method above. | 80 produced by the compile method above. |
| 74 | 81 |
| 75 Args: | 82 Args: |
| 76 clang_path: Path to the clang-cl compiler in the syzygy project. | 83 clang_path: Path to the clang-cl compiler in the syzygy project. |
| 77 source_files: The source file names which are converted to obj filenames. | 84 source_files: The source file names which are converted to obj filenames. |
| 78 build_dir: The directory where to produce the linked dll. | 85 build_dir: The directory where to produce the linked dll. |
| 79 target_name: The name of the target being build. | 86 target_name: The name of the target being build. |
| 87 target_arch: The target architecture ia32 for 32 bit and x64 for 64 bit. | |
| 80 """ | 88 """ |
| 81 | 89 |
| 90 # By default set the bittness flag to 32 bit. | |
| 91 bittness_flag = '-m32' | |
| 92 if target_arch == 'x64': | |
| 93 bittness_flag = '-m64' | |
| 94 | |
| 82 linker_flags = [ | 95 linker_flags = [ |
| 83 '-o', | 96 '-o', |
| 84 os.path.join(build_dir, target_name + '.dll'), | 97 os.path.join(build_dir, target_name + '.dll'), |
| 85 '/link', | 98 '/link', |
| 86 '/dll', | 99 '/dll', |
| 87 os.path.join(build_dir, 'export_dll.dll.lib'), | 100 os.path.join(build_dir, 'export_dll.dll.lib'), |
| 88 os.path.join(build_dir, 'syzyasan_rtl.dll.lib'), | 101 os.path.join(build_dir, 'syzyasan_rtl.dll.lib'), |
| 89 '-defaultlib:libcmt', | 102 '-defaultlib:libcmt', |
| 90 '/debug', | 103 '/debug', |
| 91 '/def:' + def_file, | 104 '/def:' + def_file, |
| 92 ] | 105 ] |
| 93 | 106 |
| 94 linker_command = [clang_path, '-m32'] | 107 linker_command = [clang_path, bittness_flag] |
| 95 linker_command.extend(object_files) | 108 linker_command.extend(object_files) |
| 96 linker_command.extend(linker_flags) | 109 linker_command.extend(linker_flags) |
| 97 | 110 |
| 98 ret = subprocess.call(linker_command) | 111 ret = subprocess.call(linker_command) |
| 99 | 112 |
| 100 if ret != 0: | 113 if ret != 0: |
| 101 print 'ERROR: Failed to link %s using clang-cl.' % target_name | 114 print 'ERROR: Failed to link %s using clang-cl.' % target_name |
| 102 return ret | 115 return ret |
| 103 | 116 |
| 104 | 117 |
| 105 def main(): | 118 def main(): |
| 106 parser = optparse.OptionParser(usage='%prog [options]') | 119 parser = optparse.OptionParser(usage='%prog [options]') |
| 107 parser.add_option('--output-dir', | 120 parser.add_option('--output-dir', |
| 108 help='Path to the Syzygy Release directory.') | 121 help='Path to the Syzygy Release directory.') |
| 109 parser.add_option('--input-files', help='Files to be compiled and linked.') | 122 parser.add_option('--input-files', help='Files to be compiled and linked.') |
| 110 parser.add_option('--target-name', help='Name of the target to be compiled.') | 123 parser.add_option('--target-name', help='Name of the target to be compiled.') |
| 111 parser.add_option('--def-file', help='Definition file for the dll.') | 124 parser.add_option('--def-file', help='Definition file for the dll.') |
| 125 parser.add_option('--target-arch', help='Target architecture x64 or ia32.') | |
| 112 | 126 |
| 113 options, _ = parser.parse_args() | 127 options, _ = parser.parse_args() |
| 114 | 128 |
| 115 if not options.output_dir: | 129 if not options.output_dir: |
| 116 parser.error('--output-dir is required.') | 130 parser.error('--output-dir is required.') |
| 117 if not options.input_files: | 131 if not options.input_files: |
| 118 parser.error('--input-files is required.') | 132 parser.error('--input-files is required.') |
| 119 if not options.target_name: | 133 if not options.target_name: |
| 120 parser.error('--target-name is required.') | 134 parser.error('--target-name is required.') |
| 121 if not options.def_file: | 135 if not options.def_file: |
| 122 parser.error('--def-file is required.') | 136 parser.error('--def-file is required.') |
| 137 if not options.target_arch: | |
| 138 parser.error('--target-arch is required.') | |
| 123 | 139 |
| 124 def get_object_file_location(source_file, | 140 def get_object_file_location(source_file, |
| 125 output_dir, target_name): | 141 output_dir, target_name): |
| 126 return os.path.join(output_dir, 'obj', | 142 return os.path.join(output_dir, 'obj', |
| 127 os.path.dirname(os.path.relpath(source_file, _SRC_DIR)), | 143 os.path.dirname(os.path.relpath(source_file, _SRC_DIR)), |
| 128 '%s.%s.obj' % (target_name, | 144 '%s.%s.obj' % (target_name, |
| 129 os.path.splitext(os.path.basename(source_file))[0])) | 145 os.path.splitext(os.path.basename(source_file))[0])) |
| 130 | 146 |
| 131 source_files = options.input_files.split() | 147 source_files = options.input_files.split() |
| 132 object_files = [] | 148 object_files = [] |
| 133 | 149 |
| 134 for source_file in source_files: | 150 for source_file in source_files: |
| 135 object_files.append(get_object_file_location(source_file, | 151 object_files.append(get_object_file_location(source_file, |
| 136 options.output_dir, | 152 options.output_dir, |
| 137 options.target_name)) | 153 options.target_name)) |
| 138 | 154 |
| 139 ret = compile_with_asan(_CLANG_CL_PATH, source_files, _SRC_DIR, | 155 ret = compile_with_asan(_CLANG_CL_PATH, source_files, _SRC_DIR, |
| 140 object_files, options.target_name) | 156 object_files, options.target_name, |
| 157 options.target_arch) | |
| 141 | 158 |
| 142 if ret == 0: | 159 if ret == 0: |
| 143 ret = link(_CLANG_CL_PATH, object_files, options.output_dir, | 160 ret = link(_CLANG_CL_PATH, object_files, options.output_dir, |
| 144 options.target_name, options.def_file) | 161 options.target_name, options.def_file, options.target_arch) |
| 145 else: | 162 else: |
| 146 print ('ERROR: Compilation of %s failed, skipping link step.' | 163 print ('ERROR: Compilation of %s failed, skipping link step.' |
| 147 % options.target_name) | 164 % options.target_name) |
| 148 | 165 |
| 149 return ret | 166 return ret |
| 150 | 167 |
| 151 | 168 |
| 152 if __name__ == '__main__': | 169 if __name__ == '__main__': |
| 153 sys.exit(main()) | 170 sys.exit(main()) |
| OLD | NEW |