version_deps += custom_target('version information', command : [preprocess_command, '@INPUT@', '@OUTPUT@'], build_by_default : true, build_always_stale : true, input : 'version_auto.c.in', output : 'version_auto.c', ) if host_machine.system() == 'windows' winmod = import('windows') rcpath = join_paths(meson.current_build_dir(), 'taisei.rc') icons_dir = join_paths(meson.source_root(), 'misc', 'icons') icon_main = join_paths(icons_dir, 'taisei.ico') icon_replay = join_paths(icons_dir, 'taisei-replay.ico') manifest = join_paths(meson.current_source_dir(), 'taisei.manifest') rcdefs = [ '-DICON_MAIN=@0@'.format(icon_main), '-DICON_REPLAY=@0@'.format(icon_replay), '-DMANIFEST=@0@'.format(manifest), ] if is_debug_build rcdefs += ['-DBUILDTYPE_DEFINE=#define DEBUG_BUILD'] else rcdefs += ['-DBUILDTYPE_DEFINE=#define RELEASE_BUILD'] endif # https://github.com/mesonbuild/meson/issues/4301 rc_target = custom_target('windows-resource', command : [preprocess_command, rcdefs, '@INPUT@', '@OUTPUT@'], build_always_stale : true, build_by_default : true, input : 'taisei.rc.in', output : 'taisei.rc', ) version_deps += winmod.compile_resources( rc_target, depend_files : files( 'taisei.manifest', icon_main, icon_replay, ) ) # msvcrt is dumb and only supports up to c89. # with this defined, alternative implementations from mingw for e.g. the # printf family of functions will be used, which conform to c11. config.set('__USE_MINGW_ANSI_STDIO', 1) endif taisei_src = files( 'aniplayer.c', 'boss.c', 'cli.c', 'color.c', 'color.c', 'common_tasks.c', 'config.c', 'credits.c', 'dialog.c', 'difficulty.c', 'dynarray.c', 'enemy.c', 'enemy_classes.c', 'entity.c', 'events.c', 'framerate.c', 'gamepad.c', 'global.c', 'hashtable.c', 'hirestime.c', 'item.c', 'list.c', 'log.c', 'move.c', 'player.c', 'plrmodes.c', 'portrait.c', 'progress.c', 'projectile.c', 'projectile_prototypes.c', 'random.c', 'ringbuf.c', 'stage.c', 'stagedraw.c', 'stageinfo.c', 'stageobjects.c', 'stagetext.c', 'stageutils.c', 'stats.c', 'taskmanager.c', 'thread.c', 'transition.c', 'version.c', 'video.c', 'video_postprocess.c', 'watchdog.c', ) taisei_main_src = files('main.c') if is_developer_build taisei_src += files( 'camcontrol.c' ) endif if host_machine.system() == 'nx' taisei_src += files( 'arch_switch.c', ) endif subdir('audio') subdir('coroutine') subdir('cutscenes') subdir('dialog') subdir('eventloop') subdir('filewatch') subdir('lasers') subdir('memory') subdir('menu') subdir('pixmap') subdir('plrmodes') subdir('renderer') subdir('replay') subdir('resource') subdir('rwops') subdir('stages') subdir('util') subdir('vfs') taisei_src += [ audio_src, coroutine_src, cutscenes_src, dialog_src, eventloop_src, filewatch_src, lasers_src, memory_src, menu_src, pixmap_src, plrmodes_src, renderer_src, replay_src, resource_src, rwops_src, util_src, vfs_src, ] taisei_deps += [ audio_deps, renderer_deps, util_deps, ] if stages_live_reload taisei_src += files('dynstage.c') # We want this to build fast libstages_opts = ['b_lto=false'] if get_option('optimization') != '0' # Don't force a higher optimization level if we're building the project # without optimizations libstages_opts += ['optimization=g'] endif taisei_stages = shared_module('taisei-stages', stages_src, version_deps, dependencies : taisei_deps, c_args : taisei_c_args, c_pch : 'pch/taisei_pch.h', build_by_default : true, gnu_symbol_visibility : 'hidden', override_options : libstages_opts, ) taisei_deps += cc.find_library('dl', required : false) taisei_stages_compile_command = [ find_program('meson'), 'compile', '-C', meson.project_build_root(), '-v', taisei_stages.name(), ] r = run_command(format_array_command, taisei_stages_compile_command, check : true) config.set_quoted('TAISEI_BUILDCONF_DYNSTAGE_LIB', taisei_stages.full_path()) config.set_quoted('TAISEI_BUILDCONF_DYNSTAGE_SRCROOT', stages_srcdir) config.set('TAISEI_BUILDCONF_DYNSTAGE_REBUILD_CMD', r.stdout().strip()) else taisei_src += files('dynstage_stub.c') taisei_src += stages_src endif configure_file(configuration : config, output : 'build_config.h') taisei_basename = (macos_app_bundle ? 'Taisei' : 'taisei') have_libtaisei = false if host_machine.system() == 'emscripten' if get_option('b_staticpic') warning('b_staticpic is not compatible with the LLVM WebAssembly backend') endif # Asyncify instrumentation is very overzealous by default. # This crazy list is not exhaustive, but still helps us reduce code size quite a bit. # Link with -s ASYNCIFY_ADVISE to see what gets instrumented. asyncify_ignore = [ '*printf', 'AlphaApplyFilter', 'ApplyInverseTransforms', 'Bezier_*', 'DecodeImageData', 'DoUVTransform', 'EmitFancyRGB', 'EmitRescaledAlphaRGB', 'EmitRescaledRGB', 'EmitSampledRGB', 'Emscripten_*', 'FT_*', 'FlushRenderCommands', 'ReconstructRow', 'SDL_*', 'T1_*', 'TT_*', 'VP8*', 'VP8ExitCritical', 'WebP*', 'ZSTD_*', '__*', '__ftello_unlocked', '__fwritex', '__shgetc', '__toread', '__vfprintf_internal', '_dynarray_*', '_ht_*', '_taisei_log*', '_text_draw', 'af_*', 'afm_*', 'apply_kerning', 'astream_*', 'basist*', 'camera3d_*', 'cf2_*', 'cff_*', 'deflate*', 'fbmgr_*', 'fclose', 'fread', 'ft_*', 'gamepad_*', 'get_glyph', 'gl33_*', 'glcommon_*', 'gles30_*', 'hash_bucket', 'ht_*', 'inflate*', 'log_*', 'log_internal', 'op_get_next_page', 'op_seek_helper', 'pfr_*', 'pixmap_*', 'png_*', 'printf_core', 'px_*', 'qsort', 'sfnt_*', 'sift', 'stdio_*', 'strtox', 't1_*', 't42_*', 'tt_*', 'vfs_decref', 'wrapper_cmp', ] em_debug = is_debug_build em_link_outputs = [] em_link_output_suffixes = ['js', 'wasm'] # first element is significant em_data_dir = config.get_unquoted('TAISEI_BUILDCONF_DATA_PATH') em_common_args = [] em_link_args = [ '-O@0@'.format(get_option('optimization')), '-s', 'ALLOW_MEMORY_GROWTH=1', '-s', 'ASYNCIFY_REMOVE=@0@'.format(','.join(asyncify_ignore)), '-s', 'AUTO_ARCHIVE_INDEXES=0', '-s', 'AUTO_JS_LIBRARIES=0', '-s', 'AUTO_NATIVE_LIBRARIES=0', '-s', 'DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=["$autoResumeAudioContext"]', '-s', 'DYNAMIC_EXECUTION=0', '-s', 'ENVIRONMENT=web', '-s', 'EXIT_RUNTIME=0', '-s', 'EXPORT_NAME=createTaisei', '-s', 'EXPORTED_FUNCTIONS=["_main", "_vfs_sync_callback"]', '-s', 'EXPORTED_RUNTIME_METHODS=["ccall","callMain","FS","ENV"]', '-s', 'FETCH_SUPPORT_INDEXEDDB=0', '-s', 'FETCH', '-s', 'FILESYSTEM=1', '-s', 'FORCE_FILESYSTEM=1', '-s', 'GL_ENABLE_GET_PROC_ADDRESS', '-s', 'GL_POOL_TEMP_BUFFERS=0', '-s', 'GL_PREINITIALIZED_CONTEXT=1', '-s', 'GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS=0', '-s', 'GL_SUPPORT_SIMPLE_ENABLE_EXTENSIONS=0', '-s', 'IGNORE_MISSING_MAIN=0', '-s', 'INITIAL_MEMORY=268435456', '-s', 'INVOKE_RUN=0', '-s', 'LLD_REPORT_UNDEFINED', '-s', 'MAX_WEBGL_VERSION=2', '-s', 'MIN_WEBGL_VERSION=2', '-s', 'MODULARIZE=1', '-s', 'STACK_SIZE=1MB', '-s', 'SUPPORT_BIG_ENDIAN=1', '-s', 'WASM=1', '-lGL', '-legl.js', '-lidbfs.js', '-lwebgl.js', '-lhtml5', # NOTE: SDL dependency; should be fixed there ] em_link_args += subproject('koishi').get_variable('koishi_external_link_args') if em_debug em_link_output_suffixes += ['wasm.map'] em_link_args += [ '--profiling', '-g3', '-gsource-map', '--source-map-base', meson.get_external_property('source_map_base', 'http://0.0.0.0:6931/'), '-s', 'ASSERTIONS=2', '-s', 'GL_ASSERTIONS=1', '-s', 'GL_DEBUG=1', '-s', 'GL_TRACK_ERRORS=1', ] else em_link_args += [ '-g0', '-s', 'ASSERTIONS=0', '-s', 'GL_TRACK_ERRORS=0', ] if get_option('optimization') != '0' em_link_args += ['--closure', '1'] endif endif foreach suffix : em_link_output_suffixes em_link_outputs += ['@0@.@1@'.format(taisei_basename, suffix)] endforeach meson_link_whole_is_broken = meson.version().version_compare('>1.1.0') if meson_link_whole_is_broken warning('Installing private static library to work around a Meson bug: https://github.com/mesonbuild/meson/issues/12638') endif libtaisei = static_library(taisei_basename, taisei_src, taisei_main_src, version_deps, dependencies : taisei_deps, c_pch : 'pch/taisei_pch.h', c_args : [em_common_args, taisei_c_args], install : meson_link_whole_is_broken, install_dir : '.', install_tag : 'trash', # Explicitly give it a predictable name, in case we have to remove it via install script name_prefix : 'lib', name_suffix : 'a', ) if meson_link_whole_is_broken meson.add_install_script( post_install_remove_command, 'lib' + libtaisei.name() + '.a', install_tag : 'trash', ) endif taisei = static_library(taisei_basename + '-full', link_whole : libtaisei, ) taisei_js = custom_target(em_link_outputs[0], command : [ meson.get_compiler('cpp').cmd_array(), taisei, '--pre-js', em_preamble, '--post-js', em_postamble, get_option('c_args'), get_option('c_link_args'), em_common_args, em_link_args, '-o', '@OUTPUT0@', ], build_by_default : true, output : em_link_outputs, install : true, install_dir : bindir, install_tag : 'runtime', console : true, ) bindist_deps += taisei_js elif host_machine.system() == 'nx' taisei_elf_name = '@0@.elf'.format(taisei_basename) taisei_elf = executable(taisei_elf_name, taisei_src, taisei_main_src, version_deps, dependencies : taisei_deps, c_args : taisei_c_args, c_pch : 'pch/taisei_pch.h', install : is_debug_build, install_dir : bindir, override_options: ['strip=false'], ) bindist_deps += taisei_elf taisei_nacp_name = '@0@.nacp'.format(taisei_basename) taisei_nacp = custom_target(taisei_nacp_name, command : [ find_program('nacptool'), '--create', nx_app_title, nx_app_author, taisei_version_string, '@OUTPUT@', ], build_by_default : true, install : false, output : taisei_nacp_name, ) taisei_nro_name = '@0@.nro'.format(taisei_basename) taisei_nro = custom_target(taisei_nro_name, command : [ find_program('elf2nro'), taisei_elf, '@OUTPUT@', '--nacp=@0@'.format(taisei_nacp.full_path()), # if we could pass the path in a standalone argument, we could have meson generate an implicit dependency here... '--icon=@0@'.format(nx_icon_path), ], build_by_default : true, depends : [taisei_nacp], install : true, install_dir : bindir, install_tag : 'runtime', output : taisei_nro_name, ) bindist_deps += taisei_nro else libtaisei = static_library(taisei_basename, taisei_src, version_deps, dependencies : taisei_deps, c_args : taisei_c_args, c_pch : 'pch/taisei_pch.h', install : false, ) libtaisei_dep = declare_dependency( compile_args : taisei_c_args, dependencies : taisei_deps, include_directories : include_directories('.'), link_with : libtaisei, ) taisei = executable(taisei_basename, taisei_main_src, dependencies : stages_live_reload ? libtaisei_dep.as_link_whole() : libtaisei_dep, win_subsystem : get_option('win_console') ? 'console' : 'windows', install : true, install_dir : bindir, export_dynamic : stages_live_reload, ) bindist_deps += taisei have_libtaisei = true endif