Beispiel #1
0
    def create():
        logging.info('building port: harfbuzz')
        ports.clear_project_build('harfbuzz')

        source_path = os.path.join(ports.get_dir(), 'harfbuzz',
                                   'harfbuzz-' + TAG)
        dest_path = os.path.join(ports.get_build_dir(), 'harfbuzz')

        freetype_lib = shared.Cache.get_path('libfreetype.a')
        freetype_include = os.path.join(ports.get_include_dir(), 'freetype2',
                                        'freetype')
        freetype_include_dirs = freetype_include + ';' + os.path.join(
            freetype_include, 'config')

        configure_args = [
            'cmake', '-G', 'Unix Makefiles', '-B' + dest_path,
            '-H' + source_path, '-DCMAKE_BUILD_TYPE=Release',
            '-DCMAKE_INSTALL_PREFIX=' + dest_path,
            '-DFREETYPE_INCLUDE_DIRS=' + freetype_include_dirs,
            '-DFREETYPE_LIBRARY=' + freetype_lib, '-DHB_HAVE_FREETYPE=ON'
        ]

        if settings.USE_PTHREADS:
            configure_args += ['-DCMAKE_CXX_FLAGS="-pthread"']

        building.configure(configure_args)
        building.make([
            'make',
            '-j%d' % building.get_num_cores(), '-C' + dest_path, 'install'
        ])

        ports.install_header_dir(os.path.join(dest_path, 'include',
                                              'harfbuzz'))

        return os.path.join(dest_path, 'libharfbuzz.a')
Beispiel #2
0
    def create(final):
        logging.info('building port: harfbuzz')
        ports.clear_project_build('harfbuzz')

        source_path = os.path.join(ports.get_dir(), 'harfbuzz',
                                   'harfbuzz-' + TAG)
        dest_path = os.path.join(ports.get_build_dir(), 'harfbuzz')

        freetype_lib = shared.Cache.get_path(
            shared.Cache.get_lib_name('libfreetype.a'))
        freetype_include = os.path.join(ports.get_include_dir(), 'freetype2',
                                        'freetype')
        freetype_include_dirs = freetype_include + ';' + os.path.join(
            freetype_include, 'config')

        configure_args = [
            'cmake', '-G', 'Unix Makefiles', '-B' + dest_path,
            '-H' + source_path, '-DCMAKE_BUILD_TYPE=Release',
            '-DCMAKE_INSTALL_PREFIX=' + dest_path,
            '-DFREETYPE_INCLUDE_DIRS=' + freetype_include_dirs,
            '-DFREETYPE_LIBRARY=' + freetype_lib, '-DHB_HAVE_FREETYPE=ON'
        ]

        extra_cflags = []

        if settings.RELOCATABLE:
            extra_cflags.append('-fPIC')

        if settings.USE_PTHREADS:
            extra_cflags.append('-pthread')

        if len(extra_cflags):
            configure_args += [
                '-DCMAKE_CXX_FLAGS="{}"'.format(' '.join(extra_cflags))
            ]
            configure_args += [
                '-DCMAKE_C_FLAGS="{}"'.format(' '.join(extra_cflags))
            ]

        building.configure(configure_args)
        building.make([
            'make',
            '-j%d' % building.get_num_cores(), '-C' + dest_path, 'install'
        ])

        ports.install_header_dir(os.path.join(dest_path, 'include',
                                              'harfbuzz'))

        shutil.copyfile(os.path.join(dest_path, 'libharfbuzz.a'), final)
Beispiel #3
0
def run():
    if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'):
        print('''\
emcmake is a helper for cmake, setting various environment
variables so that emcc etc. are used. Typical usage:

  emcmake cmake [FLAGS]
''',
              file=sys.stderr)
        return 1

    try:
        building.configure(sys.argv[1:])
        return 0
    except CalledProcessError as e:
        return e.returncode
Beispiel #4
0
def run():
    if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'):
        print('''\
emconfigure is a helper for configure, setting various environment
variables so that emcc etc. are used. Typical usage:

  emconfigure ./configure [FLAGS]

(but you can run any command instead of configure)''',
              file=sys.stderr)
        return 1

    if 'cmake' in sys.argv[1]:
        print(
            'error: use `emcmake` rather then `emconfigure` for cmake projects',
            file=sys.stderr)
        return 1

    try:
        building.configure(sys.argv[1:])
        return 0
    except CalledProcessError as e:
        return e.returncode
