mkxp-z/meson.build

669 lines
21 KiB
Meson

project('mkxp-z', 'c', 'cpp', version: '2.4.2', meson_version: '>=1.3.0', default_options: ['cpp_std=c++14', 'buildtype=release'])
host_system = host_machine.system()
host_endian = host_machine.endian()
host_cpu_family = host_machine.cpu_family()
compilers = {'c': meson.get_compiler('c'), 'cpp': meson.get_compiler('cpp')}
is_clang = ['armclang', 'clang', 'emscripten', 'llvm'].contains(compilers['cpp'].get_id())
is_libretro = get_option('libretro')
is_emscripten = host_system == 'emscripten'
core_is_static = is_libretro and (is_emscripten or host_system == 'bare' or host_system == 'none')
is_vita = core_is_static and host_cpu_family == 'arm' and compilers['c'].has_header_symbol('sys/config.h', '__vita__')
is_devkitarm = core_is_static and host_cpu_family == 'arm' and not is_vita
is_devkitppc = core_is_static and host_cpu_family == 'ppc'
# Position-independent code is not supported on some platforms where we need to build a static library, e.g. https://github.com/vitasdk/vita-toolchain/issues/264
use_pic = not core_is_static
if not is_libretro and host_system == 'darwin'
error('This Meson project no longer supports macOS. Please use the Xcode project instead.')
endif
if is_libretro and (host_cpu_family == 'ppc' or host_cpu_family == 'ppc64') and not get_option('b_lto') and not get_option('ruby_lto')
# We get a bunch of "relocation truncated to fit" when linking if LTO isn't enabled in libretro builds due to the sizes of the files generated by wasm2c.
error('LTO is required when building for PowerPC architectures. Please pass either `-Db_lto=true` or `-Druby_lto=true` to Meson.')
endif
global_sources = [vcs_tag(command: ['git', 'rev-parse', '--short=7', 'HEAD'], fallback: 'unknown', input: 'src/git-hash.h.in', output: 'git-hash.h')]
global_dependencies = []
global_include_dirs = []
global_args = []
global_cpp_args = []
global_link_args = []
libretro_ruby_args = []
if is_libretro
global_cpp_args += '-fno-rtti'
endif
sizeof = {'void*': compilers['cpp'].sizeof('void*'),
'long': compilers['cpp'].sizeof('long')
}
win64 = (sizeof['void*'] != sizeof['long'])
global_args += '-DMKXPZ_BUILD_MESON'
global_args += '-DMKXPZ_VERSION="@0@"'.format(meson.project_version())
have_any_mutex = true
have_any_thread = true
have_std_mutex = true
have_pthread_mutex = true
have_std_thread = true
have_pthread_thread = true
if is_libretro
global_args += '-DMKXPZ_RETRO'
global_args += '-D_FILE_OFFSET_BITS=64'
else
global_args += '-DHAVE_NANOSLEEP'
endif
if core_is_static and not is_emscripten and get_option('b_lto')
global_args += '-ffat-lto-objects'
endif
if is_libretro and get_option('ruby_lto') and not get_option('b_lto')
libretro_ruby_args += '-flto'
libretro_ruby_args += '-ffat-lto-objects'
endif
if is_vita
global_args += '-mword-relocations'
endif
if is_devkitarm
global_args += '-march=armv6k'
global_args += '-mtune=mpcore'
endif
if core_is_static and host_cpu_family == 'arm'
global_args += '-mfloat-abi=hard'
endif
if is_emscripten
if get_option('emscripten_threaded')
global_args += '-pthread'
else
have_any_mutex = false
have_any_thread = false
endif
endif
if host_endian == 'big'
global_args += '-DMKXPZ_BIG_ENDIAN'
endif
if is_emscripten or core_is_static or not compilers['cpp'].compiles('struct E {}; int main() { throw E(); }', name: 'C++ exceptions support check')
global_cpp_args += '-fno-exceptions'
global_args += '-DMKXPZ_NO_EXCEPTIONS'
global_args += '-DBOOST_NO_EXCEPTIONS'
endif
if not compilers['cpp'].has_header_symbol('stdio.h', 'sprintf')
global_args += '-DMKXPZ_NO_SPRINTF'
endif
if not compilers['cpp'].has_header_symbol('stdio.h', 'snprintf')
global_args += '-DMKXPZ_NO_SNPRINTF'
endif
if not compilers['cpp'].has_header_symbol('stdio.h', 'vsprintf')
global_args += '-DMKXPZ_NO_VSPRINTF'
endif
if not compilers['cpp'].has_header_symbol('stdio.h', 'vsnprintf')
global_args += '-DMKXPZ_NO_VSNPRINTF'
endif
if not compilers['cpp'].has_header_symbol('cstdio', 'std::sprintf')
global_args += '-DMKXPZ_NO_STD_SPRINTF'
endif
if not compilers['cpp'].has_header_symbol('cstdio', 'std::snprintf')
global_args += '-DMKXPZ_NO_STD_SNPRINTF'
endif
if not compilers['cpp'].has_header_symbol('cstdio', 'std::vsprintf')
global_args += '-DMKXPZ_NO_STD_VSPRINTF'
endif
if not compilers['cpp'].has_header_symbol('cstdio', 'std::vsnprintf')
global_args += '-DMKXPZ_NO_STD_VSNPRINTF'
endif
if not compilers['cpp'].has_header_symbol('cmath', 'std::round')
global_args += '-DMKXPZ_NO_STD_ROUND'
endif
if not compilers['cpp'].has_header_symbol('cmath', 'std::lround')
global_args += '-DMKXPZ_NO_STD_LROUND'
endif
if not compilers['cpp'].has_header_symbol('cmath', 'std::copysign')
global_args += '-DMKXPZ_NO_STD_COPYSIGN'
endif
if not compilers['cpp'].has_header_symbol('cmath', 'std::cbrt')
global_args += '-DMKXPZ_NO_STD_CBRT'
endif
if not compilers['cpp'].has_header_symbol('cmath', 'std::log2')
global_args += '-DMKXPZ_NO_STD_LOG2'
endif
if not compilers['cpp'].has_header_symbol('string', 'std::to_string')
global_args += '-DMKXPZ_NO_STD_TO_STRING'
endif
if not compilers['cpp'].has_header_symbol('string', 'std::stoi')
global_args += '-DMKXPZ_NO_STD_STOI'
endif
if not compilers['cpp'].has_header_symbol('string', 'std::stol')
global_args += '-DMKXPZ_NO_STD_STOL'
endif
if not compilers['cpp'].has_header_symbol('string', 'std::stoll')
global_args += '-DMKXPZ_NO_STD_STOLL'
endif
if not compilers['cpp'].has_header_symbol('string', 'std::stoul')
global_args += '-DMKXPZ_NO_STD_STOUL'
endif
if not compilers['cpp'].has_header_symbol('string', 'std::stoull')
global_args += '-DMKXPZ_NO_STD_STOULL'
endif
if not compilers['cpp'].has_header_symbol('string', 'std::stof')
global_args += '-DMKXPZ_NO_STD_STOF'
endif
if not compilers['cpp'].has_header_symbol('string', 'std::stod')
global_args += '-DMKXPZ_NO_STD_STOD'
endif
if not compilers['cpp'].has_header_symbol('string', 'std::stold')
global_args += '-DMKXPZ_NO_STD_STOLD'
endif
if not compilers['cpp'].has_header_symbol('mutex', 'std::mutex')
have_std_mutex = false
global_args += '-DMKXPZ_NO_STD_MUTEX'
if not compilers['cpp'].has_header_symbol('condition_variable', 'std::condition_variable_any')
global_args += '-DMKXPZ_NO_STD_CONDITION_VARIABLE_ANY'
endif
endif
if not compilers['cpp'].has_header_symbol('mutex', 'std::recursive_mutex')
global_args += '-DMKXPZ_NO_STD_RECURSIVE_MUTEX'
endif
if not compilers['cpp'].links('''
#include <atomic>
int main(void) {
std::atomic<uint64_t> atom(1);
atom.store(2, std::memory_order_seq_cst);
return atom.load(std::memory_order_seq_cst) != 2 || atom.fetch_add(3, std::memory_order_seq_cst) != 2 || atom.load(std::memory_order_seq_cst) != 5;
}
''', name: 'check for broken std::atomic<uint64_t>')
global_args += '-DMKXPZ_NO_STD_ATOMIC_UINT64_T'
endif
if not compilers['cpp'].has_header_symbol('thread', 'std::thread')
have_std_thread = false
global_args += '-DMKXPZ_NO_STD_THREAD'
endif
if not compilers['cpp'].has_header_symbol('thread', 'std::this_thread::yield')
global_args += '-DMKXPZ_NO_STD_THIS_THREAD_YIELD'
endif
if not compilers['cpp'].has_header_symbol('thread', 'std::this_thread::sleep_for')
global_args += '-DMKXPZ_NO_STD_THIS_THREAD_SLEEP_FOR'
endif
if not compilers['cpp'].has_header_symbol('unistd.h', 'usleep')
global_args += '-DMKXPZ_NO_USLEEP'
endif
if not compilers['cpp'].has_header_symbol('time.h', 'nanosleep')
global_args += '-DMKXPZ_NO_NANOSLEEP'
endif
if not compilers['cpp'].has_header('pthread.h') or not compilers['cpp'].links('''
#include <pthread.h>
int main(void) {
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_cond_signal(&cond);
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
int result = pthread_self() != pthread_self();
pthread_mutex_unlock(&mutex);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return result;
}
''', name: 'pthread.h mutex sanity check')
if is_devkitarm
global_args += '-DMKXPZ_DEVKITARM_NO_PTHREAD_H_MUTEX'
else
have_pthread_mutex = false
global_args += '-DMKXPZ_NO_PTHREAD_H_MUTEX'
endif
global_args += '-DMKXPZ_NO_SEMAPHORE_H'
elif not compilers['cpp'].has_header('semaphore.h') or not compilers['cpp'].links('''
#include <semaphore.h>
int main(void) {
sem_t sem;
sem_init(&sem, 0, 0);
sem_post(&sem);
sem_wait(&sem);
sem_destroy(&sem);
return 0;
}
''', name: 'semaphore.h sanity check')
global_args += '-DMKXPZ_NO_SEMAPHORE_H'
endif
if not compilers['cpp'].has_header('pthread.h') or not compilers['cpp'].links('''
#include <pthread.h>
void *func(void *arg) {
return NULL;
}
int main(void) {
pthread_t thread;
void *ret;
pthread_create(&thread, NULL, &func, NULL);
pthread_join(thread, &ret);
return ret != NULL;
}
''', name: 'pthread.h thread sanity check')
if is_devkitarm
global_args += '-DMKXPZ_DEVKITARM_NO_PTHREAD_H_THREAD'
else
have_pthread_thread = false
global_args += '-DMKXPZ_NO_PTHREAD_H_THREAD'
endif
endif
if compilers['cpp'].has_header_symbol('stdlib.h', 'posix_memalign') and compilers['cpp'].links('''
#include <stdlib.h>
int main(void) {
void *mem;
return posix_memalign(&mem, 16, 4);
}
''', name: 'posix_memalign sanity check')
global_args += '-DMKXPZ_HAVE_POSIX_MEMALIGN'
elif compilers['cpp'].has_header_symbol('malloc.h', '_aligned_malloc') and compilers['cpp'].links('''
#include <malloc.h>
int main(void) {
void *mem = _aligned_malloc(4, 16);
_aligned_free(mem);
return mem == NULL;
}
''', name: '_aligned_malloc sanity check')
global_args += '-DMKXPZ_HAVE_ALIGNED_MALLOC'
elif compilers['cpp'].has_header_symbol('stdlib.h', 'aligned_alloc') and compilers['cpp'].links('''
#include <stdlib.h>
int main(void) {
return aligned_alloc(16, 4) == NULL;
}
''', name: 'aligned_alloc sanity check')
global_args += '-DMKXPZ_HAVE_ALIGNED_ALLOC'
endif
if compilers['cpp'].has_header('sys/stat.h') and (not compilers['cpp'].has_header_symbol('sys/stat.h', 'lstat') or not compilers['cpp'].links('''
#include <sys/stat.h>
int main(void) {
struct stat stat;
lstat("/", &stat);
return 0;
}
''', name: 'lstat sanity check'))
global_args += '-DMKXPZ_NO_LSTAT'
endif
# Enable integer-only mode in FLAC when building with Vita SDK. Otherwise, we get an internal compiler error in FLAC__window_triangle:
#
# ../subprojects/flac/src/libFLAC/window.c: In function 'FLAC__window_triangle':
# ../subprojects/flac/src/libFLAC/window.c:197:1: error: unrecognizable insn:
# 197 | }
# | ^
# (insn 191 190 192 21 (set (reg:V4SF 443)
# (mult:V4SF (reg:V4SF 443)
# (reg:V4SF 444))) "../subprojects/flac/src/libFLAC/window.c":189:43 -1
# (nil))
# during RTL pass: vregs
# ../subprojects/flac/src/libFLAC/window.c:197:1: internal compiler error: in extract_insn, at recog.c:2294
# Please submit a full bug report,
# with preprocessed source if appropriate.
# See <https://gcc.gnu.org/bugs/> for instructions.
if is_vita
global_args += '-DFLAC__INTEGER_ONLY_LIBRARY'
endif
if is_devkitarm
global_args += '-D__DEVKITPRO__'
global_args += '-D__DEVKITARM__'
endif
if is_devkitppc
global_args += '-D__DEVKITPRO__'
global_args += '-D__DEVKITPPC__'
endif
if is_libretro
# We need to statically link the C++ standard library (libstdc++/libc++), the compiler runtime library (libgcc/compiler-rt) and libpthread in MSYS2 libretro builds for Windows because those are not part of the operating system
if host_system == 'windows'
global_link_args += ['-static-libgcc', '-static-libstdc++', '-Wl,-Bstatic', '-lgcc', '-lstdc++', '-lpthread', '-Wl,-Bdynamic']
endif
# Android doesn't have a built-in C++ standard library, so we need to statically link against the C++ standard library
if host_system == 'android'
compilers['cpp'].has_link_argument('-static-libstdc++', required: true)
global_link_args += '-static-libstdc++'
endif
# If possible, put all functions and data objects in their own sections to allow the linker to remove dead code
if compilers['c'].has_argument('-ffunction-sections')
global_args += '-ffunction-sections'
endif
if compilers['c'].has_argument('-fdata-sections')
global_args += '-fdata-sections'
endif
if not core_is_static and compilers['cpp'].has_link_argument('-Wl,--gc-sections')
global_link_args += '-Wl,--gc-sections'
endif
# If possible, stop the linker from reexporting the symbols from the static libraries we use (e.g. zlib)
if not core_is_static and compilers['cpp'].has_link_argument('-Wl,--version-script,' + meson.current_source_dir() / 'libretro/link.T') # Only works with GNU linker and LLVM linker
global_link_args += '-Wl,--version-script,' + meson.current_source_dir() / 'libretro/link.T'
endif
elif get_option('static_executable')
if host_system == 'windows'
# '-static-libgcc', '-static-libstdc++' are here to avoid needing to ship a separate libgcc_s_seh-1.dll on Windows; it still works without those flags if you have the dll.
global_link_args += ['-static-libgcc', '-static-libstdc++', '-Wl,-Bstatic', '-lgcc', '-lstdc++', '-lpthread', '-Wl,-Bdynamic']
else
global_link_args += ['-static-libgcc', '-static-libstdc++']
endif
global_args += '-DAL_LIBTYPE_STATIC'
endif
if not have_std_mutex and not have_pthread_mutex
have_any_mutex = false
endif
if not have_any_mutex or not have_std_thread and not have_pthread_thread
have_any_thread = false
endif
if not have_any_mutex
global_args += '-DMKXPZ_NO_THREADED_AUDIO'
endif
if not have_any_thread
global_args += '-DMKXPZ_NO_THREAD'
endif
# ====================
# Ext libs
# ====================
if not is_libretro
# STEAMWORKS
steamworks = false
steamworks_path = get_option('steamworks_path')
if steamworks_path != ''
libname = 'steam_api'
if host_system == 'linux'
if sizeof['void*'] == 4
bindir = 'linux32'
else
bindir = 'linux64'
endif
else
if win64 == true
bindir = 'win64'
libname += '64'
else
bindir = ''
endif
endif
steam_libpath = steamworks_path + '/redistributable_bin/' + bindir
steamlib = compilers['cpp'].find_library(libname, required: false, dirs: [steam_libpath])
if steamlib.found() == true
global_include_dirs += include_directories('steamshim')
global_args += '-DMKXPZ_STEAM'
global_sources += 'steamshim/steamshim_child.c'
steamworks = true
endif
endif
# GLES
gfx_backend = get_option('gfx_backend')
if gfx_backend == 'gles'
# Needs to be manually set up for now
global_args += '-DGLES2_HEADER'
elif gfx_backend == 'gl'
global_dependencies += dependency('gl')
# boop
endif
endif
# ====================
# Main source
# ====================
# Suppress warnings
global_cpp_args += ['-Wno-non-virtual-dtor', '-Wno-reorder']
global_args += ['-Wno-uninitialized', '-Wno-unknown-pragmas']
if is_clang
global_args += ['-Wno-undefined-var-template', '-Wno-delete-non-abstract-non-virtual-dtor']
else
global_args += ['-Wno-stringop-truncation']
endif
if host_system == 'windows'
if not is_clang
global_args += '-masm=intel'
endif
endif
if not is_libretro
# Decide whether or not to use MiniFFI
miniffi = get_option('use_miniffi')
if miniffi == true
miniffi = true
global_args += '-DMKXPZ_MINIFFI'
endif
# Defines
if get_option('workdir_current')
global_args += '-DWORKDIR_CURRENT'
endif
if get_option('cxx11_experimental') == true
global_args += '-DMKXPZ_EXP_FS'
endif
if get_option('force32') == true
global_args += '-m32'
endif
build_static = false
if get_option('static_executable') == true
build_static = true
endif
global_args += '-DMKXPZ_INIT_GL_LATER'
endif
subdir('tools')
subdir('src')
subdir(is_libretro ? 'binding-sandbox' : 'binding')
subdir('shader')
subdir('assets')
global_include_dirs += include_directories('src')
if is_libretro
global_include_dirs += include_directories('binding-sandbox')
endif
global_include_dirs += include_directories('binding')
if is_libretro
libretro_stage1_path = get_option('libretro_stage1_path')
libretro_ruby_sources = []
foreach i : range(8)
libretro_ruby_sources += libretro_stage1_path / 'ruby/mkxp-sandbox-ruby_@0@.c'.format(i)
endforeach
global_dependencies += declare_dependency(
link_with: static_library(
'ruby',
c_args: global_args + libretro_ruby_args + [
'-frounding-math',
'-Wno-unused-function',
'-Wno-unused-value',
'-Wno-unused-variable',
'-Wno-unused-but-set-variable',
] + (is_clang ? [] : ['-fsignaling-nans']),
include_directories: [
include_directories('binding-sandbox'),
include_directories(libretro_stage1_path),
include_directories(libretro_stage1_path / 'sandbox-bindgen'),
include_directories(libretro_stage1_path / 'ruby'),
],
sources: libretro_ruby_sources,
gnu_symbol_visibility: 'hidden',
install: false,
pic: use_pic,
),
include_directories: [
include_directories(libretro_stage1_path),
include_directories(libretro_stage1_path / 'sandbox-bindgen'),
include_directories(libretro_stage1_path / 'ruby'),
],
)
global_sources += libretro_stage1_path / 'sandbox-bindgen/mkxp-sandbox-bindgen.cpp'
global_sources += custom_target(
'dist-zip',
input: libretro_stage1_path / 'dist.zip',
output: 'dist.zip.cpp',
command: [
embedtool,
'@INPUT@',
'@OUTPUT@',
'dist_zip',
],
)
if core_is_static
global_dependencies_processed = []
foreach dep : global_dependencies
global_dependencies_processed += dep.as_link_whole()
endforeach
else
global_dependencies_processed = global_dependencies
endif
libretro = build_target(
meson.project_name() + '_libretro',
name_prefix: '',
target_type: core_is_static ? 'static_library' : 'shared_library',
dependencies: global_dependencies_processed,
c_args: global_args,
cpp_args: global_args + global_cpp_args,
link_args: global_link_args,
pic: use_pic,
gnu_symbol_visibility: 'hidden',
install: true, # Prevents Meson from creating thin archives; see https://github.com/mesonbuild/meson/issues/9479
include_directories: global_include_dirs,
sources: global_sources,
)
else
rpath = ''
if host_system == 'windows'
windows_resource_directory = '../' + get_option('windows_resource_directory')
subdir('windows')
global_sources += windows_resources
global_include_dirs += include_directories('windows')
else
subdir('linux')
rpath = '$ORIGIN/lib'
if get_option('appimage') != true
if sizeof['long'] == 8 and get_option('force32') != true
rpath += '64'
else
rpath += '32'
endif
endif
endif
exe_name = meson.project_name()
if host_system == 'linux' and get_option('appimage') == false
exe_name += '.' + host_machine.cpu()
endif
if steamworks == true
exe_name = 'steam_' + exe_name
la = ''
if build_static == true
if host_system == 'windows'
la = '-static'
else
la = '-static-libgcc -static-libstdc++'
endif
endif
shim_args = [
'-DGAME_LAUNCH_NAME="' + exe_name + '"',
'-I' + steamworks_path + '/public'
]
if get_option('steam_appid') != ''
shim_args += '-DSTEAM_APPID=' + get_option('steam_appid')
endif
if get_option('steamshim_debug') == true
shim_args += '-DSTEAMSHIM_DEBUG'
shim_ws = 'console'
else
shim_ws = 'windows'
endif
executable(meson.project_name(),
sources: files('steamshim/steamshim_parent.cpp'),
dependencies: steamlib,
cpp_args: shim_args,
link_args: la.split(),
win_subsystem: shim_ws,
install: (host_system != 'windows'))
endif
executable(exe_name,
sources: global_sources,
dependencies: global_dependencies,
include_directories: global_include_dirs,
install_rpath: rpath,
link_args: global_link_args,
cpp_args: global_args + global_cpp_args,
objc_args: global_args,
objcpp_args: global_args + global_cpp_args,
win_subsystem: 'windows',
install: (host_system != 'windows')
)
endif