# Copyright 2012 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
#     * Neither the name of Google Inc. nor the names of its
#       contributors may be used to endorse or promote products derived
#       from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import sys
from os.path import join, dirname, abspath
root_dir = dirname(File('SConstruct').rfile().abspath)
sys.path.append(join(root_dir, 'tools'))
import js2c
Import('context')
Import('tools')
Import('d8_env')


SOURCES = {
  'all': Split("""
    accessors.cc
    allocation.cc
    api.cc
    assembler.cc
    ast.cc
    atomicops_internals_x86_gcc.cc
    bignum.cc
    bignum-dtoa.cc
    bootstrapper.cc
    builtins.cc
    cached-powers.cc
    checks.cc
    circular-queue.cc
    code-stubs.cc
    codegen.cc
    compilation-cache.cc
    compiler.cc
    contexts.cc
    conversions.cc
    counters.cc
    cpu-profiler.cc
    data-flow.cc
    date.cc
    dateparser.cc
    debug-agent.cc
    debug.cc
    deoptimizer.cc
    disassembler.cc
    diy-fp.cc
    dtoa.cc
    elements.cc
    execution.cc
    factory.cc
    flags.cc
    frames.cc
    full-codegen.cc
    func-name-inferrer.cc
    gdb-jit.cc
    global-handles.cc
    fast-dtoa.cc
    fixed-dtoa.cc
    handles.cc
    heap-profiler.cc
    heap.cc
    hydrogen.cc
    hydrogen-instructions.cc
    ic.cc
    incremental-marking.cc
    interface.cc
    inspector.cc
    interpreter-irregexp.cc
    isolate.cc
    jsregexp.cc
    lithium-allocator.cc
    lithium.cc
    liveedit.cc
    liveobjectlist.cc
    log-utils.cc
    log.cc
    mark-compact.cc
    messages.cc
    objects.cc
    objects-printer.cc
    objects-visiting.cc
    once.cc
    parser.cc
    preparser.cc
    preparse-data.cc
    profile-generator.cc
    property.cc
    regexp-macro-assembler-irregexp.cc
    regexp-macro-assembler.cc
    regexp-stack.cc
    rewriter.cc
    runtime.cc
    runtime-profiler.cc
    safepoint-table.cc
    scanner.cc
    scanner-character-streams.cc
    scopeinfo.cc
    scopes.cc
    serialize.cc
    snapshot-common.cc
    spaces.cc
    string-search.cc
    string-stream.cc
    strtod.cc
    stub-cache.cc
    token.cc
    type-info.cc
    unicode.cc
    utils.cc
    v8-counters.cc
    v8.cc
    v8conversions.cc
    v8threads.cc
    v8utils.cc
    variables.cc
    version.cc
    store-buffer.cc
    zone.cc
    extensions/gc-extension.cc
    extensions/externalize-string-extension.cc
    """),
  'arch:arm': Split("""
    arm/builtins-arm.cc
    arm/code-stubs-arm.cc
    arm/codegen-arm.cc
    arm/constants-arm.cc
    arm/cpu-arm.cc
    arm/debug-arm.cc
    arm/deoptimizer-arm.cc
    arm/disasm-arm.cc
    arm/frames-arm.cc
    arm/full-codegen-arm.cc
    arm/ic-arm.cc
    arm/lithium-arm.cc
    arm/lithium-codegen-arm.cc
    arm/lithium-gap-resolver-arm.cc
    arm/macro-assembler-arm.cc
    arm/regexp-macro-assembler-arm.cc
    arm/stub-cache-arm.cc
    arm/assembler-arm.cc
    """),
  'arch:mips': Split("""
    mips/assembler-mips.cc
    mips/builtins-mips.cc
    mips/code-stubs-mips.cc
    mips/codegen-mips.cc
    mips/constants-mips.cc
    mips/cpu-mips.cc
    mips/debug-mips.cc
    mips/deoptimizer-mips.cc
    mips/disasm-mips.cc
    mips/frames-mips.cc
    mips/full-codegen-mips.cc
    mips/ic-mips.cc
    mips/lithium-codegen-mips.cc
    mips/lithium-gap-resolver-mips.cc
    mips/lithium-mips.cc
    mips/macro-assembler-mips.cc
    mips/regexp-macro-assembler-mips.cc
    mips/stub-cache-mips.cc
    """),
  'arch:ia32': Split("""
    ia32/assembler-ia32.cc
    ia32/builtins-ia32.cc
    ia32/code-stubs-ia32.cc
    ia32/codegen-ia32.cc
    ia32/cpu-ia32.cc
    ia32/debug-ia32.cc
    ia32/deoptimizer-ia32.cc
    ia32/disasm-ia32.cc
    ia32/frames-ia32.cc
    ia32/full-codegen-ia32.cc
    ia32/ic-ia32.cc
    ia32/lithium-codegen-ia32.cc
    ia32/lithium-gap-resolver-ia32.cc
    ia32/lithium-ia32.cc
    ia32/macro-assembler-ia32.cc
    ia32/regexp-macro-assembler-ia32.cc
    ia32/stub-cache-ia32.cc
    """),
  'arch:x64': Split("""
    x64/assembler-x64.cc
    x64/builtins-x64.cc
    x64/code-stubs-x64.cc
    x64/codegen-x64.cc
    x64/cpu-x64.cc
    x64/debug-x64.cc
    x64/deoptimizer-x64.cc
    x64/disasm-x64.cc
    x64/frames-x64.cc
    x64/full-codegen-x64.cc
    x64/ic-x64.cc
    x64/lithium-codegen-x64.cc
    x64/lithium-gap-resolver-x64.cc
    x64/lithium-x64.cc
    x64/macro-assembler-x64.cc
    x64/regexp-macro-assembler-x64.cc
    x64/stub-cache-x64.cc
    """),
  'simulator:arm': ['arm/simulator-arm.cc'],
  'simulator:mips': ['mips/simulator-mips.cc'],
  'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'],
  'os:openbsd': ['platform-openbsd.cc', 'platform-posix.cc'],
  'os:linux':   ['platform-linux.cc', 'platform-posix.cc'],
  'os:android': ['platform-linux.cc', 'platform-posix.cc'],
  'os:macos':   ['platform-macos.cc', 'platform-posix.cc'],
  'os:solaris': ['platform-solaris.cc', 'platform-posix.cc'],
  'os:cygwin':  ['platform-cygwin.cc', 'platform-posix.cc'],
  'os:nullos':  ['platform-nullos.cc'],
  'os:win32':   ['platform-win32.cc', 'win32-math.cc'],
  'mode:release': [],
  'mode:debug': [
    'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc'
  ]
}