Beispiel #5
0
def build():
  this_dir = os.getcwd()
  if not os.path.exists('build'):
    os.makedirs('build')
  os.chdir('build')
  targetfile = "occt.tar.gz"

  ######################################
  if not os.path.exists('occt.tar.gz'):
    stage("downloading OCCT...")
    url = "https://git.dev.opencascade.org/gitweb/?p=occt.git;a=snapshot;h=fd47711d682be943f0e0a13d1fb54911b0499c31;sf=tgz"
    myfile = requests.get(url, stream=True)
    open(targetfile, 'wb').write(myfile.content)

  ######################################
  if not os.path.exists('occt'):
    stage("extracting OCCT, patching...")
    tar = tarfile.open(targetfile, "r:gz")
    tar.extractall("occt")
    tar.close()
    source = "occt/" + os.listdir("occt")[0] + "/"
    dest = "occt"
    files = os.listdir(source)
    for f in files:
      shutil.move(source+f, dest)
    patch.fromfile("../patches/CMakeLists.txt.patch").apply()
    pset = patch.fromfile("../patches/OSD_Path.cxx.patch").apply()
    pset = patch.fromfile("../patches/OSD_Process.cxx.patch").apply()
    pset = patch.fromfile("../patches/Bnd_Box.hxx.patch").apply()
    pset = patch.fromfile("../patches/BRepGProp.hxx.patch").apply()

  if not os.path.exists('regal'):
    stage("downloading and extracting regal...")
    url = "https://github.com/p3/regal/archive/master.tar.gz"
    myfile = requests.get(url, stream=True)
    open("regal.tar.gz", 'wb').write(myfile.content)
    tar = tarfile.open("regal.tar.gz", "r:gz")
    tar.extractall("regal")
    tar.close()

  if not os.path.exists('freetype'):
    stage("downloading and extracting freetype...")
    url = "https://git.savannah.gnu.org/cgit/freetype/freetype2.git/snapshot/freetype2-VER-2-10-1.tar.gz"
    myfile = requests.get(url, stream=True)
    open("freetype.tar.gz", 'wb').write(myfile.content)
    tar = tarfile.open("freetype.tar.gz", "r:gz")
    tar.extractall("freetype")
    tar.close()

  if not os.path.exists('fontconfig'):
    stage("downloading and extracting fontconfig...")
    url = "https://gitlab.freedesktop.org/fontconfig/fontconfig/-/archive/2.13.92/fontconfig-2.13.92.tar.gz"
    myfile = requests.get(url, stream=True)
    open("fontconfig.tar.gz", 'wb').write(myfile.content)
    tar = tarfile.open("fontconfig.tar.gz", "r:gz")
    tar.extractall("fontconfig")
    tar.close()

  ######################################
  stage("checking EMSCRIPTEN...")
  envEMSDK = os.environ.get('EMSDK')
  if not envEMSDK:
    print("ERROR: envEMSDK environment variable not found")
    sys.exit(1)
  sys.path.append(os.path.join(envEMSDK, 'upstream', 'emscripten'))
  import tools.building as emscripten
  
  ######################################
  stage("build settings...")
  wasm = 'wasm' in sys.argv
  closure = 'closure' in sys.argv
  add_function_support = 'add_func' in sys.argv
  args = '-std=c++1z -s NO_EXIT_RUNTIME=1 -s EXPORTED_RUNTIME_METHODS=["UTF8ToString"]'
  args += ' -O3'
  args += ' --llvm-lto 3'
  if add_function_support:
    args += ' -s RESERVED_FUNCTION_POINTERS=20 -s EXTRA_EXPORTED_RUNTIME_METHODS=["addFunction"]'  
  if wasm:
    args += ''' -s WASM=1'''
  else:
    args += ' -s WASM=0 -s ELIMINATE_DUPLICATE_FUNCTIONS=1 -s SINGLE_FILE=1 -s LEGACY_VM_SUPPORT=1'
  if closure:
    args += ' --closure 1 -s IGNORE_CLOSURE_COMPILER_ERRORS=1'
  else:
    args += ' -s NO_DYNAMIC_EXECUTION=1'
  emcc_args = args.split(' ')
  emcc_args += ['-s', 'TOTAL_MEMORY=%d' % (128*1024*1024)]
  emcc_args += ['-s', 'ALLOW_MEMORY_GROWTH=1']
  emcc_args += '-s EXPORT_NAME="opencascade"'.split(' ')
  emcc_args += '-s MODULARIZE=1'.split(' ')
  emcc_args += ['-s', 'EXTRA_EXPORTED_RUNTIME_METHODS=["FS"]']
  emcc_args += ['-s', 'EXPORT_ES6=1']
  emcc_args += ['-s', 'USE_ES6_IMPORT_META=0']
  emcc_args += ['-s', 'AGGRESSIVE_VARIABLE_ELIMINATION=1']

  # Debugging options
  # emcc_args += ['-s', 'ASSERTIONS=2']
  # emcc_args += ['-s', 'STACK_OVERFLOW_CHECK=1']
  # emcc_args += ['-s', 'DEMANGLE_SUPPORT=1']
  # emcc_args += ['-s', 'DISABLE_EXCEPTION_CATCHING=0']
  # emcc_args += ['-g']

  target = 'opencascade.js' if not wasm else 'opencascade.wasm.js'

  ######################################
  stage('generate bindings...')

  Popen([emscripten.PYTHON, os.path.join(envEMSDK, 'upstream', 'emscripten', 'tools', 'webidl_binder.py'), os.path.join(this_dir, 'opencascade.idl'), 'glue']).communicate()
  assert os.path.exists('glue.js')
  assert os.path.exists('glue.cpp')

  ######################################
  stage('Build bindings')

  myincludes = [x[1] for x in os.walk(os.path.join('.', 'occt', 'src'))][0]
  myincludes = ['-I./occt/src/{0}'.format(s) for s in myincludes]
  myincludes.extend([
    '-I./../',
    '-c',
    '-std=c++1z',
  ])

  args = copy.deepcopy(myincludes)
  for include in INCLUDES:
    args += ['-include', include]
  emscripten.emcc('glue.cpp', args, 'glue.o')
  assert(os.path.exists('glue.o'))

  if not os.path.exists('build'):
    os.makedirs('build')
  os.chdir('build')

  cmake_build = True

  if cmake_build:
    stage('Configure via CMake')
    emscripten.configure([
      'cmake',
      '../occt/',
      '-DCMAKE_BUILD_TYPE=Release',
      '-D3RDPARTY_FREETYPE_INCLUDE_DIR_freetype2=../freetype/freetype2-VER-2-10-1/include/freetype',
      '-D3RDPARTY_FREETYPE_INCLUDE_DIR_ft2build=../freetype/freetype2-VER-2-10-1/include',
      '-DBUILD_LIBRARY_TYPE=Static',
      '-DCMAKE_CXX_FLAGS="-DIGNORE_NO_ATOMICS=1 -frtti"',
      '-D3RDPARTY_INCLUDE_DIRS=../regal/regal-master/src/apitrace/thirdparty/khronos/\;../fontconfig/fontconfig-2.13.92',
      '-DUSE_GLES2=ON',
      '-DBUILD_MODULE_Draw=OFF',
      '-DBUILD_ADDITIONAL_TOOLKITS=OFF',
      '-DBUILD_MODULE_Visualization=OFF',
      '-DBUILD_MODULE_ApplicationFramework=OFF'
    ])

  make_build = True
  if make_build:
    stage('Make')

    CORES = multiprocessing.cpu_count()

    emscripten.make(['make', '-j', str(CORES)])

  stage('Link')

  opencascade_libs = os.listdir(os.path.join('.', 'lin32', 'clang', 'lib'))
  opencascade_libs = [os.path.join('.', 'build', 'lin32', 'clang', 'lib', s) for s in opencascade_libs]

  stage('emcc: ' + ' '.join(emcc_args))
  os.chdir('..')
  if not os.path.exists('js'):
    os.makedirs('js')

  temp = os.path.join('.', 'js', target)
  emscripten.emcc('-DNOTHING_WAKA_WAKA', emcc_args + ['glue.o'] + opencascade_libs + myincludes[:len(myincludes)-2] + ['--js-transform', 'python %s' % os.path.join('..', 'bundle.py')], temp)

  assert os.path.exists(temp), 'Failed to create script code'

  stage('wrap')

  wrapped = '''
// This is opencascade.js.
''' + open(temp).read()

  open(temp, 'w').write(wrapped)

  os.chdir('..')
  if not wasm:
    shutil.copyfile(os.path.join('build', 'js', 'opencascade.js'), os.path.join('dist', 'opencascade.js'))
  else:
    shutil.copyfile(os.path.join('build', 'js', 'opencascade.wasm.js'), os.path.join('dist', 'opencascade.wasm.js'))
    shutil.copyfile(os.path.join('build', 'js', 'opencascade.wasm.js'), os.path.join('dist', 'opencascade.wasm.module.js'))
    shutil.copyfile(os.path.join('build', 'js', 'opencascade.wasm.wasm'), os.path.join('dist', 'opencascade.wasm.wasm'))

    # Comment out the ES6 Export in the non-.module.js
    wasmJSFile = open(os.path.join('dist', 'opencascade.wasm.js'), mode="r+")
    wasmJSLines = wasmJSFile.readlines()
    wasmJSFile.seek(0)
    wasmJSLines[len(wasmJSLines)-1] = "//" + wasmJSLines[len(wasmJSLines)-1]
    wasmJSFile.writelines(wasmJSLines)
    wasmJSFile.close()
