| LEFT | RIGHT |
| (no file at all) | |
| 1 #!/usr/bin/env python | |
| 2 | |
| 3 # This file is part of Adblock Plus <https://adblockplus.org/>, | |
| 4 # Copyright (C) 2006-present eyeo GmbH | |
| 5 # | |
| 6 # Adblock Plus is free software: you can redistribute it and/or modify | |
| 7 # it under the terms of the GNU General Public License version 3 as | |
| 8 # published by the Free Software Foundation. | |
| 9 # | |
| 10 # Adblock Plus is distributed in the hope that it will be useful, | |
| 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 # GNU General Public License for more details. | |
| 14 # | |
| 15 # You should have received a copy of the GNU General Public License | |
| 16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | |
| 17 | |
| 18 import argparse | |
| 19 import os | |
| 20 import subprocess | |
| 21 import sys | |
| 22 | |
| 23 BASE_DIR = os.path.dirname(__file__) | |
| 24 SOURCE_DIR = os.path.join(BASE_DIR, 'compiled') | |
| 25 JS_LIBRARY = os.path.join(SOURCE_DIR, 'library.js') | |
| 26 BINDINGS_GENERATOR = os.path.join(SOURCE_DIR, 'bindings.cpp.js') | |
| 27 BINDINGS_OUTPUT = os.path.join(SOURCE_DIR, 'bindings.js') | |
| 28 COMPILER_OUTPUT = os.path.join(BASE_DIR, 'lib', 'compiled.js') | |
| 29 GENERATION_PARAMS = { | |
| 30 'SHELL_FILE': "'{}'".format(os.path.abspath(os.path.join(SOURCE_DIR, | |
| 31 'shell.js'))), | |
| 32 'ASM_JS': 2, # "almost asm" | |
| 33 'TOTAL_MEMORY': 16*1024*1024, | |
| 34 'TOTAL_STACK': 1*1024*1024, | |
| 35 'ALLOW_MEMORY_GROWTH': 1, | |
| 36 'NO_EXIT_RUNTIME': 1, | |
| 37 'NO_DYNAMIC_EXECUTION': 1, | |
| 38 'NO_FILESYSTEM': 1, | |
| 39 'INVOKE_RUN': 0, | |
| 40 'TEXTDECODER': 0, | |
| 41 'EXPORTED_RUNTIME_METHODS': ['cwrap', 'ccall', 'stringToAscii'], | |
| 42 } | |
| 43 DEFINES = [] | |
| 44 ADDITIONAL_PARAMS = ['-O3', '-m32', '-std=c++1z', '--memory-init-file', '0', | |
| 45 '--emit-symbol-map', '-Wall', '-Werror', '-fno-exceptions', | |
| 46 '-fno-rtti', '--js-library', JS_LIBRARY] | |
| 47 | |
| 48 | |
| 49 def get_source_files(phase): | |
| 50 for (path, dirs, files) in os.walk(SOURCE_DIR): | |
| 51 for f in files: | |
| 52 if os.path.splitext(f)[1] != '.cpp': | |
| 53 continue | |
| 54 if ( | |
| 55 phase != 'bindings' and | |
| 56 os.path.basename(path) == 'bindings' and | |
| 57 not f.startswith('runtime_') | |
| 58 ): | |
| 59 continue | |
| 60 yield os.path.join(path, f) | |
| 61 | |
| 62 def getenv(emscripten_config): | |
| 63 scope = {} | |
| 64 execfile(emscripten_config, scope, scope) | |
| 65 env = os.environ.copy() | |
| 66 env.update({ | |
| 67 'EM_CONFIG': emscripten_config, | |
| 68 'EMSCRIPTEN': scope['EMSCRIPTEN_ROOT'], | |
| 69 'PYTHON': scope.get('PYTHON', sys.executable), | |
| 70 'NODE_JS': scope.get('NODE_JS', 'node'), | |
| 71 }) | |
| 72 return env | |
| 73 | |
| 74 | |
| 75 def generate_bindings(env): | |
| 76 params = [ | |
| 77 env['PYTHON'], os.path.join(env['EMSCRIPTEN'], 'emcc'), | |
| 78 '-o', BINDINGS_GENERATOR, '-std=c++1z', '--js-library', JS_LIBRARY, | |
| 79 '--js-library', os.path.join(SOURCE_DIR, 'bindings', 'library.js'), | |
| 80 ] + list(get_source_files('bindings')) | |
| 81 subprocess.check_call(params, env=env) | |
| 82 | |
| 83 with open(BINDINGS_OUTPUT, 'w') as file: | |
| 84 subprocess.check_call([env['NODE_JS'], BINDINGS_GENERATOR], | |
| 85 stdout=file) | |
| 86 | |
| 87 | |
| 88 def run_compiler(env, debug=False, tracing=False): | |
| 89 params = [ | |
| 90 env['PYTHON'], os.path.join(env['EMSCRIPTEN'], 'emcc'), | |
| 91 '-o', COMPILER_OUTPUT, | |
| 92 '--post-js', BINDINGS_OUTPUT, | |
| 93 ] | |
| 94 # Order matters. We sort source files so that we always get the same | |
| 95 # results for the same source code. | |
| 96 params.extend(sorted(get_source_files('compile'))) | |
| 97 params.extend('-D' + flag for flag in DEFINES) | |
| 98 for key, value in GENERATION_PARAMS.iteritems(): | |
| 99 params.extend(['-s', '{}={}'.format(key, str(value))]) | |
| 100 if debug: | |
| 101 params.append('-DDEBUG') | |
| 102 params.append('-g3') | |
| 103 if tracing: | |
| 104 params.append('--tracing') | |
| 105 params.extend(ADDITIONAL_PARAMS) | |
| 106 subprocess.check_call(params, env=env) | |
| 107 | |
| 108 | |
| 109 if __name__ == '__main__': | |
| 110 parser = argparse.ArgumentParser( | |
| 111 description='Compile Emscripten-based C++ code to JavaScript' | |
| 112 ) | |
| 113 parser.add_argument( | |
| 114 '--emscripten-config', | |
| 115 metavar='DIR', | |
| 116 default=os.path.expanduser('~/.emscripten'), | |
| 117 help='Emscripten installation directory' | |
| 118 ) | |
| 119 parser.add_argument( | |
| 120 '-d', '--debug', | |
| 121 action='store_true', | |
| 122 help='Disable code minification' | |
| 123 ) | |
| 124 parser.add_argument( | |
| 125 '-t', '--tracing', | |
| 126 action='store_true', | |
| 127 help='Enable memory tracing' | |
| 128 ) | |
| 129 args = parser.parse_args() | |
| 130 | |
| 131 env = getenv(args.emscripten_config) | |
| 132 generate_bindings(env) | |
| 133 run_compiler(env, debug=args.debug, tracing=args.tracing) | |
| LEFT | RIGHT |