PREPARSER_SOURCES = {
  'all': Split("""
    allocation.cc
    bignum.cc
    bignum-dtoa.cc
    cached-powers.cc
    conversions.cc
    diy-fp.cc
    dtoa.cc
    fast-dtoa.cc
    fixed-dtoa.cc
    preparse-data.cc
    preparser.cc
    preparser-api.cc
    scanner.cc
    strtod.cc
    token.cc
    unicode.cc
    utils.cc
    """),
  'os:win32': ['win32-math.cc']
}


D8_LIGHT_FILES = {
  'all': [
    'd8.cc'
  ]
}


D8_FULL_FILES = {
  'all': [
    'd8.cc', 'd8-debug.cc'
  ],
  'os:linux': [
    'd8-posix.cc'
  ],
  'os:macos': [
    'd8-posix.cc'
  ],
  'os:android': [
    'd8-posix.cc'
  ],
  'os:freebsd': [
    'd8-posix.cc'
  ],
  'os:openbsd': [
    'd8-posix.cc'
  ],
  'os:solaris': [
    'd8-posix.cc'
  ],
  'os:cygwin': [
    'd8-posix.cc'
  ],
  'os:win32': [
    'd8-windows.cc'
  ],
  'os:nullos': [
    'd8-windows.cc'   # Empty implementation at the moment.
  ],
  'console:readline': [
    'd8-readline.cc'
  ]
}


LIBRARY_FILES = '''
runtime.js
v8natives.js
array.js
string.js
uri.js
math.js
messages.js
apinatives.js
date.js
regexp.js
json.js
liveedit-debugger.js
mirror-debugger.js
debug-debugger.js
'''.split()


EXPERIMENTAL_LIBRARY_FILES = '''
proxy.js
collection.js
'''.split()