Beispiel #6
0
def build():
    this_dir = os.getcwd()

    stage("clearing dist folder")
    os.chdir('dist')
    os.system("rm * -fr")
    os.chdir('..')

    if not os.path.exists('build'):
        os.makedirs('build')
    os.chdir('build')

    # stage("clearing build folder")
    # os.system("rm * -fr")

    ######################################
    targetfile = "occt.tar.gz"
    if not os.path.exists(targetfile):
        stage("downloading OCCT...")
        url = "https://git.dev.opencascade.org/gitweb/?p=occt.git;a=snapshot;h=33d9a6fa21ca4fa711da7066655aa2ba854545ee;sf=tgz"
        myfile = requests.get(url, stream=True)
        open(targetfile, 'wb').write(myfile.content)

    ######################################
    if not os.path.exists('occt'):
        stage("extracting OCCT, patching...")
        tar = tarfile.open(targetfile, "r:gz")
        tar.extractall("occt")
        tar.close()
        source = "occt/" + os.listdir("occt")[0] + "/"
        dest = "occt"
        files = os.listdir(source)
        for f in files:
            shutil.move(source + f, dest)

        patchDir = "../patches/"
        for filename in os.listdir(patchDir):
            patch.fromfile(os.path.join(patchDir, filename)).apply()

    if not os.path.exists('regal'):
        stage("downloading and extracting regal...")
        url = "https://github.com/p3/regal/archive/master.tar.gz"
        myfile = requests.get(url, stream=True)
        open("regal.tar.gz", 'wb').write(myfile.content)
        tar = tarfile.open("regal.tar.gz", "r:gz")
        tar.extractall("regal")
        tar.close()

    if not os.path.exists('freetype'):
        stage("downloading and extracting freetype...")
        url = "https://git.savannah.gnu.org/cgit/freetype/freetype2.git/snapshot/freetype2-VER-2-10-1.tar.gz"
        myfile = requests.get(url, stream=True)
        open("freetype.tar.gz", 'wb').write(myfile.content)
        tar = tarfile.open("freetype.tar.gz", "r:gz")
        tar.extractall("freetype")
        tar.close()

    if not os.path.exists('fontconfig'):
        stage("downloading and extracting fontconfig...")
        url = "https://gitlab.freedesktop.org/fontconfig/fontconfig/-/archive/2.13.92/fontconfig-2.13.92.tar.gz"
        myfile = requests.get(url, stream=True)
        open("fontconfig.tar.gz", 'wb').write(myfile.content)
        tar = tarfile.open("fontconfig.tar.gz", "r:gz")
        tar.extractall("fontconfig")
        tar.close()

    ######################################
    stage("checking EMSCRIPTEN...")
    envEMSDK = os.environ.get('EMSDK')
    if not envEMSDK:
        print("ERROR: envEMSDK environment> variable not found")
        sys.exit(1)
    sys.path.append(os.path.join(envEMSDK, 'upstream', 'emscripten'))
    import tools.building as emscripten

    #####################################
    stage('Build bindings')

    myincludes = [x[1] for x in os.walk(os.path.join('.', 'occt', 'src'))][0]
    myincludes = ['-I./occt/src/{0}'.format(s) for s in myincludes]
    myincludes.extend([
        '-I./../',
        '-c',
        '-std=c++1z',
    ])

    args = copy.deepcopy(myincludes)
    for include in INCLUDES:
        args += ['-include', include]

    if not os.path.exists('build'):
        os.makedirs('build')
    os.chdir('build')

    cmake_build = True

    if cmake_build:
        stage('Configure via CMake')
        emscripten.configure([
            'cmake', '../occt/', '-DCMAKE_BUILD_TYPE=Release',
            '-D3RDPARTY_FREETYPE_INCLUDE_DIR_freetype2=../freetype/freetype2-VER-2-10-1/include/freetype',
            '-D3RDPARTY_FREETYPE_INCLUDE_DIR_ft2build=../freetype/freetype2-VER-2-10-1/include',
            '-DBUILD_LIBRARY_TYPE=Static',
            '-DCMAKE_CXX_FLAGS="-DIGNORE_NO_ATOMICS=1 -frtti"',
            '-D3RDPARTY_INCLUDE_DIRS=../regal/regal-master/src/apitrace/thirdparty/khronos/\;../fontconfig/fontconfig-2.13.92',
            '-DUSE_GLES2=ON', '-DBUILD_MODULE_Draw=OFF',
            '-DBUILD_ADDITIONAL_TOOLKITS=ON',
            '-DBUILD_MODULE_Visualization=ON',
            '-DBUILD_MODULE_ApplicationFramework=ON'
        ])

    ###############
    stage('Make')

    CORES = multiprocessing.cpu_count()

    make_build = True

    if make_build:
        emscripten.make(['make', '-j', str(CORES)])

    ######################################
    stage('generate bindings...')

    os.chdir('../../embind')
    subprocess.call(['python3.8', './autobind.py'])
    os.chdir('../build')

    ######################################
    stage("build settings...")
    wasm = 'wasm' in sys.argv
    closure = 'closure' in sys.argv
    add_function_support = 'add_func' in sys.argv
    args = '-std=c++1z -s NO_EXIT_RUNTIME=1 -s EXPORTED_RUNTIME_METHODS=["UTF8ToString"]'
    args += ' -O3'
    if add_function_support:
        args += ' -s RESERVED_FUNCTION_POINTERS=20 -s EXTRA_EXPORTED_RUNTIME_METHODS=["addFunction"]'
    if wasm:
        args += ''' -s WASM=1'''
    else:
        args += ' -s WASM=0 -s ELIMINATE_DUPLICATE_FUNCTIONS=1 -s SINGLE_FILE=1 -s LEGACY_VM_SUPPORT=1'
    if closure:
        args += ' --closure 1 -s IGNORE_CLOSURE_COMPILER_ERRORS=1'
    else:
        args += ' -s NO_DYNAMIC_EXECUTION=1'
    emcc_args = args.split(' ')
    emcc_args += ['-s', 'TOTAL_MEMORY=%d' % (64 * 1024 * 1024)]
    emcc_args += ['-s', 'ALLOW_MEMORY_GROWTH=1']
    emcc_args += '-s EXPORT_NAME="opencascade"'.split(' ')
    emcc_args += '-s MODULARIZE=1'.split(' ')
    emcc_args += ['-s', 'EXTRA_EXPORTED_RUNTIME_METHODS=["FS"]']
    emcc_args += ['-s', 'EXPORT_ES6=1']
    emcc_args += ['-s', 'USE_ES6_IMPORT_META=0']
    emcc_args += ['-s', 'AGGRESSIVE_VARIABLE_ELIMINATION=1']

    # Debugging options
    # emcc_args += ['-s', 'ASSERTIONS=2']
    # emcc_args += ['-s', 'STACK_OVERFLOW_CHECK=1']
    # emcc_args += ['-s', 'DEMANGLE_SUPPORT=1']
    # emcc_args += ['-s', 'DISABLE_EXCEPTION_CATCHING=0']
    # emcc_args += ['-g']

    stage('Link')

    os.chdir('build')
    opencascade_libs = os.listdir(os.path.join('.', 'lin32', 'clang', 'lib'))
    opencascade_libs = [
        os.path.join('.', 'build', 'lin32', 'clang', 'lib', s)
        for s in opencascade_libs
    ]

    stage('emcc: ' + ' '.join(emcc_args))
    os.chdir('..')
    if not os.path.exists('js'):
        os.makedirs('js')

    target = 'opencascade.js' if not wasm else 'opencascade.wasm.js'
    temp = os.path.join('.', 'js', target)
    shutil.copytree(os.path.join('..', 'embind'),
                    os.path.join('.', 'embind'),
                    dirs_exist_ok=True)

    includePrefix = os.path.join(".", "occt", "src")
    includePaths = os.listdir(includePrefix)
    includeArgs = [
        '-I' + os.path.join('.', 'occt', 'src'),
        '-I' + os.path.join('.', 'regal', 'regal-master', 'src', 'apitrace',
                            'thirdparty', 'khronos')
    ]
    for path in includePaths:
        includeArgs.append('-I' + os.path.join(".", includePrefix, path))

    emccArgs = ['--bind'] + includeArgs + opencascade_libs + emcc_args
    emscripten.emcc(os.path.join('.', 'bindings.cpp'), emccArgs, temp)

    stage('wrap')

    wrapped = '''
// This is opencascade.js.
''' + open(temp).read()

    open(temp, 'w').write(wrapped)

    os.chdir("..")
    if not os.path.exists('dist'):
        os.makedirs('dist')

    if not wasm:
        shutil.copyfile(os.path.join('build', 'js', 'opencascade.js'),
                        os.path.join('dist', 'opencascade.js'))
    else:
        shutil.copyfile(os.path.join('build', 'js', 'opencascade.wasm.js'),
                        os.path.join('dist', 'opencascade.wasm.js'))
        shutil.copyfile(os.path.join('build', 'js', 'opencascade.wasm.wasm'),
                        os.path.join('dist', 'opencascade.wasm.wasm'))
