• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2
3# Copyright JS Foundation and other contributors, http://js.foundation
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17from __future__ import print_function
18
19import argparse
20import multiprocessing
21import os
22import shutil
23import subprocess
24import sys
25import settings
26
27def default_toolchain():
28    # We don't have default toolchain on Windows and os.uname() isn't supported.
29    if sys.platform == 'win32':
30        return None
31
32    (sysname, _, _, _, machine) = os.uname()
33    toolchain = os.path.join(settings.PROJECT_DIR,
34                             'cmake',
35                             'toolchain_%s_%s.cmake' % (sysname.lower(), machine.lower()))
36    return toolchain if os.path.isfile(toolchain) else None
37
38def get_arguments():
39    devhelp_preparser = argparse.ArgumentParser(add_help=False)
40    devhelp_preparser.add_argument('--devhelp', action='store_true', default=False,
41                                   help='show help with all options '
42                                        '(including those, which are useful for developers only)')
43
44    devhelp_arguments, args = devhelp_preparser.parse_known_args()
45    if devhelp_arguments.devhelp:
46        args.append('--devhelp')
47
48    def devhelp(helpstring):
49        return helpstring if devhelp_arguments.devhelp else argparse.SUPPRESS
50
51    parser = argparse.ArgumentParser(parents=[devhelp_preparser], epilog="""
52        This tool is a thin wrapper around cmake and make to help build the
53        project easily. All the real build logic is in the CMakeLists.txt files.
54        For most of the options, the defaults are also defined there.
55        """)
56
57    buildgrp = parser.add_argument_group('general build options')
58    buildgrp.add_argument('--builddir', metavar='DIR', default=os.path.join(settings.PROJECT_DIR, 'build'),
59                          help='specify build directory (default: %(default)s)')
60    buildgrp.add_argument('--clean', action='store_true', default=False,
61                          help='clean build')
62    buildgrp.add_argument('--cmake-param', metavar='OPT', action='append', default=[],
63                          help='add custom argument to CMake')
64    buildgrp.add_argument('--compile-flag', metavar='OPT', action='append', default=[],
65                          help='add custom compile flag')
66    buildgrp.add_argument('--debug', action='store_const', const='Debug', dest='build_type',
67                          default='MinSizeRel', help='debug build')
68    buildgrp.add_argument('--install', metavar='DIR', nargs='?', default=None, const=False,
69                          help='install after build (default: don\'t install; '
70                               'default directory if install: OS-specific)')
71    buildgrp.add_argument('-j', '--jobs', metavar='N', type=int, default=multiprocessing.cpu_count() + 1,
72                          help='number of parallel build jobs (default: %(default)s)')
73    buildgrp.add_argument('--link-lib', metavar='OPT', action='append', default=[],
74                          help='add custom library to be linked')
75    buildgrp.add_argument('--linker-flag', metavar='OPT', action='append', default=[],
76                          help='add custom linker flag')
77    buildgrp.add_argument('--lto', metavar='X', choices=['ON', 'OFF'], type=str.upper,
78                          help='enable link-time optimizations (%(choices)s)')
79    buildgrp.add_argument('--shared-libs', metavar='X', choices=['ON', 'OFF'], type=str.upper,
80                          help='enable building of shared libraries (%(choices)s)')
81    buildgrp.add_argument('--strip', metavar='X', choices=['ON', 'OFF'], type=str.upper,
82                          help='strip release binaries (%(choices)s)')
83    buildgrp.add_argument('--toolchain', metavar='FILE', default=default_toolchain(),
84                          help='specify toolchain file (default: %(default)s)')
85    buildgrp.add_argument('-v', '--verbose', action='store_const', const='ON',
86                          help='increase verbosity')
87
88    compgrp = parser.add_argument_group('optional components')
89    compgrp.add_argument('--doctests', metavar='X', choices=['ON', 'OFF'], type=str.upper,
90                         help=devhelp('build doctests (%(choices)s)'))
91    compgrp.add_argument('--jerry-cmdline', metavar='X', choices=['ON', 'OFF'], type=str.upper,
92                         help='build jerry command line tool (%(choices)s)')
93    compgrp.add_argument('--jerry-cmdline-snapshot', metavar='X', choices=['ON', 'OFF'], type=str.upper,
94                         help='build snapshot command line tool (%(choices)s)')
95    compgrp.add_argument('--jerry-cmdline-test', metavar='X', choices=['ON', 'OFF'], type=str.upper,
96                         help=devhelp('build test version of the jerry command line tool (%(choices)s)'))
97    compgrp.add_argument('--libfuzzer', metavar='X', choices=['ON', 'OFF'], type=str.upper,
98                         help=devhelp('build jerry with libfuzzer support (%(choices)s)'))
99    compgrp.add_argument('--jerry-ext', metavar='X', choices=['ON', 'OFF'], type=str.upper,
100                         help='build jerry-ext (%(choices)s)')
101    compgrp.add_argument('--jerry-libm', metavar='X', choices=['ON', 'OFF'], type=str.upper,
102                         help='build and use jerry-libm (%(choices)s)')
103    compgrp.add_argument('--jerry-port-default', metavar='X', choices=['ON', 'OFF'], type=str.upper,
104                         help='build default jerry port implementation (%(choices)s)')
105    compgrp.add_argument('--unittests', metavar='X', choices=['ON', 'OFF'], type=str.upper,
106                         help=devhelp('build unittests (%(choices)s)'))
107
108    coregrp = parser.add_argument_group('jerry-core options')
109    coregrp.add_argument('--all-in-one', metavar='X', choices=['ON', 'OFF'], type=str.upper,
110                         help='all-in-one build (%(choices)s)')
111    coregrp.add_argument('--cpointer-32bit', metavar='X', choices=['ON', 'OFF'], type=str.upper,
112                         help='enable 32 bit compressed pointers (%(choices)s)')
113    coregrp.add_argument('--error-messages', metavar='X', choices=['ON', 'OFF'], type=str.upper,
114                         help='enable error messages (%(choices)s)')
115    coregrp.add_argument('--external-context', metavar='X', choices=['ON', 'OFF'], type=str.upper,
116                         help='enable external context (%(choices)s)')
117    coregrp.add_argument('--jerry-debugger', metavar='X', choices=['ON', 'OFF'], type=str.upper,
118                         help='enable the jerry debugger (%(choices)s)')
119    coregrp.add_argument('--js-parser', metavar='X', choices=['ON', 'OFF'], type=str.upper,
120                         help='enable js-parser (%(choices)s)')
121    coregrp.add_argument('--line-info', metavar='X', choices=['ON', 'OFF'], type=str.upper,
122                         help='provide line info (%(choices)s)')
123    coregrp.add_argument('--logging', metavar='X', choices=['ON', 'OFF'], type=str.upper,
124                         help='enable logging (%(choices)s)')
125    coregrp.add_argument('--mem-heap', metavar='SIZE', type=int,
126                         help='size of memory heap (in kilobytes)')
127    coregrp.add_argument('--gc-limit', metavar='SIZE', type=int,
128                         help='memory usage limit to trigger garbage collection (in bytes)')
129    coregrp.add_argument('--stack-limit', metavar='SIZE', type=int,
130                         help='maximum stack usage (in kilobytes)')
131    coregrp.add_argument('--gc-mark-limit', metavar='SIZE', type=int,
132                         help='maximum depth of recursion during GC mark phase')
133    coregrp.add_argument('--mem-stats', metavar='X', choices=['ON', 'OFF'], type=str.upper,
134                         help=devhelp('enable memory statistics (%(choices)s)'))
135    coregrp.add_argument('--mem-stress-test', metavar='X', choices=['ON', 'OFF'], type=str.upper,
136                         help=devhelp('enable mem-stress test (%(choices)s)'))
137    coregrp.add_argument('--profile', metavar='FILE',
138                         help='specify profile file')
139    coregrp.add_argument('--regexp-strict-mode', metavar='X', choices=['ON', 'OFF'], type=str.upper,
140                         help=devhelp('enable regexp strict mode (%(choices)s)'))
141    coregrp.add_argument('--show-opcodes', metavar='X', choices=['ON', 'OFF'], type=str.upper,
142                         help=devhelp('enable parser byte-code dumps (%(choices)s)'))
143    coregrp.add_argument('--show-regexp-opcodes', metavar='X', choices=['ON', 'OFF'], type=str.upper,
144                         help=devhelp('enable regexp byte-code dumps (%(choices)s)'))
145    coregrp.add_argument('--snapshot-exec', metavar='X', choices=['ON', 'OFF'], type=str.upper,
146                         help='enable executing snapshot files (%(choices)s)')
147    coregrp.add_argument('--snapshot-save', metavar='X', choices=['ON', 'OFF'], type=str.upper,
148                         help='enable saving snapshot files (%(choices)s)')
149    coregrp.add_argument('--system-allocator', metavar='X', choices=['ON', 'OFF'], type=str.upper,
150                         help='enable system allocator (%(choices)s)')
151    coregrp.add_argument('--valgrind', metavar='X', choices=['ON', 'OFF'], type=str.upper,
152                         help=devhelp('enable Valgrind support (%(choices)s)'))
153    coregrp.add_argument('--vm-exec-stop', metavar='X', choices=['ON', 'OFF'], type=str.upper,
154                         help='enable VM execution stopping (%(choices)s)')
155
156    maingrp = parser.add_argument_group('jerry-main options')
157    maingrp.add_argument('--link-map', metavar='X', choices=['ON', 'OFF'], type=str.upper,
158                         help=devhelp('enable the generation of link map for jerry command line tool (%(choices)s)'))
159
160    arguments = parser.parse_args(args)
161    if arguments.devhelp:
162        parser.print_help()
163        sys.exit(0)
164
165    return arguments
166
167def generate_build_options(arguments):
168    build_options = []
169
170    def build_options_append(cmakeopt, cliarg):
171        if cliarg:
172            build_options.append('-D%s=%s' % (cmakeopt, cliarg))
173
174    # general build options
175    build_options_append('CMAKE_BUILD_TYPE', arguments.build_type)
176    build_options_append('EXTERNAL_COMPILE_FLAGS', ' '.join(arguments.compile_flag))
177    build_options_append('EXTERNAL_LINK_LIBS', ' '.join(arguments.link_lib))
178    build_options_append('EXTERNAL_LINKER_FLAGS', ' '.join(arguments.linker_flag))
179    build_options_append('ENABLE_LTO', arguments.lto)
180    build_options_append('BUILD_SHARED_LIBS', arguments.shared_libs)
181    build_options_append('ENABLE_STRIP', arguments.strip)
182    build_options_append('CMAKE_TOOLCHAIN_FILE', arguments.toolchain)
183    build_options_append('CMAKE_VERBOSE_MAKEFILE', arguments.verbose)
184
185    # optional components
186    build_options_append('DOCTESTS', arguments.doctests)
187    build_options_append('JERRY_CMDLINE', arguments.jerry_cmdline)
188    build_options_append('JERRY_CMDLINE_SNAPSHOT', arguments.jerry_cmdline_snapshot)
189    build_options_append('JERRY_CMDLINE_TEST', arguments.jerry_cmdline_test)
190    build_options_append('JERRY_LIBFUZZER', arguments.libfuzzer)
191    build_options_append('JERRY_EXT', arguments.jerry_ext)
192    build_options_append('JERRY_LIBM', arguments.jerry_libm)
193    build_options_append('JERRY_PORT_DEFAULT', arguments.jerry_port_default)
194    build_options_append('UNITTESTS', arguments.unittests)
195
196    # jerry-core options
197    build_options_append('ENABLE_ALL_IN_ONE', arguments.all_in_one)
198    build_options_append('JERRY_CPOINTER_32_BIT', arguments.cpointer_32bit)
199    build_options_append('JERRY_ERROR_MESSAGES', arguments.error_messages)
200    build_options_append('JERRY_EXTERNAL_CONTEXT', arguments.external_context)
201    build_options_append('JERRY_DEBUGGER', arguments.jerry_debugger)
202    build_options_append('JERRY_PARSER', arguments.js_parser)
203    build_options_append('JERRY_LINE_INFO', arguments.line_info)
204    build_options_append('JERRY_LOGGING', arguments.logging)
205    build_options_append('JERRY_GLOBAL_HEAP_SIZE', arguments.mem_heap)
206    build_options_append('JERRY_GC_LIMIT', arguments.gc_limit)
207    build_options_append('JERRY_STACK_LIMIT', arguments.stack_limit)
208    build_options_append('JERRY_MEM_STATS', arguments.mem_stats)
209    build_options_append('JERRY_MEM_GC_BEFORE_EACH_ALLOC', arguments.mem_stress_test)
210    build_options_append('JERRY_PROFILE', arguments.profile)
211    build_options_append('JERRY_REGEXP_STRICT_MODE', arguments.regexp_strict_mode)
212    build_options_append('JERRY_PARSER_DUMP_BYTE_CODE', arguments.show_opcodes)
213    build_options_append('JERRY_REGEXP_DUMP_BYTE_CODE', arguments.show_regexp_opcodes)
214    build_options_append('JERRY_SNAPSHOT_EXEC', arguments.snapshot_exec)
215    build_options_append('JERRY_SNAPSHOT_SAVE', arguments.snapshot_save)
216    build_options_append('JERRY_SYSTEM_ALLOCATOR', arguments.system_allocator)
217    build_options_append('JERRY_VALGRIND', arguments.valgrind)
218    build_options_append('JERRY_VM_EXEC_STOP', arguments.vm_exec_stop)
219
220    if arguments.gc_mark_limit is not None:
221        build_options.append('-D%s=%s' % ('JERRY_GC_MARK_LIMIT', arguments.gc_mark_limit))
222
223    # jerry-main options
224    build_options_append('ENABLE_LINK_MAP', arguments.link_map)
225
226    # general build options (final step)
227    if arguments.cmake_param:
228        build_options.extend(arguments.cmake_param)
229
230    return build_options
231
232def configure_output_dir(arguments):
233    if not os.path.isabs(arguments.builddir):
234        arguments.builddir = os.path.join(settings.PROJECT_DIR, arguments.builddir)
235
236    if arguments.clean and os.path.exists(arguments.builddir):
237        shutil.rmtree(arguments.builddir)
238
239    if not os.path.exists(arguments.builddir):
240        os.makedirs(arguments.builddir)
241
242def configure_jerry(arguments):
243    configure_output_dir(arguments)
244
245    build_options = generate_build_options(arguments)
246
247    cmake_cmd = ['cmake', '-B' + arguments.builddir, '-H' + settings.PROJECT_DIR]
248
249    if arguments.install:
250        cmake_cmd.append('-DCMAKE_INSTALL_PREFIX=%s' % arguments.install)
251
252    cmake_cmd.extend(build_options)
253
254    return subprocess.call(cmake_cmd)
255
256def make_jerry(arguments):
257    make_cmd = ['cmake', '--build', arguments.builddir, '--config', arguments.build_type]
258    env = dict(os.environ)
259    env['CMAKE_BUILD_PARALLEL_LEVEL'] = str(arguments.jobs)
260    env['MAKEFLAGS'] = '-j%d' % (arguments.jobs) # Workaround for CMake < 3.12
261    proc = subprocess.Popen(make_cmd, env=env)
262    proc.wait()
263
264    return proc.returncode
265
266def install_jerry(arguments):
267    install_target = 'INSTALL' if sys.platform == 'win32' else 'install'
268    make_cmd = ['cmake', '--build', arguments.builddir, '--config', arguments.build_type, '--target', install_target]
269    return subprocess.call(make_cmd)
270
271def print_result(ret):
272    print('=' * 30)
273    if ret:
274        print('Build failed with exit code: %s' % (ret))
275    else:
276        print('Build succeeded!')
277    print('=' * 30)
278
279def main():
280    arguments = get_arguments()
281
282    ret = configure_jerry(arguments)
283
284    if not ret:
285        ret = make_jerry(arguments)
286
287    if not ret and arguments.install is not None:
288        ret = install_jerry(arguments)
289
290    print_result(ret)
291    sys.exit(ret)
292
293
294if __name__ == "__main__":
295    main()
296