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 |