Beispiel #7
0
def build():
    EMSCRIPTEN_ROOT = os.environ.get('EMSCRIPTEN')
    if not EMSCRIPTEN_ROOT:
        emcc = which('emcc')
        EMSCRIPTEN_ROOT = os.path.dirname(emcc)

    if not EMSCRIPTEN_ROOT:
        print "ERROR: EMSCRIPTEN_ROOT environment variable (which should be equal to emscripten's root dir) not found"
        sys.exit(1)

    sys.path.append(EMSCRIPTEN_ROOT)
    import tools.building as emscripten

    # Settings
    '''
            Settings.INLINING_LIMIT = 0
            Settings.DOUBLE_MODE = 0
            Settings.PRECISE_I64_MATH = 0
            Settings.CORRECT_SIGNS = 0
            Settings.CORRECT_OVERFLOWS = 0
            Settings.CORRECT_ROUNDINGS = 0
  '''

    wasm = 'wasm' in sys.argv
    closure = 'closure' in sys.argv
    add_function_support = 'add_func' in sys.argv

    args = '-O3 --llvm-lto 1 -s NO_EXIT_RUNTIME=1 -s NO_FILESYSTEM=1 -s EXPORTED_RUNTIME_METHODS=["UTF8ToString"]'
    if add_function_support:
        args += ' -s RESERVED_FUNCTION_POINTERS=20 -s EXTRA_EXPORTED_RUNTIME_METHODS=["addFunction"]'
    if not wasm:
        args += ' -s WASM=0 -s AGGRESSIVE_VARIABLE_ELIMINATION=1 -s ELIMINATE_DUPLICATE_FUNCTIONS=1 -s SINGLE_FILE=1 -s LEGACY_VM_SUPPORT=1'
    else:
        args += ''' -s WASM=1 -s BINARYEN_IGNORE_IMPLICIT_TRAPS=1'''
    if closure:
        args += ' --closure 1 -s IGNORE_CLOSURE_COMPILER_ERRORS=1'  # closure complains about the bullet Node class (Node is a DOM thing too)
    else:
        args += ' -s NO_DYNAMIC_EXECUTION=1'

    emcc_args = args.split(' ')

    emcc_args += [
        '-s', 'TOTAL_MEMORY=%d' % (64 * 1024 * 1024)
    ]  # default 64MB. Compile with ALLOW_MEMORY_GROWTH if you want a growable heap (slower though).
    #emcc_args += ['-s', 'ALLOW_MEMORY_GROWTH=1'] # resizable heap, with some amount of slowness

    emcc_args += '-s EXPORT_NAME="Ammo" -s MODULARIZE=1'.split(' ')

    target = 'ammo.js' if not wasm else 'ammo.wasm.js'

    print
    print '--------------------------------------------------'
    print 'Building ammo.js, build type:', emcc_args
    print '--------------------------------------------------'
    print
    '''
  import os, sys, re

  infile = open(sys.argv[1], 'r').read()
  outfile = open(sys.argv[2], 'w')

  t1 = infile
  while True:
    t2 = re.sub(r'\(\n?!\n?1\n?\+\n?\(\n?!\n?1\n?\+\n?(\w)\n?\)\n?\)', lambda m: '(!1+' + m.group(1) + ')', t1)
    print len(infile), len(t2)
    if t1 == t2: break
    t1 = t2

  outfile.write(t2)
  '''

    # Utilities

    def stage(text):
        global stage_counter
        stage_counter += 1
        text = 'Stage %d: %s' % (stage_counter, text)
        print
        print '=' * len(text)
        print text
        print '=' * len(text)
        print

    # Main

    try:
        this_dir = os.getcwd()
        os.chdir('bullet')
        if not os.path.exists('build'):
            os.makedirs('build')
        os.chdir('build')

        stage('Generate bindings')

        Popen([
            emscripten.PYTHON,
            os.path.join(EMSCRIPTEN_ROOT, 'tools', 'webidl_binder.py'),
            os.path.join(this_dir, 'ammo.idl'), 'glue'
        ]).communicate()
        assert os.path.exists('glue.js')
        assert os.path.exists('glue.cpp')

        stage('Build bindings')

        args = ['-I../src', '-c']
        for include in INCLUDES:
            args += ['-include', include]
        emscripten.emcc('glue.cpp', args, 'glue.o')
        assert (os.path.exists('glue.o'))

        # Configure with CMake on Windows, and with configure on Unix.
        cmake_build = emscripten.WINDOWS

        if cmake_build:
            if not os.path.exists('CMakeCache.txt'):
                stage('Configure via CMake')
                emscripten.configure([
                    emscripten.PYTHON,
                    os.path.join(EMSCRIPTEN_ROOT, 'emcmake'), 'cmake', '..',
                    '-DBUILD_DEMOS=OFF', '-DBUILD_EXTRAS=OFF',
                    '-DBUILD_CPU_DEMOS=OFF', '-DUSE_GLUT=OFF',
                    '-DCMAKE_BUILD_TYPE=Release'
                ])
        else:
            if not os.path.exists('config.h'):
                stage(
                    'Configure (if this fails, run autogen.sh in bullet/ first)'
                )
                emscripten.configure([
                    '../configure', '--disable-demos',
                    '--disable-dependency-tracking'
                ])

        stage('Make')

        CORES = multiprocessing.cpu_count()

        if emscripten.WINDOWS:
            emscripten.make(['mingw32-make', '-j', str(CORES)])
        else:
            emscripten.make(['make', '-j', str(CORES)])

        stage('Link')

        if cmake_build:
            bullet_libs = [
                os.path.join('src', 'BulletSoftBody', 'libBulletSoftBody.a'),
                os.path.join('src', 'BulletDynamics', 'libBulletDynamics.a'),
                os.path.join('src', 'BulletCollision', 'libBulletCollision.a'),
                os.path.join('src', 'LinearMath', 'libLinearMath.a')
            ]
        else:
            bullet_libs = [
                os.path.join('src', '.libs', 'libBulletSoftBody.a'),
                os.path.join('src', '.libs', 'libBulletDynamics.a'),
                os.path.join('src', '.libs', 'libBulletCollision.a'),
                os.path.join('src', '.libs', 'libLinearMath.a')
            ]

        stage('emcc: ' + ' '.join(emcc_args))

        temp = os.path.join('..', '..', 'builds', target)
        emscripten.emcc(
            '-DNOTHING_WAKA_WAKA', emcc_args + ['glue.o'] + bullet_libs + [
                '--js-transform',
                'python %s' % os.path.join('..', '..', 'bundle.py')
            ], temp)

        assert os.path.exists(temp), 'Failed to create script code'

        stage('wrap')

        wrapped = '''
  // This is ammo.js, a port of Bullet Physics to JavaScript. zlib licensed.
  ''' + open(temp).read()

        open(temp, 'w').write(wrapped)

    finally:
        os.chdir(this_dir)