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