project('cell', ['c', 'cpp'],
  version: '0.9.3',
  meson_version: '>=1.4',
  default_options : [ 'cpp_std=c++11', 'default_library=static'])

libtype = get_option('default_library') 

link = []
src = []

add_project_arguments(
  '-Wno-incompatible-pointer-types',
  '-Wno-missing-braces',
  '-Wno-strict-prototypes',
  '-Wno-unused-function',
  '-Wno-int-conversion',
  language: 'c'
)
add_project_arguments('-Wno-narrowing', language: 'cpp')

if get_option('validate_gc')
  add_project_arguments('-DVALIDATE_GC', language: 'c')
endif

if get_option('force_gc')
  add_project_arguments('-DFORCE_GC_AT_MALLOC', language: 'c')
endif


deps = []

if host_machine.system() == 'darwin'
  add_project_arguments('-x', 'objective-c', language: 'c')
  fworks = [
    'CoreFoundation',
    'CFNetwork',
  ]
  foreach fkit : fworks
    deps += dependency('appleframeworks', modules: fkit)
  endforeach
  # 32MB stack for deep native recursion (CPS patterns without TCO)
  link += ['-Wl,-stack_size,0x2000000']
endif

if host_machine.system() == 'playdate'
  add_project_arguments('-DTARGET_PLAYDATE', language: 'c')
endif

link_args = link
sources = []
src += [        # core
  'monocypher.c',
  'cell.c',
  'suite.c',
  'wildmatch.c',
  'qjs_actor.c',
  'miniz.c',
  'runtime.c',
  'mach.c',
  'libregexp.c', 'libunicode.c', 'cutils.c', 'dtoa.c'
]

src += ['scheduler.c']
src += ['qbe_helpers.c']
src += ['qbe_backend.c']

scripts = [
  'debug/js.c',
  'qop.c',
  'wildstar.c',
  'fit.c',
  'crypto.c',
  'internal/kim.c',
  'internal/time.c',
  'debug/debug.c',
  'internal/os.c',
  'internal/fd.c',
  'net/http.c',
  'net/enet.c',
  'wildstar.c',
  'archive/miniz.c',
  'source/cJSON.c'
]

foreach file: scripts
  sources += files(file)
endforeach

srceng = 'source'
includes = [srceng, 'internal', 'debug', 'net', 'archive', 'src/qbe']

foreach file : src
  full_path = join_paths(srceng, file)
  sources += files(full_path)
endforeach

# QBE compiler sources (all except main.c)
# Built as a separate static library to avoid -x objective-c on macOS
# (QBE uses 'Class' as a struct name, which conflicts with ObjC)
qbe_src = [
  'src/qbe/util.c',
  'src/qbe/parse.c',
  'src/qbe/abi.c',
  'src/qbe/cfg.c',
  'src/qbe/mem.c',
  'src/qbe/ssa.c',
  'src/qbe/alias.c',
  'src/qbe/load.c',
  'src/qbe/copy.c',
  'src/qbe/fold.c',
  'src/qbe/gvn.c',
  'src/qbe/gcm.c',
  'src/qbe/simpl.c',
  'src/qbe/ifopt.c',
  'src/qbe/live.c',
  'src/qbe/spill.c',
  'src/qbe/rega.c',
  'src/qbe/emit.c',
  'src/qbe/amd64/targ.c',
  'src/qbe/amd64/sysv.c',
  'src/qbe/amd64/isel.c',
  'src/qbe/amd64/emit.c',
  'src/qbe/amd64/winabi.c',
  'src/qbe/arm64/targ.c',
  'src/qbe/arm64/abi.c',
  'src/qbe/arm64/isel.c',
  'src/qbe/arm64/emit.c',
  'src/qbe/rv64/targ.c',
  'src/qbe/rv64/abi.c',
  'src/qbe/rv64/isel.c',
  'src/qbe/rv64/emit.c',
]

qbe_files = []
foreach file : qbe_src
  qbe_files += files(file)
endforeach

includers = []
foreach inc : includes
  includers += include_directories(inc)
endforeach

qbe_c_args = ['-x', 'c']
qbe_lib = static_library('qbe',
  qbe_files,
  include_directories: includers,
  c_args: qbe_c_args,
)

if host_machine.system() == 'windows'
  exe_ext = '.exe'
  link += '-Wl,--export-all-symbols'
else
  exe_ext = ''
  link += '-Wl,-export_dynamic'
endif

cell_so = shared_library(
  'cell_runtime',
  sources,
  include_directories: includers,
  dependencies: deps,
  link_whole: qbe_lib,
  install : true,
)

# Determine RPATH based on OS
# MacOS uses @loader_path, Linux uses $ORIGIN
# We include both the current directory (for build) and ../lib (for install)
rpath_dirs = []
if host_machine.system() == 'darwin'
  rpath_dirs += ['@loader_path', '@loader_path/../lib']
elif host_machine.system() == 'linux'
  rpath_dirs += ['$ORIGIN', '$ORIGIN/../lib']
endif

# Create main executable linked against the cell library
cell_exe = executable('cell',
  'source/main.c',
  dependencies: deps,
  include_directories: includers,
  link_with: cell_so,
  link_args: link,
  build_rpath: ':'.join(rpath_dirs),
  install: true
)

# Install headers for building dynamic libraries using Cell
install_headers('source/cell.h')
install_headers('source/quickjs.h')
install_headers('source/wota.h')