def Abort(message):
  print message
  sys.exit(1)


def ConfigureObjectFiles():
  env = Environment(tools=tools)
  env.Replace(**context.flags['v8'])
  context.ApplyEnvOverrides(env)
  env['BUILDERS']['JS2C'] = Builder(action=js2c.JS2C)
  env['BUILDERS']['Snapshot'] = Builder(action='$SOURCE $TARGET --logfile "$LOGFILE" --log-snapshot-positions')

  def BuildJS2CEnv(type):
    js2c_env = { 'TYPE': type, 'COMPRESSION': 'off' }
    if 'COMPRESS_STARTUP_DATA_BZ2' in env['CPPDEFINES']:
      js2c_env['COMPRESSION'] = 'bz2'
    return js2c_env

  # Build the standard platform-independent source files.
  source_files = context.GetRelevantSources(SOURCES)
  d8_js = env.JS2C('d8-js.cc', 'd8.js', **{'TYPE': 'D8', 'COMPRESSION': 'off'})
  d8_js_obj = context.ConfigureObject(env, d8_js, CPPPATH=['.'])
  if context.options['library'] == 'shared':
    d8_files = context.GetRelevantSources(D8_LIGHT_FILES)
    d8_objs = []
  else:
    d8_files = context.GetRelevantSources(D8_FULL_FILES)
    d8_objs = [d8_js_obj]
  d8_objs.append(context.ConfigureObject(d8_env, [d8_files]))

  # Combine the JavaScript library files into a single C++ file and
  # compile it.
  library_files = [s for s in LIBRARY_FILES]
  library_files.append('macros.py')
  libraries_src = env.JS2C(
    ['libraries.cc'], library_files, **BuildJS2CEnv('CORE'))
  libraries_obj = context.ConfigureObject(env, libraries_src, CPPPATH=['.'])

  # Combine the experimental JavaScript library files into a C++ file
  # and compile it.
  experimental_library_files = [ s for s in EXPERIMENTAL_LIBRARY_FILES ]
  experimental_library_files.append('macros.py')
  experimental_libraries_src = env.JS2C(['experimental-libraries.cc'],
                                        experimental_library_files,
                                        **BuildJS2CEnv('EXPERIMENTAL'))
  experimental_libraries_obj = context.ConfigureObject(env, experimental_libraries_src, CPPPATH=['.'])

  source_objs = context.ConfigureObject(env, source_files)
  non_snapshot_files = [source_objs]

  preparser_source_files = context.GetRelevantSources(PREPARSER_SOURCES)
  preparser_objs = context.ConfigureObject(env, preparser_source_files)

  # Create snapshot if necessary.  For cross compilation you should either
  # do without snapshots and take the performance hit or you should build a
  # host VM with the simulator=arm and snapshot=on options and then take the
  # resulting snapshot.cc file from obj/release and put it in the src
  # directory.  Then rebuild the VM with the cross compiler and specify
  # snapshot=nobuild on the scons command line.
  empty_snapshot_obj = context.ConfigureObject(env, 'snapshot-empty.cc')
  mksnapshot_env = env.Copy()
  mksnapshot_env.Replace(**context.flags['mksnapshot'])
  mksnapshot_src = 'mksnapshot.cc'
  mksnapshot = mksnapshot_env.Program('mksnapshot', [mksnapshot_src, libraries_obj, experimental_libraries_obj,  non_snapshot_files, empty_snapshot_obj], PDB='mksnapshot.exe.pdb')
  if context.use_snapshot:
    if context.build_snapshot:
      snapshot_cc = env.Snapshot('snapshot.cc', mksnapshot, LOGFILE=File('snapshot.log').abspath)
    else:
      snapshot_cc = 'snapshot.cc'
    snapshot_obj = context.ConfigureObject(env, snapshot_cc, CPPPATH=['.'])
  else:
    snapshot_obj = empty_snapshot_obj
  library_objs = [non_snapshot_files, libraries_obj, experimental_libraries_obj, snapshot_obj]
  return (library_objs, d8_objs, [mksnapshot], preparser_objs)


(library_objs, d8_objs, mksnapshot, preparser_objs) = ConfigureObjectFiles()
Return('library_objs d8_objs mksnapshot preparser_objs')