mirror of
https://github.com/Relintai/godot-mono-builds.git
synced 2024-11-12 10:25:10 +01:00
Add build scripts for WASM, AOT cross-compilers, BCL and desktop
This commit is contained in:
parent
9efec19e6b
commit
09fbbb7d61
99
README.md
99
README.md
@ -1,26 +1,101 @@
|
||||
# Mono build scripts for Godot
|
||||
This repository contains scripts for building the Mono runtime to use with Godot Engine
|
||||
|
||||
## Android instructions
|
||||
## Command-line options
|
||||
|
||||
Run `python build_mono_android.py --help` for the full list of command line options.
|
||||
You may need to tweak some of those if the default values do not fit your needs.
|
||||
**Requires Python 3.7 or higher**
|
||||
|
||||
Example:
|
||||
These scripts are based on the Mono [sdks](https://github.com/mono/mono/tree/master/sdks) makefiles, with some changes to work well with Godot. Some platforms or targets depend on files from the `sdks` directory in the Mono source repository. This directory may be missing from tarballs. If that's the case, cloning the git repository may be needed. [This table](https://www.mono-project.com/docs/about-mono/versioning/#mono-source-versioning) can be used to determine the branch for a specific version of Mono.
|
||||
|
||||
Run `python SCRIPT.py --help` for the full list of command line options.
|
||||
|
||||
By default, the scripts will install the resulting files to `$HOME/mono-installs`.
|
||||
A custom output directory can be specified with the `--install-dir` option.
|
||||
|
||||
When cross-compiling to Windows, `--mxe-prefix` must be specified. For example, with the `mingw-w64` package installed on Ubuntu, one can pass `--mxe-prefix=/usr`.
|
||||
|
||||
A path to the Mono source tree must be provided with the `--mono-sources` option or with the `MONO_SOURCE_ROOT` environment variable:
|
||||
|
||||
```bash
|
||||
# These are the default values. You can omit them if they apply to your system
|
||||
export MONO_SOURCE_ROOT=$HOME/git/mono
|
||||
```
|
||||
|
||||
### Notes
|
||||
- Python 3.7 or higher is required.
|
||||
- Cross-compiling for macOS via osxcross is not yet supported.
|
||||
- Building on Windows is not supported. It's possible to use Cygwin or WSL (Windows Subsystem for Linux) but this hasn't been tested.
|
||||
|
||||
## Desktop
|
||||
|
||||
```bash
|
||||
# Build the runtimes for 32-bit and 64-bit Linux.
|
||||
./desktop.py linux configure --target=i686 --target=x86_64
|
||||
./desktop.py linux make --target=i686 --target=x86_64
|
||||
|
||||
# Build the runtimes for 32-bit and 64-bit Windows.
|
||||
./desktop.py windows configure --target=i686 --target=x86_64 --mxe-prefix=/usr
|
||||
./desktop.py windows make --target=i686 --target=x86_64 --mxe-prefix=/usr
|
||||
|
||||
# Build the runtime for 64-bit macOS.
|
||||
./desktop.py osx configure --target=x86_64
|
||||
./desktop.py osx make --target=x86_64
|
||||
```
|
||||
|
||||
_AOT cross-compilers for desktop platforms cannot be built with this script yet._
|
||||
|
||||
## Android
|
||||
|
||||
Some patches may need to be applied to the Mono sources before building for Android. This can be done by running `./patch_mono.py`.
|
||||
|
||||
```bash
|
||||
# These are the default values. This step can be omitted if SDK and NDK root are in this location.
|
||||
export ANDROID_SDK_ROOT=$HOME/Android/Sdk
|
||||
export ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk-bundle
|
||||
|
||||
# The mono sources may be in a different location on your system
|
||||
export MONO_SOURCE_ROOT=$HOME/git/mono
|
||||
# Build the runtime for all supported Android ABIs.
|
||||
./android.py configure --target=all-runtime
|
||||
./android.py make --target=all-runtime
|
||||
|
||||
./build_mono_android.py configure --target=all
|
||||
./build_mono_android.py make --target=all
|
||||
# Build the AOT cross-compilers targeting all supported Android ABIs.
|
||||
./android.py configure --target=all-cross
|
||||
./android.py make --target=all-cross
|
||||
|
||||
# Build the AOT cross-compilers for Windows targeting all supported Android ABIs.
|
||||
./android.py configure --target=all-cross-win --mxe-prefix=/usr
|
||||
./android.py make --target=all-cross-win --mxe-prefix=/usr
|
||||
```
|
||||
|
||||
The option `--target=all` is a shortcut for `--target=armeabi-v7a --target=x86 --target=arm64-v8a --target=x86_64`.
|
||||
The option `--target=all-runtime` is a shortcut for `--target=armeabi-v7a --target=x86 --target=arm64-v8a --target=x86_64`. The equivalent applies for `all-cross` and `all-cross-win`.
|
||||
|
||||
By default, the script will install the resulting files to `$HOME/mono-installs`.
|
||||
You can specify a custom output directory with the `--install-dir` option.
|
||||
## WebAssembly
|
||||
|
||||
Just like with Godot, an active Emscripten SDK is needed for building the Mono WebAssembly runtime.
|
||||
|
||||
Some patches may need to be applied to the Emscripten SDK before building Mono. This can be done by running `./patch_emscripten.py`.
|
||||
|
||||
```bash
|
||||
# Build the runtime for WebAssembly.
|
||||
./wasm.py configure --target=runtime
|
||||
./wasm.py make --target=runtime
|
||||
```
|
||||
|
||||
_AOT cross-compilers for WebAssembly cannot be built with this script yet._
|
||||
|
||||
## Base Class library
|
||||
|
||||
```bash
|
||||
# Build the Desktop BCL.
|
||||
./bcl.py make --product=desktop
|
||||
|
||||
# Build the Android BCL.
|
||||
./bcl.py make --product=android
|
||||
|
||||
# Build the WebAssembly BCL.
|
||||
./bcl.py make --product=wasm
|
||||
```
|
||||
|
||||
## Reference Assemblies
|
||||
|
||||
```bash
|
||||
./reference_assemblies.py install
|
||||
```
|
||||
|
0
__init__.py
Normal file
0
__init__.py
Normal file
546
android.py
Executable file
546
android.py
Executable file
@ -0,0 +1,546 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
from os.path import join as path_join
|
||||
|
||||
from options import *
|
||||
from os_utils import *
|
||||
import runtime
|
||||
|
||||
|
||||
runtime_targets = ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64']
|
||||
cross_targets = ['cross-arm', 'cross-arm64', 'cross-x86', 'cross-x86_64']
|
||||
cross_mxe_targets = ['cross-arm-win', 'cross-arm64-win', 'cross-x86-win', 'cross-x86_64-win']
|
||||
|
||||
|
||||
def is_cross(target) -> bool:
|
||||
return target in cross_targets or is_cross_mxe(target)
|
||||
|
||||
|
||||
def is_cross_mxe(target) -> bool:
|
||||
return target in cross_mxe_targets
|
||||
|
||||
|
||||
def android_autodetect_cmake(opts: AndroidOpts) -> str:
|
||||
from distutils.version import LooseVersion
|
||||
from os import listdir
|
||||
|
||||
sdk_cmake_basedir = path_join(opts.android_sdk_root, 'cmake')
|
||||
versions = []
|
||||
|
||||
for entry in listdir(sdk_cmake_basedir):
|
||||
if os.path.isdir(path_join(sdk_cmake_basedir, entry)):
|
||||
try:
|
||||
version = LooseVersion(entry)
|
||||
versions += [version]
|
||||
except ValueError:
|
||||
continue # Not a version folder
|
||||
|
||||
if len(versions) == 0:
|
||||
raise BuildError('Cannot auto-detect Android CMake version')
|
||||
|
||||
lattest_version = str(sorted(versions)[-1])
|
||||
print('Auto-detected Android CMake version: ' + lattest_version)
|
||||
|
||||
return lattest_version
|
||||
|
||||
|
||||
def get_api_version_or_min(opts: AndroidOpts, target: str) -> str:
|
||||
min_versions = { 'arm64-v8a': '21', 'x86_64': '21' }
|
||||
if target in min_versions and int(opts.android_api_version) < int(min_versions[target]):
|
||||
print('WARNING: %s is less than minimum platform for %s; using %s' % (opts.android_api_version, target, min_versions[target]))
|
||||
return min_versions[target]
|
||||
return opts.android_api_version
|
||||
|
||||
|
||||
def get_android_cmake_version(opts: AndroidOpts) -> str:
|
||||
return opts.android_cmake_version if opts.android_cmake_version != 'autodetect' else android_autodetect_cmake(opts)
|
||||
|
||||
|
||||
class AndroidTargetTable:
|
||||
archs = {
|
||||
'armeabi-v7a': 'arm',
|
||||
'arm64-v8a': 'arm64',
|
||||
'x86': 'x86',
|
||||
'x86_64': 'x86_64'
|
||||
}
|
||||
|
||||
abi_names = {
|
||||
'armeabi-v7a': 'arm-linux-androideabi',
|
||||
'arm64-v8a': 'aarch64-linux-android',
|
||||
'x86': 'i686-linux-android',
|
||||
'x86_64': 'x86_64-linux-android'
|
||||
}
|
||||
|
||||
host_triples = {
|
||||
'armeabi-v7a': 'armv5-linux-androideabi',
|
||||
'arm64-v8a': 'aarch64-linux-android',
|
||||
'x86': 'i686-linux-android',
|
||||
'x86_64': 'x86_64-linux-android'
|
||||
}
|
||||
|
||||
|
||||
def setup_android_target_template(env: dict, opts: AndroidOpts, target: str):
|
||||
extra_target_envs = {
|
||||
'armeabi-v7a': {
|
||||
'android-armeabi-v7a_CFLAGS': ['-D__POSIX_VISIBLE=201002', '-DSK_RELEASE', '-DNDEBUG', '-UDEBUG', '-fpic', '-march=armv7-a', '-mtune=cortex-a8', '-mfpu=vfp', '-mfloat-abi=softfp'],
|
||||
'android-armeabi-v7a_CXXFLAGS': ['-D__POSIX_VISIBLE=201002', '-DSK_RELEASE', '-DNDEBUG', '-UDEBUG', '-fpic', '-march=armv7-a', '-mtune=cortex-a8', '-mfpu=vfp', '-mfloat-abi=softfp'],
|
||||
'android-armeabi-v7a_LDFLAGS': ['-Wl,--fix-cortex-a8']
|
||||
},
|
||||
'arm64-v8a': {
|
||||
'android-arm64-v8a_CFLAGS': ['-D__POSIX_VISIBLE=201002', '-DSK_RELEASE', '-DNDEBUG', '-UDEBUG', '-fpic', '-DL_cuserid=9', '-DANDROID64'],
|
||||
'android-arm64-v8a_CXXFLAGS': ['-D__POSIX_VISIBLE=201002', '-DSK_RELEASE', '-DNDEBUG', '-UDEBUG', '-fpic', '-DL_cuserid=9', '-DANDROID64']
|
||||
},
|
||||
'x86': {},
|
||||
'x86_64': {
|
||||
'android-x86_64_CFLAGS': ['-DL_cuserid=9'],
|
||||
'android-x86_64_CXXFLAGS': ['-DL_cuserid=9']
|
||||
}
|
||||
}
|
||||
|
||||
if target in extra_target_envs:
|
||||
env.update(extra_target_envs[target])
|
||||
|
||||
android_new_ndk = True
|
||||
|
||||
with open(path_join(opts.android_ndk_root, 'source.properties')) as file:
|
||||
for line in file:
|
||||
line = line.strip()
|
||||
if line.startswith('Pkg.Revision ') or line.startswith('Pkg.Revision='):
|
||||
pkg_revision = line.split('=')[1].strip()
|
||||
mayor = int(pkg_revision.split('.')[0])
|
||||
android_new_ndk = mayor >= 18
|
||||
break
|
||||
|
||||
arch = AndroidTargetTable.archs[target]
|
||||
abi_name = AndroidTargetTable.abi_names[target]
|
||||
host_triple = AndroidTargetTable.host_triples[target]
|
||||
api = env['ANDROID_API_VERSION']
|
||||
|
||||
toolchain_path = path_join(opts.android_toolchains_prefix, opts.toolchain_name_fmt % (target, api))
|
||||
|
||||
tools_path = path_join(toolchain_path, 'bin')
|
||||
name_fmt = abi_name + '-%s'
|
||||
|
||||
sdk_cmake_dir = path_join(opts.android_sdk_root, 'cmake', get_android_cmake_version(opts))
|
||||
if not os.path.isdir(sdk_cmake_dir):
|
||||
print('Android CMake directory \'%s\' not found' % sdk_cmake_dir)
|
||||
|
||||
AR = path_join(tools_path, name_fmt % 'ar')
|
||||
AS = path_join(tools_path, name_fmt % 'as')
|
||||
CC = path_join(tools_path, name_fmt % 'clang')
|
||||
CXX = path_join(tools_path, name_fmt % 'clang++')
|
||||
DLLTOOL = ''
|
||||
LD = path_join(tools_path, name_fmt % 'ld')
|
||||
OBJDUMP = path_join(tools_path, name_fmt % 'objdump')
|
||||
RANLIB = path_join(tools_path, name_fmt % 'ranlib')
|
||||
CMAKE = path_join(sdk_cmake_dir, 'bin', 'cmake')
|
||||
STRIP = path_join(tools_path, name_fmt % 'strip')
|
||||
|
||||
CPP = path_join(tools_path, name_fmt % 'cpp')
|
||||
if not os.path.isfile(CPP):
|
||||
CPP = path_join(tools_path, (name_fmt % 'clang'))
|
||||
CPP += ' -E'
|
||||
|
||||
CXXCPP = path_join(tools_path, name_fmt % 'cpp')
|
||||
if not os.path.isfile(CXXCPP):
|
||||
CXXCPP = path_join(tools_path, (name_fmt % 'clang++'))
|
||||
CXXCPP += ' -E'
|
||||
|
||||
ccache_path = os.environ.get('CCACHE', '')
|
||||
if ccache_path:
|
||||
CC = '%s %s' % (ccache_path, CC)
|
||||
CXX = '%s %s' % (ccache_path, CXX)
|
||||
CPP = '%s %s' % (ccache_path, CPP)
|
||||
CXXCPP = '%s %s' % (ccache_path, CXXCPP)
|
||||
|
||||
AC_VARS = [
|
||||
'mono_cv_uscore=yes',
|
||||
'ac_cv_func_sched_getaffinity=no',
|
||||
'ac_cv_func_sched_setaffinity=no',
|
||||
'ac_cv_func_shm_open_working_with_mmap=no'
|
||||
]
|
||||
|
||||
CFLAGS, CXXFLAGS, CPPFLAGS, CXXCPPFLAGS, LDFLAGS = [], [], [], [], []
|
||||
|
||||
# On Android we use 'getApplicationInfo().nativeLibraryDir' as the libdir where Mono will look for shared objects.
|
||||
# This path looks something like this: '/data/app-lib/{package_name-{num}}'. However, Mono does some relocation
|
||||
# and the actual path it will look at will be '/data/app-lib/{package_name}-{num}/../lib', which doesn't exist.
|
||||
# Cannot use '/data/data/{package_name}/lib' either, as '/data/data/{package_name}/lib/../lib' may result in
|
||||
# permission denied. Therefore we just override 'MONO_RELOC_LIBDIR' here to avoid the relocation.
|
||||
CPPFLAGS += ['-DMONO_RELOC_LIBDIR=\\\".\\\"']
|
||||
|
||||
CFLAGS += ['-fstack-protector']
|
||||
CFLAGS += ['-DMONODROID=1'] if opts.with_monodroid else []
|
||||
CFLAGS += ['-D__ANDROID_API__=' + api] if android_new_ndk else []
|
||||
CXXFLAGS += ['-fstack-protector']
|
||||
CXXFLAGS += ['-DMONODROID=1'] if opts.with_monodroid else []
|
||||
CXXFLAGS += ['-D__ANDROID_API__=' + api] if android_new_ndk else []
|
||||
|
||||
CPPFLAGS += ['-I%s/sysroot/usr/include' % toolchain_path]
|
||||
CXXCPPFLAGS += ['-I%s/sysroot/usr/include' % toolchain_path]
|
||||
|
||||
path_link = '%s/platforms/android-%s/arch-%s/usr/lib' % (opts.android_ndk_root, api, arch)
|
||||
|
||||
LDFLAGS += [
|
||||
'-z', 'now', '-z', 'relro', '-z', 'noexecstack',
|
||||
'-ldl', '-lm', '-llog', '-lc', '-lgcc',
|
||||
'-Wl,-rpath-link=%s,-dynamic-linker=/system/bin/linker' % path_link,
|
||||
'-L' + path_link
|
||||
]
|
||||
|
||||
# Fixes this error: DllImport unable to load library 'dlopen failed: empty/missing DT_HASH in "libmono-native.so" (built with --hash-style=gnu?)'.
|
||||
LDFLAGS += ['-Wl,--hash-style=both']
|
||||
|
||||
CONFIGURE_FLAGS = [
|
||||
'--disable-boehm',
|
||||
'--disable-executables',
|
||||
'--disable-iconv',
|
||||
'--disable-mcs-build',
|
||||
'--disable-nls',
|
||||
'--enable-dynamic-btls',
|
||||
'--enable-maintainer-mode',
|
||||
'--enable-minimal=ssa,portability,attach,verifier,full_messages,sgen_remset'
|
||||
',sgen_marksweep_par,sgen_marksweep_fixed,sgen_marksweep_fixed_par'
|
||||
',sgen_copying,logging,security,shared_handles,interpreter',
|
||||
'--with-btls-android-ndk=%s' % opts.android_ndk_root,
|
||||
'--with-btls-android-api=%s' % api,
|
||||
]
|
||||
|
||||
CONFIGURE_FLAGS += ['--enable-monodroid'] if opts.with_monodroid else []
|
||||
CONFIGURE_FLAGS += ['--with-btls-android-ndk-asm-workaround'] if android_new_ndk else []
|
||||
|
||||
CONFIGURE_FLAGS += [
|
||||
'--with-btls-android-cmake-toolchain=%s/build/cmake/android.toolchain.cmake' % opts.android_ndk_root,
|
||||
'--with-sigaltstack=yes',
|
||||
'--with-tls=pthread',
|
||||
'--without-ikvm-native',
|
||||
'--disable-cooperative-suspend',
|
||||
'--disable-hybrid-suspend',
|
||||
'--disable-crash-reporting'
|
||||
]
|
||||
|
||||
env['_android-%s_AR' % target] = AR
|
||||
env['_android-%s_AS' % target] = AS
|
||||
env['_android-%s_CC' % target] = CC
|
||||
env['_android-%s_CXX' % target] = CXX
|
||||
env['_android-%s_CPP' % target] = CPP
|
||||
env['_android-%s_CXXCPP' % target] = CXXCPP
|
||||
env['_android-%s_DLLTOOL' % target] = DLLTOOL
|
||||
env['_android-%s_LD' % target] = LD
|
||||
env['_android-%s_OBJDUMP' % target] = OBJDUMP
|
||||
env['_android-%s_RANLIB' % target] = RANLIB
|
||||
env['_android-%s_CMAKE' % target] = CMAKE
|
||||
env['_android-%s_STRIP' % target] = STRIP
|
||||
|
||||
env['_android-%s_AC_VARS' % target] = AC_VARS
|
||||
env['_android-%s_CFLAGS' % target] = CFLAGS
|
||||
env['_android-%s_CXXFLAGS' % target] = CXXFLAGS
|
||||
env['_android-%s_CPPFLAGS' % target] = CPPFLAGS
|
||||
env['_android-%s_CXXCPPFLAGS' % target] = CXXCPPFLAGS
|
||||
env['_android-%s_LDFLAGS' % target] = LDFLAGS
|
||||
env['_android-%s_CONFIGURE_FLAGS' % target] = CONFIGURE_FLAGS
|
||||
|
||||
# Runtime template
|
||||
runtime.setup_runtime_template(env, opts, 'android', target, host_triple)
|
||||
|
||||
|
||||
class AndroidCrossTable:
|
||||
target_archs = {
|
||||
'cross-arm': 'armv7',
|
||||
'cross-arm64': 'aarch64-v8a',
|
||||
'cross-x86': 'i686',
|
||||
'cross-x86_64': 'x86_64'
|
||||
}
|
||||
|
||||
device_targets = {
|
||||
'cross-arm': 'armeabi-v7a',
|
||||
'cross-arm64': 'arm64-v8a',
|
||||
'cross-x86': 'x86',
|
||||
'cross-x86_64': 'x86_64'
|
||||
}
|
||||
|
||||
offsets_dumper_abis = {
|
||||
'cross-arm': 'armv7-none-linux-androideabi',
|
||||
'cross-arm64': 'aarch64-v8a-linux-android',
|
||||
'cross-x86': 'i686-none-linux-android',
|
||||
'cross-x86_64': 'x86_64-none-linux-android'
|
||||
}
|
||||
|
||||
|
||||
def get_android_libclang_path(opts):
|
||||
if sys.platform == 'darwin':
|
||||
return '%s/toolchains/llvm/prebuilt/darwin-x86_64/lib64/libclang.dylib' % opts.android_ndk_root
|
||||
elif sys.platform in ['linux', 'linux2']:
|
||||
return '%s/toolchains/llvm/prebuilt/linux-x86_64/lib64/libclang.so.8svn' % opts.android_ndk_root
|
||||
assert False
|
||||
|
||||
|
||||
def setup_android_cross_template(env: dict, opts: AndroidOpts, target: str, host_arch: str):
|
||||
def get_host_triple():
|
||||
if sys.platform == 'darwin':
|
||||
return '%s-apple-darwin10' % host_arch
|
||||
elif sys.platform in ['linux', 'linux2']:
|
||||
return '%s-linux-gnu' % host_arch
|
||||
assert False
|
||||
|
||||
target_arch = AndroidCrossTable.target_archs[target]
|
||||
device_target = AndroidCrossTable.device_targets[target]
|
||||
offsets_dumper_abi = AndroidCrossTable.offsets_dumper_abis[target]
|
||||
host_triple = get_host_triple()
|
||||
target_triple = '%s-linux-android' % target_arch
|
||||
|
||||
android_libclang = get_android_libclang_path(opts)
|
||||
|
||||
env['_android-%s_OFFSETS_DUMPER_ARGS' % target] = [
|
||||
'--libclang=%s' % android_libclang,
|
||||
'--sysroot=%s/sysroot' % opts.android_ndk_root
|
||||
]
|
||||
|
||||
env['_android-%s_AR' % target] = 'ar'
|
||||
env['_android-%s_AS' % target] = 'as'
|
||||
env['_android-%s_CC' % target] = 'cc'
|
||||
env['_android-%s_CXX' % target] = 'c++'
|
||||
env['_android-%s_CXXCPP' % target] = 'cpp'
|
||||
env['_android-%s_LD' % target] = 'ld'
|
||||
env['_android-%s_RANLIB' % target] = 'ranlib'
|
||||
env['_android-%s_STRIP' % target] = 'strip'
|
||||
|
||||
is_darwin = sys.platform == 'darwin'
|
||||
|
||||
CFLAGS = []
|
||||
CFLAGS += ['-DDEBUG_CROSS'] if not opts.release else []
|
||||
CFLAGS += ['-mmacosx-version-min=10.9'] if is_darwin else []
|
||||
|
||||
env['_android-%s_CFLAGS' % target] = CFLAGS
|
||||
|
||||
CXXFLAGS = []
|
||||
CXXFLAGS += ['-DDEBUG_CROSS'] if not opts.release else []
|
||||
CXXFLAGS += ['-mmacosx-version-min=10.9 -stdlib=libc++'] if is_darwin else []
|
||||
|
||||
env['_android-%s_CXXFLAGS' % target] = CXXFLAGS
|
||||
|
||||
env['_android-%s_CONFIGURE_FLAGS' % target] = [
|
||||
'--disable-boehm',
|
||||
'--disable-mcs-build',
|
||||
'--disable-nls',
|
||||
'--enable-maintainer-mode',
|
||||
'--with-tls=pthread'
|
||||
]
|
||||
|
||||
# Runtime cross template
|
||||
runtime.setup_runtime_cross_template(env, opts, 'android', target, host_triple, target_triple, device_target, 'llvm-llvm64', offsets_dumper_abi)
|
||||
|
||||
|
||||
def setup_android_cross_mxe_template(env: dict, opts: AndroidOpts, target: str, host_arch: str):
|
||||
table_target = cross_targets[cross_mxe_targets.index(target)] # Re-use the non-mxe table
|
||||
|
||||
target_arch = AndroidCrossTable.target_archs[table_target]
|
||||
device_target = AndroidCrossTable.device_targets[table_target]
|
||||
offsets_dumper_abi = AndroidCrossTable.offsets_dumper_abis[table_target]
|
||||
host_triple = '%s-w64-mingw32' % host_arch
|
||||
target_triple = '%s-linux-android' % target_arch
|
||||
|
||||
android_libclang = get_android_libclang_path(opts)
|
||||
|
||||
env['_android-%s_OFFSETS_DUMPER_ARGS' % target] = [
|
||||
'--libclang=%s' % android_libclang,
|
||||
'--sysroot=%s/sysroot' % opts.android_ndk_root
|
||||
]
|
||||
|
||||
mxe_bin = path_join(opts.mxe_prefix, 'bin')
|
||||
|
||||
env['_android-%s_PATH' % target] = mxe_bin
|
||||
|
||||
name_fmt = host_arch + '-w64-mingw32-%s'
|
||||
|
||||
env['_android-%s_AR' % target] = path_join(mxe_bin, name_fmt % 'ar')
|
||||
env['_android-%s_AS' % target] = path_join(mxe_bin, name_fmt % 'as')
|
||||
env['_android-%s_CC' % target] = path_join(mxe_bin, name_fmt % 'gcc')
|
||||
env['_android-%s_CXX' % target] = path_join(mxe_bin, name_fmt % 'g++')
|
||||
env['_android-%s_DLLTOOL' % target] = path_join(mxe_bin, name_fmt % 'dlltool')
|
||||
env['_android-%s_LD' % target] = path_join(mxe_bin, name_fmt % 'ld')
|
||||
env['_android-%s_OBJDUMP' % target] = path_join(mxe_bin, name_fmt % 'objdump')
|
||||
env['_android-%s_RANLIB' % target] = path_join(mxe_bin, name_fmt % 'ranlib')
|
||||
env['_android-%s_STRIP' % target] = path_join(mxe_bin, name_fmt % 'strip')
|
||||
|
||||
mingw_zlib_prefix = '%s/opt/mingw-zlib/usr' % opts.mxe_prefix
|
||||
if not os.path.isdir(mingw_zlib_prefix):
|
||||
mingw_zlib_prefix = opts.mxe_prefix
|
||||
|
||||
CFLAGS = []
|
||||
CFLAGS += ['-DDEBUG_CROSS'] if not opts.release else []
|
||||
CFLAGS += ['-I%s/%s-w64-mingw32/include' % (mingw_zlib_prefix, host_arch)]
|
||||
|
||||
env['_android-%s_CFLAGS' % target] = CFLAGS
|
||||
|
||||
CXXFLAGS = []
|
||||
CXXFLAGS += ['-DDEBUG_CROSS'] if not opts.release else []
|
||||
CXXFLAGS += ['-I%s/%s-w64-mingw32/include' % (mingw_zlib_prefix, host_arch)]
|
||||
|
||||
env['_android-%s_CXXFLAGS' % target] = CXXFLAGS
|
||||
|
||||
env['_android-%s_LDFLAGS' % target] = []
|
||||
|
||||
CONFIGURE_FLAGS = [
|
||||
'--disable-boehm',
|
||||
'--disable-mcs-build',
|
||||
'--disable-nls',
|
||||
'--enable-static-gcc-libs',
|
||||
'--enable-maintainer-mode',
|
||||
'--with-tls=pthread'
|
||||
]
|
||||
|
||||
CONFIGURE_FLAGS += ['--with-static-zlib=%s/%s-w64-mingw32/lib/libz.a' % (mingw_zlib_prefix, host_arch)]
|
||||
|
||||
env['_android-%s_CONFIGURE_FLAGS' % target] = CONFIGURE_FLAGS
|
||||
|
||||
# Runtime cross template
|
||||
runtime.setup_runtime_cross_template(env, opts, 'android', target, host_triple, target_triple, device_target, 'llvm-llvmwin64', offsets_dumper_abi)
|
||||
|
||||
|
||||
def make_standalone_toolchain(opts: AndroidOpts, target: str, api: str):
|
||||
install_dir = path_join(opts.android_toolchains_prefix, opts.toolchain_name_fmt % (target, api))
|
||||
if os.path.isdir(path_join(install_dir, 'bin')):
|
||||
return # Looks like it's already there, so no need to re-create it
|
||||
command = path_join(opts.android_ndk_root, 'build', 'tools', 'make_standalone_toolchain.py')
|
||||
args = ['--verbose', '--force', '--api=' + api, '--arch=' + AndroidTargetTable.archs[target],
|
||||
'--install-dir=' + install_dir]
|
||||
run_command(command, args=args, name='make_standalone_toolchain')
|
||||
|
||||
|
||||
def strip_libs(opts: AndroidOpts, product: str, target: str, api: str):
|
||||
toolchain_path = path_join(opts.android_toolchains_prefix, opts.toolchain_name_fmt % (target, api))
|
||||
|
||||
tools_path = path_join(toolchain_path, 'bin')
|
||||
name_fmt = AndroidTargetTable.abi_names[target] + '-%s'
|
||||
|
||||
strip = path_join(tools_path, name_fmt % 'strip')
|
||||
|
||||
install_dir = path_join(opts.install_dir, '%s-%s-%s' % (product, target, opts.configuration))
|
||||
out_libs_dir = path_join(install_dir, 'lib')
|
||||
|
||||
lib_files = globs(('*.a', '*.so'), dirpath=out_libs_dir)
|
||||
if len(lib_files):
|
||||
run_command(strip, args=['--strip-unneeded'] + lib_files, name='strip')
|
||||
|
||||
|
||||
def configure(opts: AndroidOpts, product: str, target: str):
|
||||
env = { 'ANDROID_API_VERSION': get_api_version_or_min(opts, target) }
|
||||
|
||||
if is_cross(target):
|
||||
import llvm
|
||||
|
||||
if is_cross_mxe(target):
|
||||
llvm.make(opts, 'llvmwin64')
|
||||
setup_android_cross_mxe_template(env, opts, target, host_arch='x86_64')
|
||||
else:
|
||||
llvm.make(opts, 'llvm64')
|
||||
setup_android_cross_template(env, opts, target, host_arch='x86_64')
|
||||
else:
|
||||
make_standalone_toolchain(opts, target, env['ANDROID_API_VERSION'])
|
||||
setup_android_target_template(env, opts, target)
|
||||
|
||||
if not os.path.isfile(path_join(opts.mono_source_root, 'configure')):
|
||||
runtime.run_autogen(opts)
|
||||
|
||||
runtime.run_configure(env, opts, product, target)
|
||||
|
||||
|
||||
def make(opts: AndroidOpts, product: str, target: str):
|
||||
env = { 'ANDROID_API_VERSION': get_api_version_or_min(opts, target) }
|
||||
|
||||
build_dir = path_join(opts.configure_dir, '%s-%s-%s' % (product, target, opts.configuration))
|
||||
|
||||
make_args = ['-C', build_dir]
|
||||
make_args += ['V=1'] if opts.verbose_make else []
|
||||
|
||||
run_command('make', args=make_args, name='make')
|
||||
run_command('make', args=['-C', '%s/mono' % build_dir, 'install'], name='make install mono')
|
||||
run_command('make', args=['-C', '%s/support' % build_dir, 'install'], name='make install support')
|
||||
|
||||
if opts.strip_libs and not is_cross(target):
|
||||
strip_libs(opts, product, target, env['ANDROID_API_VERSION'])
|
||||
|
||||
|
||||
def clean(opts: AndroidOpts, product: str, target: str):
|
||||
rm_rf(
|
||||
path_join(opts.configure_dir, 'toolchains', '%s-%s' % (product, target)),
|
||||
path_join(opts.configure_dir, '%s-%s-%s' % (product, target, opts.configuration)),
|
||||
path_join(opts.configure_dir, '%s-%s-%s.config.cache' % (product, target, opts.configuration)),
|
||||
path_join(opts.install_dir, '%s-%s-%s' % (product, target, opts.configuration))
|
||||
)
|
||||
|
||||
|
||||
def main(raw_args):
|
||||
import cmd_utils
|
||||
from cmd_utils import custom_bool
|
||||
from collections import OrderedDict
|
||||
from typing import Callable
|
||||
|
||||
target_shortcuts = {
|
||||
'all-runtime': runtime_targets,
|
||||
'all-cross': cross_targets,
|
||||
'all-cross-win': cross_mxe_targets
|
||||
}
|
||||
|
||||
target_values = runtime_targets + cross_targets + cross_mxe_targets + list(target_shortcuts)
|
||||
|
||||
actions = OrderedDict()
|
||||
actions['configure'] = configure
|
||||
actions['make'] = make
|
||||
actions['clean'] = clean
|
||||
|
||||
parser = cmd_utils.build_arg_parser(
|
||||
description='Builds the Mono runtime for Android',
|
||||
env_vars={
|
||||
'ANDROID_SDK_ROOT': 'Overrides default value for --android-sdk',
|
||||
'ANDROID_NDK_ROOT': 'Overrides default value for --android-ndk',
|
||||
'ANDROID_HOME': 'Same as ANDROID_SDK_ROOT'
|
||||
}
|
||||
)
|
||||
|
||||
home = os.environ.get('HOME')
|
||||
android_sdk_default = os.environ.get('ANDROID_HOME', os.environ.get('ANDROID_SDK_ROOT', path_join(home, 'Android/Sdk')))
|
||||
android_ndk_default = os.environ.get('ANDROID_NDK_ROOT', path_join(android_sdk_default, 'ndk-bundle'))
|
||||
|
||||
default_help = 'default: %(default)s'
|
||||
|
||||
parser.add_argument('action', choices=['configure', 'make', 'clean'])
|
||||
parser.add_argument('--target', choices=target_values, action='append', required=True)
|
||||
parser.add_argument('--toolchains-prefix', default=path_join(home, 'android-toolchains'), help=default_help)
|
||||
parser.add_argument('--android-sdk', default=android_sdk_default, help=default_help)
|
||||
parser.add_argument('--android-ndk', default=android_ndk_default, help=default_help)
|
||||
parser.add_argument('--android-api-version', default='18', help=default_help)
|
||||
parser.add_argument('--android-cmake-version', default='autodetect', help=default_help)
|
||||
parser.add_argument('--with-monodroid', type=custom_bool, default=True, help=default_help)
|
||||
|
||||
cmd_utils.add_runtime_arguments(parser, default_help)
|
||||
|
||||
args = parser.parse_args(raw_args)
|
||||
|
||||
input_action = args.action
|
||||
input_targets = args.target
|
||||
|
||||
opts = android_opts_from_args(args)
|
||||
|
||||
if not os.path.isdir(opts.mono_source_root):
|
||||
print('Mono sources directory not found: ' + opts.mono_source_root)
|
||||
sys.exit(1)
|
||||
|
||||
targets = cmd_utils.expand_input_targets(input_targets, target_shortcuts)
|
||||
action = actions[input_action]
|
||||
|
||||
try:
|
||||
for target in targets:
|
||||
action(opts, 'android', target)
|
||||
except BuildError as e:
|
||||
sys.exit(e.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sys import argv
|
||||
main(argv[1:])
|
151
bcl.py
Executable file
151
bcl.py
Executable file
@ -0,0 +1,151 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
from os.path import join as path_join
|
||||
from options import *
|
||||
from os_utils import *
|
||||
|
||||
|
||||
product_values = ['desktop', 'android', 'wasm']
|
||||
profiles_table = {
|
||||
'desktop': ['net_4_x'],
|
||||
'android': ['monodroid', 'monodroid_tools'],
|
||||
'wasm': ['wasm', 'wasm_tools']
|
||||
}
|
||||
test_profiles_table = {
|
||||
'desktop': [],
|
||||
'android': ['monodroid', 'monodroid_tools'],
|
||||
'wasm': ['wasm']
|
||||
}
|
||||
|
||||
|
||||
def configure_bcl(opts: BclOpts):
|
||||
stamp_file = path_join(opts.configure_dir, '.stamp-bcl-configure')
|
||||
|
||||
if os.path.isfile(stamp_file):
|
||||
return
|
||||
|
||||
build_dir = path_join(opts.configure_dir, 'bcl')
|
||||
mkdir_p(build_dir)
|
||||
|
||||
CONFIGURE_FLAGS = [
|
||||
'--disable-boehm',
|
||||
'--disable-btls-lib',
|
||||
'--disable-nls',
|
||||
'--disable-support-build',
|
||||
'--with-mcs-docs=no'
|
||||
]
|
||||
|
||||
configure = path_join(opts.mono_source_root, 'configure')
|
||||
configure_args = CONFIGURE_FLAGS
|
||||
|
||||
run_command(configure, args=configure_args, cwd=build_dir, name='configure bcl')
|
||||
|
||||
touch(stamp_file)
|
||||
|
||||
|
||||
def make_bcl(opts: BclOpts):
|
||||
stamp_file = path_join(opts.configure_dir, '.stamp-bcl-make')
|
||||
|
||||
if os.path.isfile(stamp_file):
|
||||
return
|
||||
|
||||
build_dir = path_join(opts.configure_dir, 'bcl')
|
||||
|
||||
make_args = ['-C', build_dir, '-C', 'mono']
|
||||
make_args += ['V=1'] if opts.verbose_make else []
|
||||
|
||||
run_command('make', args=make_args, name='make bcl')
|
||||
|
||||
touch(stamp_file)
|
||||
|
||||
|
||||
def build_bcl(opts: BclOpts):
|
||||
configure_bcl(opts)
|
||||
make_bcl(opts)
|
||||
|
||||
|
||||
def clean_bcl(opts: BclOpts):
|
||||
configure_stamp_file = path_join(opts.configure_dir, '.stamp-bcl-configure')
|
||||
make_stamp_file = path_join(opts.configure_dir, '.stamp-bcl-make')
|
||||
build_dir = path_join(opts.configure_dir, 'bcl')
|
||||
rm_rf(configure_stamp_file, make_stamp_file, build_dir)
|
||||
|
||||
|
||||
def make_product(opts: BclOpts, product: str):
|
||||
build_bcl(opts)
|
||||
|
||||
build_dir = path_join(opts.configure_dir, 'bcl')
|
||||
|
||||
profiles = profiles_table[product]
|
||||
test_profiles = test_profiles_table[product]
|
||||
|
||||
install_dir = path_join(opts.install_dir, '%s-bcl' % product)
|
||||
|
||||
mkdir_p(install_dir)
|
||||
|
||||
for profile in profiles:
|
||||
mkdir_p('%s/%s' % (install_dir, profile))
|
||||
|
||||
make_args = ['-C', build_dir, '-C', 'runtime', 'all-mcs', 'build_profiles=%s' % ' '.join(profiles)]
|
||||
make_args += ['V=1'] if opts.verbose_make else []
|
||||
run_command('make', args=make_args, name='make profiles')
|
||||
|
||||
if opts.tests and len(test_profiles) > 0:
|
||||
test_make_args = ['-C', build_dir, '-C', 'runtime', 'test', 'xunit-test', 'test_profiles=%s' % ' '.join(test_profiles)]
|
||||
test_make_args += ['V=1'] if opts.verbose_make else []
|
||||
run_command('make', args=test_make_args, name='make tests')
|
||||
|
||||
# Copy the bcl profiles to the output directory
|
||||
from distutils.dir_util import copy_tree
|
||||
for profile in profiles:
|
||||
copy_tree('%s/mcs/class/lib/%s' % (opts.mono_source_root, profile), '%s/%s' % (install_dir, profile))
|
||||
|
||||
# Recursively remove hidden files we shoudln't have copied (e.g.: .stamp)
|
||||
import glob
|
||||
hidden_file_pattern = '%s/**/.*' % install_dir
|
||||
for profile in profiles:
|
||||
[rm_rf(x) for x in glob.iglob(hidden_file_pattern, recursive=True)]
|
||||
|
||||
|
||||
def clean_product(opts: BclOpts, product: str):
|
||||
clean_bcl(opts)
|
||||
|
||||
install_dir = path_join(opts.install_dir, '%s-bcl' % product)
|
||||
rm_rf(install_dir)
|
||||
|
||||
|
||||
def main(raw_args):
|
||||
import cmd_utils
|
||||
|
||||
actions = {
|
||||
'make': make_product,
|
||||
'clean': clean_product
|
||||
}
|
||||
|
||||
parser = cmd_utils.build_arg_parser(description='Builds the Mono BCL')
|
||||
|
||||
default_help = 'default: %(default)s'
|
||||
|
||||
parser.add_argument('action', choices=actions.keys())
|
||||
parser.add_argument('--product', choices=product_values, action='append', required=True)
|
||||
parser.add_argument('--tests', action='store_true', default=False, help=default_help)
|
||||
|
||||
cmd_utils.add_base_arguments(parser, default_help)
|
||||
|
||||
args = parser.parse_args(raw_args)
|
||||
|
||||
opts = bcl_opts_from_args(args)
|
||||
products = args.product
|
||||
|
||||
for product in products:
|
||||
action = actions[args.action]
|
||||
action(opts, product)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sys import argv
|
||||
main(argv[1:])
|
@ -1,597 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from os import environ
|
||||
from os.path import exists as path_exists, join as path_join, isfile, isdir, abspath
|
||||
from sys import exit
|
||||
|
||||
|
||||
class MonoBuildError(Exception):
|
||||
'''Generic exception for custom build errors'''
|
||||
def __init__(self, msg):
|
||||
super(MonoBuildError, self).__init__(msg)
|
||||
self.message = msg
|
||||
|
||||
|
||||
def run_command(command, args=[], custom_env=None, name='command'):
|
||||
def cmd_args_to_str(cmd_args):
|
||||
return ' '.join([arg if not ' ' in arg else '"%s"' % arg for arg in cmd_args])
|
||||
|
||||
assert isinstance(command, str) and isinstance(args, list)
|
||||
args = [command] + args
|
||||
|
||||
import subprocess
|
||||
try:
|
||||
print('Running command \'%s\': %s' % (name, cmd_args_to_str(args)))
|
||||
if custom_env is None:
|
||||
subprocess.check_call(args)
|
||||
else:
|
||||
subprocess.check_call(args, env=custom_env)
|
||||
print('Command \'%s\' completed successfully' % name)
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise MonoBuildError('\'%s\' exited with error code: %s' % (name, e.returncode))
|
||||
|
||||
|
||||
# Creates the directory if no other file or directory with the same path exists
|
||||
def mkdir_p(path):
|
||||
from os import makedirs
|
||||
if not path_exists(path):
|
||||
print('creating directory: ' + path)
|
||||
makedirs(path)
|
||||
|
||||
|
||||
def chdir(path):
|
||||
from os import chdir as os_chdir
|
||||
print('entering directory: ' + path)
|
||||
os_chdir(path)
|
||||
|
||||
|
||||
# Remove files and/or directories recursively
|
||||
def rm_rf(*paths):
|
||||
from os import remove
|
||||
from shutil import rmtree
|
||||
for path in paths:
|
||||
if isfile(path):
|
||||
print('removing file: ' + path)
|
||||
remove(path)
|
||||
elif isdir(path):
|
||||
print('removing directory and its contents: ' + path)
|
||||
rmtree(path)
|
||||
|
||||
|
||||
def globs(pathnames, dirpath='.'):
|
||||
import glob
|
||||
files = []
|
||||
for pathname in pathnames:
|
||||
files.extend(glob.glob(path_join(dirpath, pathname)))
|
||||
return files
|
||||
|
||||
|
||||
TOOLCHAIN_NAME_FMT = '%s-api%s-clang'
|
||||
|
||||
CONFIGURATION = None
|
||||
RELEASE = None
|
||||
|
||||
ANDROID_TOOLCHAINS_PREFIX = None
|
||||
|
||||
ANDROID_SDK_ROOT = None
|
||||
ANDROID_NDK_ROOT = None
|
||||
|
||||
WITH_MONODROID = None
|
||||
ENABLE_CXX = None
|
||||
VERBOSE_MAKE = None
|
||||
STRIP_LIBS = None
|
||||
|
||||
CONFIGURE_DIR = None
|
||||
INSTALL_DIR = None
|
||||
|
||||
MONO_SOURCE_ROOT = None
|
||||
|
||||
_ANDROID_API_VERSION = None
|
||||
_ANDROID_CMAKE_VERSION = None
|
||||
|
||||
|
||||
class AndroidTargetInfo:
|
||||
archs = {
|
||||
'armeabi-v7a': 'arm',
|
||||
'arm64-v8a': 'arm64',
|
||||
'x86': 'x86',
|
||||
'x86_64': 'x86_64'
|
||||
}
|
||||
|
||||
abi_names = {
|
||||
'armeabi-v7a': 'arm-linux-androideabi',
|
||||
'arm64-v8a': 'aarch64-linux-android',
|
||||
'x86': 'i686-linux-android',
|
||||
'x86_64': 'x86_64-linux-android'
|
||||
}
|
||||
|
||||
host_triples = {
|
||||
'armeabi-v7a': 'armv5-linux-androideabi',
|
||||
'arm64-v8a': 'aarch64-linux-android',
|
||||
'x86': 'i686-linux-android',
|
||||
'x86_64': 'x86_64-linux-android'
|
||||
}
|
||||
|
||||
|
||||
def android_autodetect_cmake():
|
||||
from distutils.version import LooseVersion
|
||||
from os import listdir
|
||||
|
||||
sdk_cmake_basedir = path_join(ANDROID_SDK_ROOT, 'cmake')
|
||||
versions = []
|
||||
|
||||
for entry in listdir(sdk_cmake_basedir):
|
||||
if isdir(path_join(sdk_cmake_basedir, entry)):
|
||||
try:
|
||||
version = LooseVersion(entry)
|
||||
versions += [version]
|
||||
except ValueError:
|
||||
continue # Not a version folder
|
||||
|
||||
if len(versions) == 0:
|
||||
raise MonoBuildError('Cannot auto-detect Android CMake version')
|
||||
|
||||
lattest_version = str(sorted(versions)[-1])
|
||||
print('Auto-detected Android CMake version: ' + lattest_version)
|
||||
|
||||
return lattest_version
|
||||
|
||||
|
||||
def get_api_version_or_min(target):
|
||||
min_versions = { 'arm64-v8a': '21', 'x86_64': '21' }
|
||||
if target in min_versions and int(_ANDROID_API_VERSION) < int(min_versions[target]):
|
||||
print('WARNING: %s is less than minimum platform for %s; using %s' % (_ANDROID_API_VERSION, target, min_versions[target]))
|
||||
return min_versions[target]
|
||||
return _ANDROID_API_VERSION
|
||||
|
||||
|
||||
def get_android_cmake_version():
|
||||
return _ANDROID_CMAKE_VERSION if _ANDROID_CMAKE_VERSION != 'autodetect' else android_autodetect_cmake()
|
||||
|
||||
|
||||
def setup_runtime_template(env, product, target, host_triple):
|
||||
BITNESS = ''
|
||||
if any(s in host_triple for s in ['i686', 'i386']):
|
||||
BITNESS = '-m32'
|
||||
elif 'x86_64' in host_triple:
|
||||
BITNESS = '-m64'
|
||||
|
||||
CFLAGS = []
|
||||
CFLAGS += ['-O2', '-g'] if RELEASE else ['-O0', '-ggdb3', '-fno-omit-frame-pointer']
|
||||
CFLAGS += env.get('_%s-%s_CFLAGS' % (product, target), [])
|
||||
CFLAGS += env.get('%s-%s_CFLAGS' % (product, target), [])
|
||||
CFLAGS += [BITNESS] if BITNESS else []
|
||||
|
||||
CXXFLAGS = []
|
||||
CXXFLAGS += ['-O2', '-g'] if RELEASE else ['-O0', '-ggdb3', '-fno-omit-frame-pointer']
|
||||
CXXFLAGS += env.get('_%s-%s_CXXFLAGS' % (product, target), [])
|
||||
CXXFLAGS += env.get('%s-%s_CXXFLAGS' % (product, target), [])
|
||||
CXXFLAGS += [BITNESS] if BITNESS else []
|
||||
|
||||
CPPFLAGS = []
|
||||
CPPFLAGS += ['-O2', '-g'] if RELEASE else ['-O0', '-ggdb3', '-fno-omit-frame-pointer']
|
||||
CPPFLAGS += env.get('_%s-%s_CPPFLAGS' % (product, target), [])
|
||||
CPPFLAGS += env.get('%s-%s_CPPFLAGS' % (product, target), [])
|
||||
CPPFLAGS += [BITNESS] if BITNESS else []
|
||||
|
||||
CXXCPPFLAGS = []
|
||||
CXXCPPFLAGS += ['-O2', '-g'] if RELEASE else ['-O0', '-ggdb3', '-fno-omit-frame-pointer']
|
||||
CXXCPPFLAGS += env.get('_%s-%s_CXXCPPFLAGS' % (product, target), [])
|
||||
CXXCPPFLAGS += env.get('%s-%s_CXXCPPFLAGS' % (product, target), [])
|
||||
CXXCPPFLAGS += [BITNESS] if BITNESS else []
|
||||
|
||||
LDFLAGS = []
|
||||
LDFLAGS += env.get('_%s-%s_LDFLAGS' % (product, target), [])
|
||||
LDFLAGS += env.get('%s-%s_LDFLAGS' % (product, target), [])
|
||||
|
||||
AC_VARS = []
|
||||
AC_VARS += env.get('_%s-%s_AC_VARS' % (product, target), [])
|
||||
AC_VARS += env.get('%s-%s_AC_VARS' % (product, target), [])
|
||||
|
||||
CONFIGURE_ENVIRONMENT = {}
|
||||
|
||||
def append_product_env_var(var_name):
|
||||
val = env.get('_%s-%s_%s' % (product, target, var_name), '')
|
||||
if val:
|
||||
CONFIGURE_ENVIRONMENT[var_name] = val
|
||||
|
||||
append_product_env_var('AR')
|
||||
append_product_env_var('AS')
|
||||
append_product_env_var('CC')
|
||||
append_product_env_var('CPP')
|
||||
append_product_env_var('CXX')
|
||||
append_product_env_var('CXXCPP')
|
||||
append_product_env_var('DLLTOOL')
|
||||
append_product_env_var('LD')
|
||||
append_product_env_var('OBJDUMP')
|
||||
append_product_env_var('RANLIB')
|
||||
append_product_env_var('CMAKE')
|
||||
append_product_env_var('STRIP')
|
||||
|
||||
CONFIGURE_ENVIRONMENT['CFLAGS'] = CFLAGS
|
||||
CONFIGURE_ENVIRONMENT['CXXFLAGS'] = CXXFLAGS
|
||||
CONFIGURE_ENVIRONMENT['CPPFLAGS'] = CPPFLAGS
|
||||
CONFIGURE_ENVIRONMENT['CXXCPPFLAGS'] = CXXCPPFLAGS
|
||||
CONFIGURE_ENVIRONMENT['LDFLAGS'] = LDFLAGS
|
||||
|
||||
CONFIGURE_ENVIRONMENT.update(env.get('_%s-%s_CONFIGURE_ENVIRONMENT' % (product, target), {}))
|
||||
CONFIGURE_ENVIRONMENT.update(env.get('%s-%s_CONFIGURE_ENVIRONMENT' % (product, target), {}))
|
||||
|
||||
CONFIGURE_FLAGS = []
|
||||
CONFIGURE_FLAGS += ['--host=%s' % host_triple] if host_triple else []
|
||||
CONFIGURE_FLAGS += ['--cache-file=%s/%s-%s-%s.config.cache' % (CONFIGURE_DIR, product, target, CONFIGURATION)]
|
||||
CONFIGURE_FLAGS += ['--prefix=%s/%s-%s-%s' % (INSTALL_DIR, product, target, CONFIGURATION)]
|
||||
CONFIGURE_FLAGS += ['--enable-cxx'] if ENABLE_CXX else []
|
||||
# CONFIGURE_FLAGS += env['_cross-runtime_%s-%s_CONFIGURE_FLAGS' % (product, target)]
|
||||
CONFIGURE_FLAGS += env.get('_%s-%s_CONFIGURE_FLAGS' % (product, target), [])
|
||||
CONFIGURE_FLAGS += env.get('%s-%s_CONFIGURE_FLAGS' % (product, target), [])
|
||||
|
||||
env['_runtime_%s-%s_AC_VARS' % (product, target)] = AC_VARS
|
||||
env['_runtime_%s-%s_CONFIGURE_ENVIRONMENT' % (product, target)] = CONFIGURE_ENVIRONMENT
|
||||
env['_runtime_%s-%s_CONFIGURE_FLAGS' % (product, target)] = CONFIGURE_FLAGS
|
||||
|
||||
|
||||
def setup_android_target_template(env, target):
|
||||
extra_target_envs = {
|
||||
'armeabi-v7a': {
|
||||
'android-armeabi-v7a_CFLAGS': ['-D__POSIX_VISIBLE=201002', '-DSK_RELEASE', '-DNDEBUG', '-UDEBUG', '-fpic', '-march=armv7-a', '-mtune=cortex-a8', '-mfpu=vfp', '-mfloat-abi=softfp'],
|
||||
'android-armeabi-v7a_CXXFLAGS': ['-D__POSIX_VISIBLE=201002', '-DSK_RELEASE', '-DNDEBUG', '-UDEBUG', '-fpic', '-march=armv7-a', '-mtune=cortex-a8', '-mfpu=vfp', '-mfloat-abi=softfp'],
|
||||
'android-armeabi-v7a_LDFLAGS': ['-Wl,--fix-cortex-a8']
|
||||
},
|
||||
'arm64-v8a': {
|
||||
'android-arm64-v8a_CFLAGS': ['-D__POSIX_VISIBLE=201002', '-DSK_RELEASE', '-DNDEBUG', '-UDEBUG', '-fpic', '-DL_cuserid=9', '-DANDROID64'],
|
||||
'android-arm64-v8a_CXXFLAGS': ['-D__POSIX_VISIBLE=201002', '-DSK_RELEASE', '-DNDEBUG', '-UDEBUG', '-fpic', '-DL_cuserid=9', '-DANDROID64']
|
||||
},
|
||||
'x86': {},
|
||||
'x86_64': {
|
||||
'android-x86_64_CFLAGS': ['-DL_cuserid=9'],
|
||||
'android-x86_64_CXXFLAGS': ['-DL_cuserid=9']
|
||||
}
|
||||
}
|
||||
|
||||
env.update(extra_target_envs[target])
|
||||
|
||||
android_new_ndk = True
|
||||
|
||||
with open(path_join(ANDROID_NDK_ROOT, 'source.properties')) as file:
|
||||
for line in file:
|
||||
line = line.strip()
|
||||
if line.startswith('Pkg.Revision ') or line.startswith('Pkg.Revision='):
|
||||
pkg_revision = line.split('=')[1].strip()
|
||||
mayor = int(pkg_revision.split('.')[0])
|
||||
android_new_ndk = mayor >= 18
|
||||
break
|
||||
|
||||
arch = AndroidTargetInfo.archs[target]
|
||||
abi_name = AndroidTargetInfo.abi_names[target]
|
||||
host_triple = AndroidTargetInfo.host_triples[target]
|
||||
api = env['ANDROID_API_VERSION']
|
||||
|
||||
toolchain_path = path_join(ANDROID_TOOLCHAINS_PREFIX, TOOLCHAIN_NAME_FMT % (target, api))
|
||||
|
||||
tools_path = path_join(toolchain_path, 'bin')
|
||||
name_fmt = abi_name + '-%s'
|
||||
|
||||
sdk_cmake_dir = path_join(ANDROID_SDK_ROOT, 'cmake', get_android_cmake_version())
|
||||
if not isdir(sdk_cmake_dir):
|
||||
print('Android CMake directory \'%s\' not found' % sdk_cmake_dir)
|
||||
|
||||
AR = path_join(tools_path, name_fmt % 'ar')
|
||||
AS = path_join(tools_path, name_fmt % 'as')
|
||||
CC = path_join(tools_path, name_fmt % 'clang')
|
||||
CXX = path_join(tools_path, name_fmt % 'clang++')
|
||||
DLLTOOL = ''
|
||||
LD = path_join(tools_path, name_fmt % 'ld')
|
||||
OBJDUMP = path_join(tools_path, name_fmt % 'objdump')
|
||||
RANLIB = path_join(tools_path, name_fmt % 'ranlib')
|
||||
CMAKE = path_join(sdk_cmake_dir, 'bin', 'cmake')
|
||||
STRIP = path_join(tools_path, name_fmt % 'strip')
|
||||
|
||||
CPP = path_join(tools_path, name_fmt % 'cpp')
|
||||
if not isfile(CPP):
|
||||
CPP = path_join(tools_path, (name_fmt % 'clang'))
|
||||
CPP += ' -E'
|
||||
|
||||
CXXCPP = path_join(tools_path, name_fmt % 'cpp')
|
||||
if not isfile(CXXCPP):
|
||||
CXXCPP = path_join(tools_path, (name_fmt % 'clang++'))
|
||||
CXXCPP += ' -E'
|
||||
|
||||
ccache_path = environ.get('CCACHE', '')
|
||||
if ccache_path:
|
||||
CC = '%s %s' % (ccache_path, CC)
|
||||
CXX = '%s %s' % (ccache_path, CXX)
|
||||
CPP = '%s %s' % (ccache_path, CPP)
|
||||
CXXCPP = '%s %s' % (ccache_path, CXXCPP)
|
||||
|
||||
AC_VARS = [
|
||||
'mono_cv_uscore=yes',
|
||||
'ac_cv_func_sched_getaffinity=no',
|
||||
'ac_cv_func_sched_setaffinity=no',
|
||||
'ac_cv_func_shm_open_working_with_mmap=no'
|
||||
]
|
||||
|
||||
CFLAGS, CXXFLAGS, CPPFLAGS, CXXCPPFLAGS, LDFLAGS = [], [], [], [], []
|
||||
|
||||
# On Android we use 'getApplicationInfo().nativeLibraryDir' as the libdir where Mono will look for shared objects.
|
||||
# This path looks something like this: '/data/app-lib/{package_name-{num}}'. However, Mono does some relocation
|
||||
# and the actual path it will look at will be '/data/app-lib/{package_name}-{num}/../lib', which doesn't exist.
|
||||
# Cannot use '/data/data/{package_name}/lib' either, as '/data/data/{package_name}/lib/../lib' may result in
|
||||
# permission denied. Therefore we just override 'MONO_RELOC_LIBDIR' here to avoid the relocation.
|
||||
CPPFLAGS += ['-DMONO_RELOC_LIBDIR=\\\".\\\"']
|
||||
|
||||
CFLAGS += ['-fstack-protector']
|
||||
CFLAGS += ['-DMONODROID=1'] if WITH_MONODROID else []
|
||||
CFLAGS += ['-D__ANDROID_API__=' + api] if android_new_ndk else []
|
||||
CXXFLAGS += ['-fstack-protector']
|
||||
CXXFLAGS += ['-DMONODROID=1'] if WITH_MONODROID else []
|
||||
CXXFLAGS += ['-D__ANDROID_API__=' + api] if android_new_ndk else []
|
||||
|
||||
CPPFLAGS += ['-I%s/sysroot/usr/include' % toolchain_path]
|
||||
CXXCPPFLAGS += ['-I%s/sysroot/usr/include' % toolchain_path]
|
||||
|
||||
path_link = '%s/platforms/android-%s/arch-%s/usr/lib' % (ANDROID_NDK_ROOT, api, arch)
|
||||
|
||||
LDFLAGS += [
|
||||
'-z', 'now', '-z', 'relro', '-z', 'noexecstack',
|
||||
'-ldl', '-lm', '-llog', '-lc', '-lgcc',
|
||||
'-Wl,-rpath-link=%s,-dynamic-linker=/system/bin/linker' % path_link,
|
||||
'-L' + path_link
|
||||
]
|
||||
|
||||
# Fixes this error: DllImport unable to load library 'dlopen failed: empty/missing DT_HASH in "libmono-native.so" (built with --hash-style=gnu?)'.
|
||||
LDFLAGS += ['-Wl,--hash-style=both']
|
||||
|
||||
CONFIGURE_FLAGS = [
|
||||
'--disable-boehm',
|
||||
'--disable-executables',
|
||||
'--disable-iconv',
|
||||
'--disable-mcs-build',
|
||||
'--disable-nls',
|
||||
'--enable-dynamic-btls',
|
||||
'--enable-maintainer-mode',
|
||||
'--enable-minimal=ssa,portability,attach,verifier,full_messages,sgen_remset'
|
||||
',sgen_marksweep_par,sgen_marksweep_fixed,sgen_marksweep_fixed_par'
|
||||
',sgen_copying,logging,security,shared_handles,interpreter',
|
||||
'--with-btls-android-ndk=%s' % ANDROID_NDK_ROOT,
|
||||
'--with-btls-android-api=%s' % api,
|
||||
]
|
||||
|
||||
CONFIGURE_FLAGS += ['--enable-monodroid'] if WITH_MONODROID else []
|
||||
CONFIGURE_FLAGS += ['--with-btls-android-ndk-asm-workaround'] if android_new_ndk else []
|
||||
|
||||
CONFIGURE_FLAGS += [
|
||||
'--with-btls-android-cmake-toolchain=%s/build/cmake/android.toolchain.cmake' % ANDROID_NDK_ROOT,
|
||||
'--with-sigaltstack=yes',
|
||||
'--with-tls=pthread',
|
||||
'--without-ikvm-native',
|
||||
'--disable-cooperative-suspend',
|
||||
'--disable-hybrid-suspend',
|
||||
'--disable-crash-reporting'
|
||||
]
|
||||
|
||||
env['_android-%s_AR' % target] = AR
|
||||
env['_android-%s_AS' % target] = AS
|
||||
env['_android-%s_CC' % target] = CC
|
||||
env['_android-%s_CXX' % target] = CXX
|
||||
env['_android-%s_CPP' % target] = CPP
|
||||
env['_android-%s_CXXCPP' % target] = CXXCPP
|
||||
env['_android-%s_DLLTOOL' % target] = DLLTOOL
|
||||
env['_android-%s_LD' % target] = LD
|
||||
env['_android-%s_OBJDUMP' % target] = OBJDUMP
|
||||
env['_android-%s_RANLIB' % target] = RANLIB
|
||||
env['_android-%s_CMAKE' % target] = CMAKE
|
||||
env['_android-%s_STRIP' % target] = STRIP
|
||||
|
||||
env['_android-%s_AC_VARS' % target] = AC_VARS
|
||||
env['_android-%s_CFLAGS' % target] = CFLAGS
|
||||
env['_android-%s_CXXFLAGS' % target] = CXXFLAGS
|
||||
env['_android-%s_CPPFLAGS' % target] = CPPFLAGS
|
||||
env['_android-%s_CXXCPPFLAGS' % target] = CXXCPPFLAGS
|
||||
env['_android-%s_LDFLAGS' % target] = LDFLAGS
|
||||
env['_android-%s_CONFIGURE_FLAGS' % target] = CONFIGURE_FLAGS
|
||||
|
||||
setup_runtime_template(env, 'android', target, host_triple)
|
||||
|
||||
|
||||
def make_standalone_toolchain(target, api):
|
||||
install_dir = path_join(ANDROID_TOOLCHAINS_PREFIX, TOOLCHAIN_NAME_FMT % (target, api))
|
||||
if isdir(path_join(install_dir, 'bin')):
|
||||
return # Looks like it's already there, so no need to re-create it
|
||||
command = path_join(ANDROID_NDK_ROOT, 'build', 'tools', 'make_standalone_toolchain.py')
|
||||
args = ['--verbose', '--force', '--api=' + api, '--arch=' + AndroidTargetInfo.archs[target],
|
||||
'--install-dir=' + install_dir]
|
||||
run_command(command, args=args, name='make_standalone_toolchain')
|
||||
|
||||
|
||||
def strip_libs(product, target, api):
|
||||
toolchain_path = path_join(ANDROID_TOOLCHAINS_PREFIX, TOOLCHAIN_NAME_FMT % (target, api))
|
||||
|
||||
tools_path = path_join(toolchain_path, 'bin')
|
||||
name_fmt = AndroidTargetInfo.abi_names[target] + '-%s'
|
||||
|
||||
STRIP = path_join(tools_path, name_fmt % 'strip')
|
||||
|
||||
install_dir = '%s/%s-%s-%s' % (INSTALL_DIR, product, target, CONFIGURATION)
|
||||
out_libs_dir = path_join(install_dir, 'lib')
|
||||
|
||||
lib_files = globs(('*.a', '*.so'), dirpath=out_libs_dir)
|
||||
if len(lib_files):
|
||||
run_command(STRIP, args=['--strip-unneeded'] + lib_files, name='strip')
|
||||
|
||||
|
||||
def configure(product, target):
|
||||
env = { 'ANDROID_API_VERSION': get_api_version_or_min(target) }
|
||||
|
||||
make_standalone_toolchain(target, env['ANDROID_API_VERSION'])
|
||||
|
||||
setup_android_target_template(env, target)
|
||||
|
||||
chdir(MONO_SOURCE_ROOT)
|
||||
autogen_env = environ.copy()
|
||||
autogen_env['NOCONFIGURE'] = '1'
|
||||
run_command(path_join(MONO_SOURCE_ROOT, 'autogen.sh'), custom_env=autogen_env, name='autogen')
|
||||
|
||||
build_dir = CONFIGURE_DIR + '/%s-%s-%s' % (product, target, CONFIGURATION)
|
||||
mkdir_p(build_dir)
|
||||
chdir(build_dir)
|
||||
|
||||
def str_dict_val(val):
|
||||
if isinstance(val, list):
|
||||
return ' '.join(val) # No need for quotes
|
||||
return val
|
||||
|
||||
ac_vars = env['_runtime_%s-%s_AC_VARS' % (product, target)]
|
||||
configure_env = env['_runtime_%s-%s_CONFIGURE_ENVIRONMENT' % (product, target)]
|
||||
configure_env = [('%s=%s' % (key, str_dict_val(value))) for (key, value) in configure_env.items()]
|
||||
configure_flags = env['_runtime_%s-%s_CONFIGURE_FLAGS' % (product, target)]
|
||||
|
||||
command = path_join(MONO_SOURCE_ROOT, 'configure')
|
||||
configure_args = ac_vars + configure_env + configure_flags
|
||||
|
||||
run_command(command, args=configure_args, name='configure')
|
||||
|
||||
|
||||
def make(product, target):
|
||||
env = { 'ANDROID_API_VERSION': get_api_version_or_min(target) }
|
||||
|
||||
build_dir = CONFIGURE_DIR + '/%s-%s-%s' % (product, target, CONFIGURATION)
|
||||
chdir(build_dir)
|
||||
|
||||
make_args = ['V=1'] if VERBOSE_MAKE else []
|
||||
|
||||
run_command('make', args=make_args, name='make')
|
||||
run_command('make', args=['install'], name='make install')
|
||||
|
||||
if STRIP_LIBS:
|
||||
strip_libs(product, target, env['ANDROID_API_VERSION'])
|
||||
|
||||
|
||||
def clean(product, target):
|
||||
rm_rf(
|
||||
CONFIGURE_DIR + '/toolchains/%s-%s' % (product, target),
|
||||
CONFIGURE_DIR + '/%s-%s-%s' % (product, target, CONFIGURATION),
|
||||
CONFIGURE_DIR + '/%s-%s-%s.config.cache' % (product, target, CONFIGURATION),
|
||||
INSTALL_DIR + '/%s-%s-%s' % (product, target, CONFIGURATION)
|
||||
)
|
||||
|
||||
|
||||
def set_arguments(args):
|
||||
global CONFIGURATION, RELEASE, ANDROID_TOOLCHAINS_PREFIX, ANDROID_SDK_ROOT, ANDROID_NDK_ROOT, \
|
||||
_ANDROID_API_VERSION, _ANDROID_CMAKE_VERSION, WITH_MONODROID, ENABLE_CXX, \
|
||||
VERBOSE_MAKE, STRIP_LIBS, CONFIGURE_DIR, INSTALL_DIR, MONO_SOURCE_ROOT, CONFIGURATION
|
||||
|
||||
# Need to make paths absolute as we change cwd later
|
||||
|
||||
CONFIGURATION = args.configuration
|
||||
RELEASE = (CONFIGURATION == 'release')
|
||||
ANDROID_TOOLCHAINS_PREFIX = abspath(args.toolchains_prefix)
|
||||
ANDROID_SDK_ROOT = abspath(args.android_sdk)
|
||||
ANDROID_NDK_ROOT = abspath(args.android_ndk)
|
||||
WITH_MONODROID = args.with_monodroid
|
||||
ENABLE_CXX = args.enable_cxx
|
||||
VERBOSE_MAKE = args.verbose_make
|
||||
STRIP_LIBS = args.strip_libs
|
||||
CONFIGURE_DIR = abspath(args.configure_dir)
|
||||
INSTALL_DIR = abspath(args.install_dir)
|
||||
MONO_SOURCE_ROOT = abspath(args.mono_sources)
|
||||
|
||||
_ANDROID_API_VERSION = args.android_api_version
|
||||
_ANDROID_CMAKE_VERSION = args.android_cmake_version
|
||||
|
||||
|
||||
def main(raw_args):
|
||||
import argparse
|
||||
|
||||
from collections import OrderedDict
|
||||
from textwrap import dedent
|
||||
|
||||
target_indiv_values = ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64']
|
||||
target_values = target_indiv_values + ['all']
|
||||
|
||||
actions = OrderedDict()
|
||||
actions['configure'] = configure
|
||||
actions['make'] = make
|
||||
actions['clean'] = clean
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Builds the Mono runtime for Android',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=dedent('''\
|
||||
environment variables:
|
||||
ANDROID_SDK_ROOT: Overrides default value for --android-sdk
|
||||
ANDROID_NDK_ROOT: Overrides default value for --android-ndk
|
||||
MONO_SOURCE_ROOT: Overrides default value for --mono-sources
|
||||
ANDROID_HOME: Same as ANDROID_SDK_ROOT
|
||||
''')
|
||||
)
|
||||
|
||||
def custom_bool(val):
|
||||
if isinstance(val, bool):
|
||||
return val
|
||||
if val.lower() in ('yes', 'true', 't', 'y', '1'):
|
||||
return True
|
||||
elif val.lower() in ('no', 'false', 'f', 'n', '0'):
|
||||
return False
|
||||
else:
|
||||
raise argparse.ArgumentTypeError('Boolean value expected.')
|
||||
|
||||
home = environ.get('HOME')
|
||||
android_sdk_default = environ.get('ANDROID_HOME', environ.get('ANDROID_SDK_ROOT', path_join(home, 'Android/Sdk')))
|
||||
android_ndk_default = environ.get('ANDROID_NDK_ROOT', path_join(android_sdk_default, 'ndk-bundle'))
|
||||
mono_sources_default = environ.get('MONO_SOURCE_ROOT', '')
|
||||
|
||||
default_help = dedent('default: %(default)s')
|
||||
|
||||
parser.add_argument('action', choices=['configure', 'make', 'clean'])
|
||||
parser.add_argument('--target', choices=target_values, action='append', required=True)
|
||||
parser.add_argument('--configuration', choices=['release', 'debug'], default='release', help=default_help)
|
||||
parser.add_argument('--toolchains-prefix', default=path_join(home, 'android-toolchains'), help=default_help)
|
||||
parser.add_argument('--android-sdk', default=android_sdk_default, help=default_help)
|
||||
parser.add_argument('--android-ndk', default=android_ndk_default, help=default_help)
|
||||
parser.add_argument('--android-api-version', default='18', help=default_help)
|
||||
parser.add_argument('--android-cmake-version', default='autodetect', help=default_help)
|
||||
parser.add_argument('--enable-cxx', action='store_true', default=False, help=default_help)
|
||||
parser.add_argument('--verbose-make', action='store_true', default=False, help=default_help)
|
||||
parser.add_argument('--strip-libs', type=custom_bool, default=True, help=default_help)
|
||||
parser.add_argument('--with-monodroid', type=custom_bool, default=True, help=default_help)
|
||||
parser.add_argument('--configure-dir', default=path_join(home, 'mono-configs'), help=default_help)
|
||||
parser.add_argument('--install-dir', default=path_join(home, 'mono-installs'), help=default_help)
|
||||
|
||||
if mono_sources_default:
|
||||
parser.add_argument('--mono-sources', default=mono_sources_default, help=default_help)
|
||||
else:
|
||||
parser.add_argument('--mono-sources', required=True)
|
||||
|
||||
args = parser.parse_args(raw_args)
|
||||
|
||||
action = args.action
|
||||
targets = args.target
|
||||
|
||||
set_arguments(args)
|
||||
|
||||
if not isdir(MONO_SOURCE_ROOT):
|
||||
print('Mono sources directory not found: ' + MONO_SOURCE_ROOT)
|
||||
exit(1)
|
||||
|
||||
android_targets = []
|
||||
|
||||
if 'all' in targets:
|
||||
android_targets = target_indiv_values[:]
|
||||
else:
|
||||
for target in targets:
|
||||
if not target in android_targets:
|
||||
android_targets += [target]
|
||||
|
||||
action_fn = actions[action]
|
||||
|
||||
try:
|
||||
for target in android_targets:
|
||||
action_fn('android', target)
|
||||
except MonoBuildError as e:
|
||||
exit(e.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sys import argv
|
||||
main(argv[1:])
|
80
cmd_utils.py
Normal file
80
cmd_utils.py
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
|
||||
def custom_bool(val):
|
||||
if isinstance(val, bool):
|
||||
return val
|
||||
if val.lower() in ('yes', 'true', 't', 'y', '1'):
|
||||
return True
|
||||
elif val.lower() in ('no', 'false', 'f', 'n', '0'):
|
||||
return False
|
||||
else:
|
||||
from argparse import ArgumentTypeError
|
||||
raise ArgumentTypeError('Boolean value expected.')
|
||||
|
||||
|
||||
def build_arg_parser(description, env_vars={}):
|
||||
from argparse import ArgumentParser, RawDescriptionHelpFormatter
|
||||
from textwrap import dedent
|
||||
|
||||
base_env_vars = {
|
||||
'MONO_SOURCE_ROOT': 'Overrides default value for --mono-sources',
|
||||
}
|
||||
|
||||
env_vars_text = '\n'.join([' %s: %s' % (var, desc) for var, desc in env_vars.items()])
|
||||
base_env_vars_text = '\n'.join([' %s: %s' % (var, desc) for var, desc in base_env_vars.items()])
|
||||
|
||||
epilog=dedent('''\
|
||||
environment variables:
|
||||
%s
|
||||
%s
|
||||
''' % (env_vars_text, base_env_vars_text))
|
||||
|
||||
return ArgumentParser(
|
||||
description=description,
|
||||
formatter_class=RawDescriptionHelpFormatter,
|
||||
epilog=epilog
|
||||
)
|
||||
|
||||
|
||||
def add_base_arguments(parser, default_help):
|
||||
import os
|
||||
from os.path import join as path_join
|
||||
|
||||
home = os.environ.get('HOME')
|
||||
mono_sources_default = os.environ.get('MONO_SOURCE_ROOT', '')
|
||||
|
||||
parser.add_argument('--verbose-make', action='store_true', default=False, help=default_help)
|
||||
parser.add_argument('--configure-dir', default=path_join(home, 'mono-configs'), help=default_help)
|
||||
parser.add_argument('--install-dir', default=path_join(home, 'mono-installs'), help=default_help)
|
||||
|
||||
if mono_sources_default:
|
||||
parser.add_argument('--mono-sources', default=mono_sources_default, help=default_help)
|
||||
else:
|
||||
parser.add_argument('--mono-sources', required=True)
|
||||
|
||||
parser.add_argument('--mxe-prefix', default='/usr', help=default_help)
|
||||
|
||||
|
||||
def add_runtime_arguments(parser, default_help):
|
||||
add_base_arguments(parser, default_help)
|
||||
|
||||
parser.add_argument('--configuration', choices=['release', 'debug'], default='release', help=default_help)
|
||||
parser.add_argument('--enable-cxx', action='store_true', default=False, help=default_help)
|
||||
parser.add_argument('--strip-libs', type=custom_bool, default=True, help='Strip the libraries if possible after running make.\n' + default_help)
|
||||
|
||||
|
||||
def expand_input_targets(input_targets, target_shortcuts=[]):
|
||||
targets = []
|
||||
|
||||
for shortcut in target_shortcuts.keys():
|
||||
if shortcut in input_targets:
|
||||
targets += target_shortcuts[shortcut][:]
|
||||
|
||||
# The shortcuts options ('all-*') have already been handled. Remove them this way as there may be duplicates.
|
||||
input_targets = [t for t in input_targets if not t in target_shortcuts]
|
||||
|
||||
for target in input_targets:
|
||||
if not target in targets:
|
||||
targets += [target]
|
||||
|
||||
return targets
|
188
desktop.py
Executable file
188
desktop.py
Executable file
@ -0,0 +1,188 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
from os.path import join as path_join
|
||||
|
||||
from options import *
|
||||
from os_utils import *
|
||||
import runtime
|
||||
|
||||
# TODO: mono cross-compilers
|
||||
|
||||
target_platforms = ['linux', 'windows', 'osx']
|
||||
|
||||
targets = {
|
||||
'linux': ['i686', 'x86_64'],
|
||||
'windows': ['i686', 'x86_64'],
|
||||
'osx': ['x86_64']
|
||||
}
|
||||
|
||||
host_triples = {
|
||||
'linux': '%s-linux-gnu',
|
||||
'windows': '%s-w64-mingw32',
|
||||
'osx': '%s-apple-darwin',
|
||||
}
|
||||
|
||||
|
||||
def is_cross_compiling(target_platform: str) -> bool:
|
||||
return (sys.platform == 'darwin' and target_platform != 'osx') or \
|
||||
(sys.platform in ['linux', 'linux2', 'cygwin'] and target_platform != 'linux')
|
||||
|
||||
|
||||
def setup_desktop_template(env: dict, opts: RuntimeOpts, product: str, target_platform: str, target: str):
|
||||
host_triple = host_triples[target_platform] % target
|
||||
|
||||
CONFIGURE_FLAGS = [
|
||||
'--disable-boehm',
|
||||
'--disable-iconv',
|
||||
'--disable-mcs-build',
|
||||
'--disable-nls',
|
||||
'--enable-dynamic-btls',
|
||||
'--enable-maintainer-mode',
|
||||
'--with-sigaltstack=yes',
|
||||
'--with-tls=pthread',
|
||||
'--without-ikvm-native'
|
||||
]
|
||||
|
||||
if target_platform == 'windows':
|
||||
mxe_bin = path_join(opts.mxe_prefix, 'bin')
|
||||
|
||||
env['_%s-%s_PATH' % (product, target)] = mxe_bin
|
||||
|
||||
name_fmt = target + '-w64-mingw32-%s'
|
||||
|
||||
env['_%s-%s_AR' % (product, target)] = path_join(mxe_bin, name_fmt % 'ar')
|
||||
env['_%s-%s_AS' % (product, target)] = path_join(mxe_bin, name_fmt % 'as')
|
||||
env['_%s-%s_CC' % (product, target)] = path_join(mxe_bin, name_fmt % 'gcc')
|
||||
env['_%s-%s_CXX' % (product, target)] = path_join(mxe_bin, name_fmt % 'g++')
|
||||
env['_%s-%s_DLLTOOL' % (product, target)] = path_join(mxe_bin, name_fmt % 'dlltool')
|
||||
env['_%s-%s_LD' % (product, target)] = path_join(mxe_bin, name_fmt % 'ld')
|
||||
env['_%s-%s_OBJDUMP' % (product, target)] = path_join(mxe_bin, name_fmt % 'objdump')
|
||||
env['_%s-%s_RANLIB' % (product, target)] = path_join(mxe_bin, name_fmt % 'ranlib')
|
||||
env['_%s-%s_STRIP' % (product, target)] = path_join(mxe_bin, name_fmt % 'strip')
|
||||
|
||||
CONFIGURE_FLAGS += [
|
||||
'--enable-static-gcc-libs'
|
||||
]
|
||||
else:
|
||||
env['_%s-%s_CC' % (product, target)] = 'cc'
|
||||
|
||||
env['_%s-%s_CONFIGURE_FLAGS' % (product, target)] = CONFIGURE_FLAGS
|
||||
|
||||
runtime.setup_runtime_template(env, opts, product, target, host_triple)
|
||||
|
||||
|
||||
def strip_libs(opts: RuntimeOpts, product: str, target_platform: str, target: str):
|
||||
if is_cross_compiling(target_platform):
|
||||
if target_platform == 'windows':
|
||||
mxe_bin = path_join(opts.mxe_prefix, 'bin')
|
||||
name_fmt = target + '-w64-mingw32-%s'
|
||||
strip = path_join(mxe_bin, name_fmt % 'strip')
|
||||
elif target_platform == 'osx':
|
||||
assert False # TODO osxcross
|
||||
else:
|
||||
strip = 'strip'
|
||||
|
||||
install_dir = path_join(opts.install_dir, '%s-%s-%s' % (product, target, opts.configuration))
|
||||
out_libs_dir = path_join(install_dir, 'lib')
|
||||
|
||||
lib_files = globs(('*.a', '*.so'), dirpath=out_libs_dir)
|
||||
if len(lib_files):
|
||||
run_command(strip, args=['--strip-unneeded'] + lib_files, name='strip')
|
||||
|
||||
if target_platform == 'windows':
|
||||
out_bin_dir = path_join(install_dir, 'bin')
|
||||
|
||||
dll_files = globs(('*.dll',), dirpath=out_bin_dir)
|
||||
if len(dll_files):
|
||||
run_command(strip, args=['--strip-unneeded'] + dll_files, name='strip')
|
||||
|
||||
|
||||
def configure(opts: RuntimeOpts, product: str, target_platform: str, target: str):
|
||||
env = {}
|
||||
|
||||
setup_desktop_template(env, opts, product, target_platform, target)
|
||||
|
||||
if not os.path.isfile(path_join(opts.mono_source_root, 'configure')):
|
||||
runtime.run_autogen(opts)
|
||||
|
||||
runtime.run_configure(env, opts, product, target)
|
||||
|
||||
|
||||
def make(opts: RuntimeOpts, product: str, target_platform: str, target: str):
|
||||
build_dir = path_join(opts.configure_dir, '%s-%s-%s' % (product, target, opts.configuration))
|
||||
|
||||
make_args = ['-C', build_dir]
|
||||
make_args += ['V=1'] if opts.verbose_make else []
|
||||
|
||||
run_command('make', args=make_args, name='make')
|
||||
run_command('make', args=['-C', '%s/mono' % build_dir, 'install'], name='make install mono')
|
||||
run_command('make', args=['-C', '%s/support' % build_dir, 'install'], name='make install support')
|
||||
|
||||
if opts.strip_libs:
|
||||
strip_libs(opts, product, target_platform, target)
|
||||
|
||||
|
||||
def clean(opts: RuntimeOpts, product: str, target_platform: str, target: str):
|
||||
rm_rf(
|
||||
path_join(opts.configure_dir, '%s-%s-%s' % (product, target, opts.configuration)),
|
||||
path_join(opts.configure_dir, '%s-%s-%s.config.cache' % (product, target, opts.configuration)),
|
||||
path_join(opts.install_dir, '%s-%s-%s' % (product, target, opts.configuration))
|
||||
)
|
||||
|
||||
|
||||
def main(raw_args):
|
||||
import cmd_utils
|
||||
from collections import OrderedDict
|
||||
from typing import Callable
|
||||
|
||||
actions = OrderedDict()
|
||||
actions['configure'] = configure
|
||||
actions['make'] = make
|
||||
actions['clean'] = clean
|
||||
|
||||
parser = cmd_utils.build_arg_parser(description='Builds the Mono runtime for the Desktop')
|
||||
subparsers = parser.add_subparsers(dest='platform')
|
||||
|
||||
default_help = 'default: %(default)s'
|
||||
|
||||
for target_platform in target_platforms:
|
||||
target_platform_subparser = subparsers.add_parser(target_platform)
|
||||
target_platform_subparser.add_argument('action', choices=['configure', 'make', 'clean'])
|
||||
target_platform_subparser.add_argument('--target', choices=targets[target_platform], action='append', required=True)
|
||||
|
||||
cmd_utils.add_runtime_arguments(parser, default_help)
|
||||
|
||||
args = parser.parse_args(raw_args)
|
||||
|
||||
input_action = args.action
|
||||
input_target_platform = args.platform
|
||||
input_targets = args.target
|
||||
|
||||
opts = runtime_opts_from_args(args)
|
||||
|
||||
if not os.path.isdir(opts.mono_source_root):
|
||||
print('Mono sources directory not found: ' + opts.mono_source_root)
|
||||
sys.exit(1)
|
||||
|
||||
if is_cross_compiling(input_target_platform) and input_target_platform == 'osx':
|
||||
raise RuntimeError('Cross-compiling for macOS is not currently supported') # TODO: osxcross
|
||||
|
||||
if is_cross_compiling(input_target_platform) and sys.platform == 'darwin':
|
||||
raise RuntimeError('Cross-compiling from macOS is not supported')
|
||||
|
||||
action = actions[input_action]
|
||||
|
||||
try:
|
||||
for target in input_targets:
|
||||
action(opts, 'desktop-%s' % input_target_platform, input_target_platform, target)
|
||||
except BuildError as e:
|
||||
sys.exit(e.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sys import argv
|
||||
main(argv[1:])
|
118
llvm.py
Executable file
118
llvm.py
Executable file
@ -0,0 +1,118 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from os.path import join as path_join
|
||||
from options import *
|
||||
from os_utils import *
|
||||
|
||||
|
||||
target_values = ['llvm64', 'llvmwin64']
|
||||
mxe_targets = {'llvmwin64': {'arch': 'x86_64', 'mxe': 'mxe-Win64'}}
|
||||
|
||||
|
||||
def make(opts: BaseOpts, target: str):
|
||||
stamp_file = path_join(opts.configure_dir, '.stamp-%s-make' % target)
|
||||
|
||||
if os.path.isfile(stamp_file):
|
||||
return
|
||||
|
||||
build_dir = path_join(opts.configure_dir, 'llvm-%s' % target)
|
||||
install_dir = path_join(opts.install_dir, 'llvm-%s' % target)
|
||||
|
||||
mkdir_p(build_dir)
|
||||
mkdir_p(install_dir)
|
||||
|
||||
CMAKE_ARGS = []
|
||||
|
||||
if target in mxe_targets:
|
||||
mxe = mxe_targets[target]['mxe']
|
||||
arch = mxe_targets[target]['arch']
|
||||
|
||||
CMAKE_ARGS += [
|
||||
'-DCMAKE_EXE_LINKER_FLAGS="-static"',
|
||||
'-DCROSS_TOOLCHAIN_FLAGS_NATIVE=-DCMAKE_TOOLCHAIN_FILE=%s/external/llvm/cmake/modules/NATIVE.cmake' % opts.mono_source_root,
|
||||
'-DCMAKE_TOOLCHAIN_FILE=%s/external/llvm/cmake/modules/%s.cmake' % (opts.mono_source_root, mxe),
|
||||
'-DLLVM_ENABLE_THREADS=Off',
|
||||
'-DLLVM_BUILD_EXECUTION_ENGINE=Off'
|
||||
]
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
mingw_zlib_prefix = '%s/opt/mingw-zlib/usr' % opts.mxe_prefix
|
||||
if not os.path.isfile(mingw_zlib_prefix):
|
||||
mingw_zlib_prefix = opts.mxe_prefix
|
||||
|
||||
CMAKE_ARGS += [
|
||||
'-DZLIB_ROOT=%s/%s-w64-mingw32' % (mingw_zlib_prefix, arch),
|
||||
'-DZLIB_LIBRARY=%s/%s-w64-mingw32/lib/libz.a' % (mingw_zlib_prefix, arch),
|
||||
'-DZLIB_INCLUDE_DIR=%s/%s-w64-mingw32/include' % (mingw_zlib_prefix, arch)
|
||||
]
|
||||
|
||||
replace_in_new_file(
|
||||
src_file='%s/sdks/builds/%s.cmake.in' % (opts.mono_source_root, mxe),
|
||||
search='@MXE_PATH@', replace=opts.mxe_prefix,
|
||||
dst_file='%s/external/llvm/cmake/modules/%s.cmake' % (opts.mono_source_root, mxe)
|
||||
)
|
||||
|
||||
CMAKE_ARGS += [os.environ.get('llvm-%s_CMAKE_ARGS' % target, '')]
|
||||
|
||||
make_args = [
|
||||
'-C', '%s/llvm' % opts.mono_source_root,
|
||||
'-f', 'build.mk', 'install-llvm',
|
||||
'LLVM_BUILD=%s' % build_dir,
|
||||
'LLVM_PREFIX=%s' % install_dir,
|
||||
'LLVM_CMAKE_ARGS=%s' % ' '.join([a for a in CMAKE_ARGS if a])
|
||||
]
|
||||
|
||||
make_args += ['V=1'] if opts.verbose_make else []
|
||||
|
||||
run_command('make', args=make_args, name='make')
|
||||
|
||||
touch(stamp_file)
|
||||
|
||||
|
||||
def clean(opts: BaseOpts, target: str):
|
||||
build_dir = path_join(opts.configure_dir, 'llvm-%s' % target)
|
||||
install_dir = path_join(opts.install_dir, 'llvm-%s' % target)
|
||||
stamp_file = path_join(opts.configure_dir, '.stamp-%s-make' % target)
|
||||
|
||||
rm_rf(stamp_file)
|
||||
|
||||
make_args = [
|
||||
'-C', '%s/llvm' % opts.mono_source_root,
|
||||
'-f', 'build.mk', 'clean-llvm',
|
||||
'LLVM_BUILD=%s' % build_dir,
|
||||
'LLVM_PREFIX=%s' % install_dir
|
||||
]
|
||||
|
||||
make_args += ['V=1'] if opts.verbose_make else []
|
||||
|
||||
run_command('make', args=make_args, name='make clean')
|
||||
|
||||
|
||||
def main(raw_args):
|
||||
import cmd_utils
|
||||
|
||||
parser = cmd_utils.build_arg_parser(description='Builds LLVM for Mono')
|
||||
|
||||
default_help = 'default: %(default)s'
|
||||
|
||||
parser.add_argument('action', choices=['make', 'clean'])
|
||||
parser.add_argument('--target', choices=target_values, action='append', required=True)
|
||||
|
||||
cmd_utils.add_base_arguments(parser, default_help)
|
||||
|
||||
args = parser.parse_args(raw_args)
|
||||
|
||||
opts = base_opts_from_args(args)
|
||||
targets = args.target
|
||||
|
||||
for target in targets:
|
||||
action = { 'make': make, 'clean': clean }[args.action]
|
||||
action(opts, target)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sys import argv
|
||||
main(argv[1:])
|
79
options.py
Normal file
79
options.py
Normal file
@ -0,0 +1,79 @@
|
||||
|
||||
from dataclasses import dataclass
|
||||
from os.path import abspath
|
||||
|
||||
|
||||
@dataclass
|
||||
class BaseOpts:
|
||||
verbose_make: bool
|
||||
configure_dir: str
|
||||
install_dir: str
|
||||
mono_source_root: str
|
||||
mxe_prefix: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class RuntimeOpts(BaseOpts):
|
||||
configuration: str
|
||||
release: bool
|
||||
enable_cxx: bool
|
||||
strip_libs: bool
|
||||
|
||||
|
||||
@dataclass
|
||||
class AndroidOpts(RuntimeOpts):
|
||||
android_toolchains_prefix: str
|
||||
android_sdk_root: str
|
||||
android_ndk_root: str
|
||||
with_monodroid: bool
|
||||
android_api_version: str
|
||||
android_cmake_version: str
|
||||
toolchain_name_fmt: str = '%s-api%s-clang'
|
||||
|
||||
|
||||
@dataclass
|
||||
class BclOpts(BaseOpts):
|
||||
tests: bool
|
||||
|
||||
|
||||
# Need to make paths absolute as we change cwd
|
||||
|
||||
|
||||
def base_opts_from_args(args):
|
||||
from os.path import abspath
|
||||
return BaseOpts(
|
||||
verbose_make = args.verbose_make,
|
||||
configure_dir = abspath(args.configure_dir),
|
||||
install_dir = abspath(args.install_dir),
|
||||
mono_source_root = abspath(args.mono_sources),
|
||||
mxe_prefix = args.mxe_prefix
|
||||
)
|
||||
|
||||
|
||||
def runtime_opts_from_args(args):
|
||||
return RuntimeOpts(
|
||||
**vars(base_opts_from_args(args)),
|
||||
configuration = args.configuration,
|
||||
release = (args.configuration == 'release'),
|
||||
enable_cxx = args.enable_cxx,
|
||||
strip_libs = args.strip_libs
|
||||
)
|
||||
|
||||
|
||||
def android_opts_from_args(args):
|
||||
return AndroidOpts(
|
||||
**vars(runtime_opts_from_args(args)),
|
||||
android_toolchains_prefix = abspath(args.toolchains_prefix),
|
||||
android_sdk_root = abspath(args.android_sdk),
|
||||
android_ndk_root = abspath(args.android_ndk),
|
||||
with_monodroid = args.with_monodroid,
|
||||
android_api_version = args.android_api_version,
|
||||
android_cmake_version = args.android_cmake_version
|
||||
)
|
||||
|
||||
|
||||
def bcl_opts_from_args(args):
|
||||
return BclOpts(
|
||||
**vars(base_opts_from_args(args)),
|
||||
tests = args.tests
|
||||
)
|
137
os_utils.py
Normal file
137
os_utils.py
Normal file
@ -0,0 +1,137 @@
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
|
||||
class BuildError(Exception):
|
||||
'''Generic exception for custom build errors'''
|
||||
def __init__(self, msg):
|
||||
super(BuildError, self).__init__(msg)
|
||||
self.message = msg
|
||||
|
||||
|
||||
def run_command(command, args=[], cwd=None, env=None, name='command'):
|
||||
def cmd_args_to_str(cmd_args):
|
||||
return ' '.join([arg if not ' ' in arg else '"%s"' % arg for arg in cmd_args])
|
||||
|
||||
assert isinstance(command, str) and isinstance(args, list)
|
||||
args = [command] + args
|
||||
|
||||
check_call_args = {}
|
||||
if cwd is not None:
|
||||
check_call_args['cwd'] = cwd
|
||||
if env is not None:
|
||||
check_call_args['env'] = env
|
||||
|
||||
import subprocess
|
||||
try:
|
||||
print('Running command \'%s\': %s' % (name, subprocess.list2cmdline(args)))
|
||||
subprocess.check_call(args, **check_call_args)
|
||||
print('Command \'%s\' completed successfully' % name)
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise BuildError('\'%s\' exited with error code: %s' % (name, e.returncode))
|
||||
|
||||
|
||||
def source(script: str, cwd=None) -> dict:
|
||||
popen_args = {}
|
||||
if cwd is not None:
|
||||
popen_args['cwd'] = cwd
|
||||
|
||||
import subprocess
|
||||
proc = subprocess.Popen('bash -c \'source %s; env -0\'' % script, stdout=subprocess.PIPE, shell=True, **popen_args)
|
||||
output = proc.communicate()[0]
|
||||
return dict(line.split('=', 1) for line in output.decode().split('\x00') if line)
|
||||
|
||||
|
||||
# Creates the directory if no other file or directory with the same path exists
|
||||
def mkdir_p(path):
|
||||
if not os.path.exists(path):
|
||||
print('creating directory: ' + path)
|
||||
os.makedirs(path)
|
||||
|
||||
|
||||
# Remove files and/or directories recursively
|
||||
def rm_rf(*paths):
|
||||
from shutil import rmtree
|
||||
for path in paths:
|
||||
if os.path.isfile(path):
|
||||
print('removing file: ' + path)
|
||||
os.remove(path)
|
||||
elif os.path.isdir(path):
|
||||
print('removing directory and its contents: ' + path)
|
||||
rmtree(path)
|
||||
|
||||
|
||||
ENV_PATH_SEP = ';' if os.name == 'nt' else ':'
|
||||
|
||||
|
||||
def find_executable(name) -> str:
|
||||
is_windows = os.name == 'nt'
|
||||
windows_exts = ENV_PATH_SEP.split(os.environ['PATHEXT']) if is_windows else None
|
||||
path_dirs = ENV_PATH_SEP.split(os.environ['PATH'])
|
||||
|
||||
search_dirs = path_dirs + [os.getcwd()] # cwd is last in the list
|
||||
|
||||
for dir in search_dirs:
|
||||
path = os.path.join(dir, name)
|
||||
|
||||
if is_windows:
|
||||
for extension in windows_exts:
|
||||
path_with_ext = path + extension
|
||||
|
||||
if os.path.isfile(path_with_ext) and os.access(path_with_ext, os.X_OK):
|
||||
return path_with_ext
|
||||
else:
|
||||
if os.path.isfile(path) and os.access(path, os.X_OK):
|
||||
return path
|
||||
|
||||
return ''
|
||||
|
||||
|
||||
def replace_in_new_file(src_file, search, replace, dst_file):
|
||||
with open(src_file, 'r') as file:
|
||||
content = file.read()
|
||||
|
||||
content = content.replace(search, replace)
|
||||
|
||||
with open(dst_file, 'w') as file:
|
||||
file.write(content)
|
||||
|
||||
|
||||
def replace_in_file(filepath, search, replace):
|
||||
replace_in_new_file(src_file=filepath, search=search, replace=replace, dst_file=filepath)
|
||||
|
||||
|
||||
def touch(filepath: str):
|
||||
import pathlib
|
||||
pathlib.Path(filepath).touch()
|
||||
|
||||
|
||||
def get_emsdk_root():
|
||||
# Shamelessly copied from Godot's detect.py
|
||||
em_config_file = os.getenv('EM_CONFIG') or os.path.expanduser('~/.emscripten')
|
||||
if not os.path.exists(em_config_file):
|
||||
raise BuildError("Emscripten configuration file '%s' does not exist" % em_config_file)
|
||||
with open(em_config_file) as f:
|
||||
em_config = {}
|
||||
try:
|
||||
# Emscripten configuration file is a Python file with simple assignments.
|
||||
exec(f.read(), em_config)
|
||||
except StandardError as e:
|
||||
raise BuildError("Emscripten configuration file '%s' is invalid:\n%s" % (em_config_file, e))
|
||||
if 'BINARYEN_ROOT' in em_config and os.path.isdir(os.path.join(em_config.get('BINARYEN_ROOT'), 'emscripten')):
|
||||
# New style, emscripten path as a subfolder of BINARYEN_ROOT
|
||||
return os.path.join(em_config.get('BINARYEN_ROOT'), 'emscripten')
|
||||
elif 'EMSCRIPTEN_ROOT' in em_config:
|
||||
# Old style (but can be there as a result from previous activation, so do last)
|
||||
return em_config.get('EMSCRIPTEN_ROOT')
|
||||
else:
|
||||
raise BuildError("'BINARYEN_ROOT' or 'EMSCRIPTEN_ROOT' missing in Emscripten configuration file '%s'" % em_config_file)
|
||||
|
||||
|
||||
def globs(pathnames, dirpath='.'):
|
||||
import glob
|
||||
files = []
|
||||
for pathname in pathnames:
|
||||
files.extend(glob.glob(os.path.join(dirpath, pathname)))
|
||||
return files
|
37
patch_emscripten.py
Executable file
37
patch_emscripten.py
Executable file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
|
||||
def main(raw_args):
|
||||
import os
|
||||
import cmd_utils
|
||||
from os_utils import get_emsdk_root
|
||||
|
||||
parser = cmd_utils.build_arg_parser(description='Apply patches to the active Emscripten SDK')
|
||||
|
||||
default_help = 'default: %(default)s'
|
||||
|
||||
mono_sources_default = os.environ.get('MONO_SOURCE_ROOT', '')
|
||||
|
||||
if mono_sources_default:
|
||||
parser.add_argument('--mono-sources', default=mono_sources_default, help=default_help)
|
||||
else:
|
||||
parser.add_argument('--mono-sources', required=True)
|
||||
|
||||
args = parser.parse_args(raw_args)
|
||||
|
||||
mono_source_root = args.mono_sources
|
||||
emsdk_root = get_emsdk_root()
|
||||
|
||||
patches = [
|
||||
'%s/sdks/builds/fix-emscripten-8511.diff' % mono_source_root,
|
||||
'%s/sdks/builds/emscripten-pr-8457.diff' % mono_source_root
|
||||
]
|
||||
|
||||
from subprocess import Popen
|
||||
for patch in patches:
|
||||
proc = Popen('bash -c \'patch -N -p1 < %s; exit 0\'' % patch, cwd=emsdk_root, shell=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sys import argv
|
||||
main(argv[1:])
|
39
patch_mono.py
Executable file
39
patch_mono.py
Executable file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
|
||||
def main(raw_args):
|
||||
import cmd_utils
|
||||
import os
|
||||
import os.path
|
||||
from os_utils import get_emsdk_root
|
||||
|
||||
parser = cmd_utils.build_arg_parser(description='Apply patches to the Mono source tree')
|
||||
|
||||
default_help = 'default: %(default)s'
|
||||
|
||||
mono_sources_default = os.environ.get('MONO_SOURCE_ROOT', '')
|
||||
|
||||
if mono_sources_default:
|
||||
parser.add_argument('--mono-sources', default=mono_sources_default, help=default_help)
|
||||
else:
|
||||
parser.add_argument('--mono-sources', required=True)
|
||||
|
||||
args = parser.parse_args(raw_args)
|
||||
|
||||
this_script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
patches_dir = os.path.join(this_script_dir, 'patches')
|
||||
|
||||
mono_source_root = args.mono_sources
|
||||
|
||||
patches = [
|
||||
'fix-mono-android-tkill.diff'
|
||||
]
|
||||
|
||||
from subprocess import Popen
|
||||
for patch in patches:
|
||||
proc = Popen('bash -c \'patch -N -p1 < %s; exit 0\'' % os.path.join(patches_dir, patch), cwd=mono_source_root, shell=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sys import argv
|
||||
main(argv[1:])
|
70
patches/fix-mono-android-tkill.diff
Normal file
70
patches/fix-mono-android-tkill.diff
Normal file
@ -0,0 +1,70 @@
|
||||
diff --git a/libgc/include/private/gcconfig.h b/libgc/include/private/gcconfig.h
|
||||
index e2bdf13ac3e..f962200ba4e 100644
|
||||
--- a/libgc/include/private/gcconfig.h
|
||||
+++ b/libgc/include/private/gcconfig.h
|
||||
@@ -2255,6 +2255,14 @@
|
||||
# define GETPAGESIZE() getpagesize()
|
||||
# endif
|
||||
|
||||
+#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \
|
||||
+ && ((defined(MIPS) && (CPP_WORDSZ == 32)) \
|
||||
+ || defined(ARM32) || defined(I386) /* but not x32 */)
|
||||
+ /* tkill() exists only on arm32/mips(32)/x86. */
|
||||
+ /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */
|
||||
+# define USE_TKILL_ON_ANDROID
|
||||
+#endif
|
||||
+
|
||||
# if defined(SUNOS5) || defined(DRSNX) || defined(UTS4)
|
||||
/* OS has SVR4 generic features. Probably others also qualify. */
|
||||
# define SVR4
|
||||
diff --git a/libgc/pthread_stop_world.c b/libgc/pthread_stop_world.c
|
||||
index f93ce26b562..4a49a6d578c 100644
|
||||
--- a/libgc/pthread_stop_world.c
|
||||
+++ b/libgc/pthread_stop_world.c
|
||||
@@ -336,7 +336,7 @@ void GC_push_all_stacks()
|
||||
pthread_t GC_stopping_thread;
|
||||
int GC_stopping_pid;
|
||||
|
||||
-#ifdef HOST_ANDROID
|
||||
+#ifdef USE_TKILL_ON_ANDROID
|
||||
static
|
||||
int android_thread_kill(pid_t tid, int sig)
|
||||
{
|
||||
diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c
|
||||
index ad9b8823f8f..3542b32b540 100644
|
||||
--- a/mono/metadata/threads.c
|
||||
+++ b/mono/metadata/threads.c
|
||||
@@ -77,8 +77,12 @@ mono_native_thread_join_handle (HANDLE thread_handle, gboolean close_handle);
|
||||
#include <zircon/syscalls.h>
|
||||
#endif
|
||||
|
||||
-#if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
|
||||
-#define USE_TKILL_ON_ANDROID 1
|
||||
+#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \
|
||||
+ && ((defined(MIPS) && (CPP_WORDSZ == 32)) \
|
||||
+ || defined(ARM32) || defined(I386) /* but not x32 */)
|
||||
+ /* tkill() exists only on arm32/mips(32)/x86. */
|
||||
+ /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */
|
||||
+# define USE_TKILL_ON_ANDROID
|
||||
#endif
|
||||
|
||||
#ifdef HOST_ANDROID
|
||||
diff --git a/mono/utils/mono-threads-posix.c b/mono/utils/mono-threads-posix.c
|
||||
index 3e4bf93de5f..79c9f731fe7 100644
|
||||
--- a/mono/utils/mono-threads-posix.c
|
||||
+++ b/mono/utils/mono-threads-posix.c
|
||||
@@ -31,8 +31,12 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
-#if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
|
||||
-#define USE_TKILL_ON_ANDROID 1
|
||||
+#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \
|
||||
+ && ((defined(MIPS) && (CPP_WORDSZ == 32)) \
|
||||
+ || defined(ARM32) || defined(I386) /* but not x32 */)
|
||||
+ /* tkill() exists only on arm32/mips(32)/x86. */
|
||||
+ /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */
|
||||
+# define USE_TKILL_ON_ANDROID
|
||||
#endif
|
||||
|
||||
#ifdef USE_TKILL_ON_ANDROID
|
62
reference_assemblies.py
Executable file
62
reference_assemblies.py
Executable file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from os.path import join as path_join
|
||||
from options import *
|
||||
from os_utils import *
|
||||
|
||||
|
||||
def build(opts: BaseOpts):
|
||||
build_dir = '%s/mcs/class/reference-assemblies' % opts.mono_source_root
|
||||
install_dir = path_join(opts.install_dir, 'reference-assemblies')
|
||||
|
||||
mkdir_p(install_dir)
|
||||
|
||||
make_args = ['-C', build_dir, 'build-reference-assemblies']
|
||||
make_args += ['V=1'] if opts.verbose_make else []
|
||||
run_command('make', args=make_args, name='make build-reference-assemblies')
|
||||
|
||||
|
||||
def install(opts: BaseOpts):
|
||||
build_dir = '%s/mcs/class/reference-assemblies' % opts.mono_source_root
|
||||
install_dir = path_join(opts.install_dir, 'reference-assemblies')
|
||||
|
||||
mkdir_p(install_dir)
|
||||
|
||||
make_args = ['-C', build_dir, 'install-local', 'DESTDIR=%s' % install_dir, 'prefix=/']
|
||||
make_args += ['V=1'] if opts.verbose_make else []
|
||||
run_command('make', args=make_args, name='make install-local')
|
||||
|
||||
|
||||
def clean(opts: BaseOpts):
|
||||
install_dir = path_join(opts.install_dir, 'reference-assemblies')
|
||||
rm_rf(install_dir)
|
||||
|
||||
|
||||
def main(raw_args):
|
||||
import cmd_utils
|
||||
|
||||
actions = {
|
||||
'build': build,
|
||||
'install': install,
|
||||
'clean': clean
|
||||
}
|
||||
|
||||
parser = cmd_utils.build_arg_parser(description='Copy the reference assemblies')
|
||||
|
||||
default_help = 'default: %(default)s'
|
||||
|
||||
parser.add_argument('action', choices=actions.keys())
|
||||
|
||||
cmd_utils.add_base_arguments(parser, default_help)
|
||||
|
||||
args = parser.parse_args(raw_args)
|
||||
|
||||
opts = base_opts_from_args(args)
|
||||
|
||||
action = actions[args.action]
|
||||
action(opts)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sys import argv
|
||||
main(argv[1:])
|
159
runtime.py
Normal file
159
runtime.py
Normal file
@ -0,0 +1,159 @@
|
||||
|
||||
import os
|
||||
from os.path import join as path_join
|
||||
|
||||
from options import RuntimeOpts
|
||||
from os_utils import *
|
||||
|
||||
|
||||
def setup_runtime_template(env: dict, opts: RuntimeOpts, product: str, target: str, host_triple: str):
|
||||
BITNESS = ''
|
||||
if any(s in host_triple for s in ['i686', 'i386']):
|
||||
BITNESS = '-m32'
|
||||
elif 'x86_64' in host_triple:
|
||||
BITNESS = '-m64'
|
||||
|
||||
CFLAGS = []
|
||||
CFLAGS += ['-O2', '-g'] if opts.release else ['-O0', '-ggdb3', '-fno-omit-frame-pointer']
|
||||
CFLAGS += env.get('_%s-%s_CFLAGS' % (product, target), [])
|
||||
CFLAGS += env.get('%s-%s_CFLAGS' % (product, target), [])
|
||||
CFLAGS += [BITNESS] if BITNESS else []
|
||||
|
||||
CXXFLAGS = []
|
||||
CXXFLAGS += ['-O2', '-g'] if opts.release else ['-O0', '-ggdb3', '-fno-omit-frame-pointer']
|
||||
CXXFLAGS += env.get('_%s-%s_CXXFLAGS' % (product, target), [])
|
||||
CXXFLAGS += env.get('%s-%s_CXXFLAGS' % (product, target), [])
|
||||
CXXFLAGS += [BITNESS] if BITNESS else []
|
||||
|
||||
CPPFLAGS = []
|
||||
CPPFLAGS += ['-O2', '-g'] if opts.release else ['-O0', '-ggdb3', '-fno-omit-frame-pointer']
|
||||
CPPFLAGS += env.get('_%s-%s_CPPFLAGS' % (product, target), [])
|
||||
CPPFLAGS += env.get('%s-%s_CPPFLAGS' % (product, target), [])
|
||||
CPPFLAGS += [BITNESS] if BITNESS else []
|
||||
|
||||
CXXCPPFLAGS = []
|
||||
CXXCPPFLAGS += ['-O2', '-g'] if opts.release else ['-O0', '-ggdb3', '-fno-omit-frame-pointer']
|
||||
CXXCPPFLAGS += env.get('_%s-%s_CXXCPPFLAGS' % (product, target), [])
|
||||
CXXCPPFLAGS += env.get('%s-%s_CXXCPPFLAGS' % (product, target), [])
|
||||
CXXCPPFLAGS += [BITNESS] if BITNESS else []
|
||||
|
||||
LDFLAGS = []
|
||||
LDFLAGS += env.get('_%s-%s_LDFLAGS' % (product, target), [])
|
||||
LDFLAGS += env.get('%s-%s_LDFLAGS' % (product, target), [])
|
||||
|
||||
AC_VARS = []
|
||||
AC_VARS += env.get('_%s-%s_AC_VARS' % (product, target), [])
|
||||
AC_VARS += env.get('%s-%s_AC_VARS' % (product, target), [])
|
||||
|
||||
CONFIGURE_ENVIRONMENT = {}
|
||||
|
||||
def set_product_env_var(var_name):
|
||||
val = env.get('_%s-%s_%s' % (product, target, var_name), '')
|
||||
if val:
|
||||
CONFIGURE_ENVIRONMENT[var_name] = val
|
||||
|
||||
set_product_env_var('AR')
|
||||
set_product_env_var('AS')
|
||||
set_product_env_var('CC')
|
||||
set_product_env_var('CPP')
|
||||
set_product_env_var('CXX')
|
||||
set_product_env_var('CXXCPP')
|
||||
set_product_env_var('DLLTOOL')
|
||||
set_product_env_var('LD')
|
||||
set_product_env_var('OBJDUMP')
|
||||
set_product_env_var('RANLIB')
|
||||
set_product_env_var('CMAKE')
|
||||
set_product_env_var('STRIP')
|
||||
|
||||
CONFIGURE_ENVIRONMENT['CFLAGS'] = CFLAGS
|
||||
CONFIGURE_ENVIRONMENT['CXXFLAGS'] = CXXFLAGS
|
||||
CONFIGURE_ENVIRONMENT['CPPFLAGS'] = CPPFLAGS
|
||||
CONFIGURE_ENVIRONMENT['CXXCPPFLAGS'] = CXXCPPFLAGS
|
||||
CONFIGURE_ENVIRONMENT['LDFLAGS'] = LDFLAGS
|
||||
|
||||
CONFIGURE_ENVIRONMENT.update(env.get('_%s-%s_CONFIGURE_ENVIRONMENT' % (product, target), {}))
|
||||
CONFIGURE_ENVIRONMENT.update(env.get('%s-%s_CONFIGURE_ENVIRONMENT' % (product, target), {}))
|
||||
|
||||
CONFIGURE_FLAGS = []
|
||||
CONFIGURE_FLAGS += ['--host=%s' % host_triple] if host_triple else []
|
||||
CONFIGURE_FLAGS += ['--cache-file=%s/%s-%s-%s.config.cache' % (opts.configure_dir, product, target, opts.configuration)]
|
||||
CONFIGURE_FLAGS += ['--prefix=%s/%s-%s-%s' % (opts.install_dir, product, target, opts.configuration)]
|
||||
CONFIGURE_FLAGS += ['--enable-cxx'] if opts.enable_cxx else []
|
||||
CONFIGURE_FLAGS += env.get('_cross-runtime_%s-%s_CONFIGURE_FLAGS' % (product, target), [])
|
||||
CONFIGURE_FLAGS += env.get('_%s-%s_CONFIGURE_FLAGS' % (product, target), [])
|
||||
CONFIGURE_FLAGS += env.get('%s-%s_CONFIGURE_FLAGS' % (product, target), [])
|
||||
|
||||
env['_runtime_%s-%s_AC_VARS' % (product, target)] = AC_VARS
|
||||
env['_runtime_%s-%s_CONFIGURE_ENVIRONMENT' % (product, target)] = CONFIGURE_ENVIRONMENT
|
||||
env['_runtime_%s-%s_CONFIGURE_FLAGS' % (product, target)] = CONFIGURE_FLAGS
|
||||
|
||||
|
||||
def setup_runtime_cross_template(env: dict, opts: RuntimeOpts, product: str, target: str, host_triple: str,
|
||||
target_triple: str, device_target: str, llvm: str, offsets_dumper_abi: str):
|
||||
CONFIGURE_FLAGS = [
|
||||
'--target=%s' % target_triple,
|
||||
'--with-cross-offsets=%s.h' % target_triple,
|
||||
'--with-llvm=%s/%s' % (opts.install_dir, llvm)
|
||||
]
|
||||
|
||||
env['_cross-runtime_%s-%s_CONFIGURE_FLAGS' % (product, target)] = CONFIGURE_FLAGS
|
||||
|
||||
# Setup offsets-tool-py
|
||||
run_command('make', ['-C', '%s/tools/offsets-tool-py' % opts.mono_source_root, 'setup'], name='make offsets-tool-py')
|
||||
|
||||
# Run offsets-tool in its virtual env
|
||||
|
||||
virtualenv_vars = source('%s/tools/offsets-tool-py/offtool/bin/activate' % opts.mono_source_root)
|
||||
|
||||
offsets_tool_env = os.environ.copy()
|
||||
offsets_tool_env.update(virtualenv_vars)
|
||||
|
||||
build_dir = '%s/%s-%s-%s' % (opts.configure_dir, product, target, opts.configuration)
|
||||
mkdir_p(build_dir)
|
||||
|
||||
run_command('python3', [
|
||||
'%s/tools/offsets-tool-py/offsets-tool.py' % opts.mono_source_root,
|
||||
'--targetdir=%s/%s-%s-%s' % (opts.configure_dir, product, device_target, opts.configuration),
|
||||
'--abi=%s' % offsets_dumper_abi,
|
||||
'--monodir=%s' % opts.mono_source_root,
|
||||
'--outfile=%s/%s.h' % (build_dir, target_triple)
|
||||
] + env['_%s-%s_OFFSETS_DUMPER_ARGS' % (product, target)],
|
||||
env=offsets_tool_env, name='offsets-tool')
|
||||
|
||||
# Runtime template
|
||||
setup_runtime_template(env, opts, product, target, host_triple)
|
||||
|
||||
|
||||
def run_autogen(opts: RuntimeOpts):
|
||||
autogen_env = os.environ.copy()
|
||||
autogen_env['NOCONFIGURE'] = '1'
|
||||
|
||||
if not find_executable('glibtoolize') and 'CUSTOM_GLIBTOOLIZE_PATH' in os.environ:
|
||||
autogen_env['PATH'] = os.environ['CUSTOM_GLIBTOOLIZE_PATH'] + ':' + autogen_env['PATH']
|
||||
|
||||
run_command(os.path.join(opts.mono_source_root, 'autogen.sh'), cwd=opts.mono_source_root, env=autogen_env, name='autogen')
|
||||
|
||||
|
||||
def run_configure(env: dict, opts: RuntimeOpts, product: str, target: str):
|
||||
build_dir = path_join(opts.configure_dir, '%s-%s-%s' % (product, target, opts.configuration))
|
||||
mkdir_p(build_dir)
|
||||
|
||||
def str_dict_val(val):
|
||||
if isinstance(val, list):
|
||||
return ' '.join(val) # Don't need to surround with quotes
|
||||
return val
|
||||
|
||||
ac_vars = env['_runtime_%s-%s_AC_VARS' % (product, target)]
|
||||
configure_env_args = env['_runtime_%s-%s_CONFIGURE_ENVIRONMENT' % (product, target)]
|
||||
configure_env_args = [('%s=%s' % (key, str_dict_val(value))) for (key, value) in configure_env_args.items()]
|
||||
configure_flags = env['_runtime_%s-%s_CONFIGURE_FLAGS' % (product, target)]
|
||||
|
||||
configure = path_join(opts.mono_source_root, 'configure')
|
||||
configure_args = ac_vars + configure_env_args + configure_flags
|
||||
|
||||
configure_env = os.environ.copy()
|
||||
target_extra_path = env.get('_%s-%s_PATH' % (product, target), '')
|
||||
if target_extra_path:
|
||||
configure_env['PATH'] += ':' + target_extra_path
|
||||
|
||||
run_command(configure, args=configure_args, cwd=build_dir, env=configure_env, name='configure')
|
231
wasm.py
Executable file
231
wasm.py
Executable file
@ -0,0 +1,231 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import runtime
|
||||
import sys
|
||||
|
||||
from options import *
|
||||
from os_utils import *
|
||||
from os.path import join as path_join
|
||||
|
||||
|
||||
runtime_targets = ['runtime', 'runtime-threads', 'runtime-dynamic']
|
||||
cross_targets = [] # ['cross'] # TODO
|
||||
cross_mxe_targets = [] # ['cross-win'] # TODO
|
||||
|
||||
|
||||
def is_cross(target) -> bool:
|
||||
return target in cross_targets or is_cross_mxe(target)
|
||||
|
||||
|
||||
def is_cross_mxe(target) -> bool:
|
||||
return target in cross_mxe_targets
|
||||
|
||||
|
||||
def setup_wasm_target_template(env: dict, opts: RuntimeOpts, target: str):
|
||||
extra_target_envs = {
|
||||
'runtime-threads': {
|
||||
'wasm_runtime-threads_CFLAGS': ['-s', 'USE_PTHREADS=1', '-pthread'],
|
||||
'wasm_runtime-threads_CXXFLAGS': ['-s', 'USE_PTHREADS=1', '-pthread']
|
||||
},
|
||||
'runtime-dynamic': {
|
||||
'wasm_runtime-dynamic_CFLAGS': ['-s', 'WASM_OBJECT_FILES=0'],
|
||||
'wasm_runtime-dynamic_CXXFLAGS': ['-s', 'WASM_OBJECT_FILES=0']
|
||||
}
|
||||
}
|
||||
|
||||
if target in extra_target_envs:
|
||||
env.update(extra_target_envs[target])
|
||||
|
||||
CFLAGS = ['-fexceptions']
|
||||
CFLAGS += ['-Os', '-g'] if opts.release else ['-O0', '-ggdb3', '-fno-omit-frame-pointer']
|
||||
CXXFLAGS = CFLAGS + ['-s', 'DISABLE_EXCEPTION_CATCHING=0']
|
||||
|
||||
CONFIGURE_FLAGS = [
|
||||
'--disable-mcs-build',
|
||||
'--disable-nls',
|
||||
'--disable-boehm',
|
||||
'--disable-btls',
|
||||
'--with-lazy-gc-thread-creation=yes',
|
||||
'--with-libgc=none',
|
||||
'--disable-executables',
|
||||
'--disable-support-build',
|
||||
'--disable-visibility-hidden',
|
||||
'--enable-maintainer-mode',
|
||||
'--enable-minimal=ssa,com,jit,reflection_emit_save,portability,assembly_remapping,attach,verifier,full_messages,appdomains,security,sgen_marksweep_conc,sgen_split_nursery,sgen_gc_bridge,logging,remoting,shared_perfcounters,sgen_debug_helpers,soft_debug,interpreter,assert_messages,cleanup,mdb,gac',
|
||||
'--host=wasm32',
|
||||
'--enable-llvm-runtime',
|
||||
'--enable-icall-export',
|
||||
'--disable-icall-tables',
|
||||
'--disable-crash-reporting',
|
||||
'--with-bitcode=yes'
|
||||
]
|
||||
|
||||
CONFIGURE_FLAGS += ['--enable-cxx'] if opts.enable_cxx else []
|
||||
|
||||
CONFIGURE_FLAGS += [
|
||||
'--cache-file=%s/wasm-%s-%s.config.cache' % (opts.configure_dir, target, opts.configuration),
|
||||
'--prefix=%s/wasm-%s-%s' % (opts.install_dir, target, opts.configuration),
|
||||
'CFLAGS=%s %s' % (' '.join(CFLAGS), env.get('wasm_%s_CFLAGS' % target, '')),
|
||||
'CXXFLAGS=%s %s' % (' '.join(CXXFLAGS), env.get('$$(wasm_%s_CXXFLAGS' % target, ''))
|
||||
]
|
||||
|
||||
CONFIGURE_FLAGS += env.get('wasm_%s_CONFIGURE_FLAGS' % target, [])
|
||||
|
||||
env['_wasm_%s_CONFIGURE_FLAGS' % target] = CONFIGURE_FLAGS
|
||||
env['_wasm_%s_AC_VARS' % target] = ['ac_cv_func_shm_open_working_with_mmap=no']
|
||||
|
||||
|
||||
def wasm_run_configure(env: dict, opts: RuntimeOpts, product: str, target: str, emsdk_root: str):
|
||||
build_dir = path_join(opts.configure_dir, '%s-%s-%s' % (product, target, opts.configuration))
|
||||
mkdir_p(build_dir)
|
||||
|
||||
def str_dict_val(val):
|
||||
if isinstance(val, list):
|
||||
return ' '.join(val) # Don't need to surround with quotes
|
||||
return val
|
||||
|
||||
ac_vars = env['_%s_%s_AC_VARS' % (product, target)]
|
||||
configure_flags = env['_%s_%s_CONFIGURE_FLAGS' % (product, target)]
|
||||
|
||||
configure = path_join(opts.mono_source_root, 'configure')
|
||||
configure_args = ac_vars + configure_flags
|
||||
|
||||
configure_env = os.environ.copy()
|
||||
|
||||
target_extra_path = env.get('_%s-%s_PATH' % (product, target), '')
|
||||
if target_extra_path:
|
||||
configure_env['PATH'] += ':' + target_extra_path
|
||||
|
||||
configure_env['PATH'] = emsdk_root + ':' + configure_env['PATH']
|
||||
|
||||
run_command('emconfigure', args=[configure] + configure_args, cwd=build_dir, env=configure_env, name='configure')
|
||||
|
||||
|
||||
def configure(opts: RuntimeOpts, product: str, target: str):
|
||||
env = {}
|
||||
|
||||
if is_cross(target):
|
||||
if is_cross_mxe(target):
|
||||
raise RuntimeError('TODO')
|
||||
else:
|
||||
raise RuntimeError('TODO')
|
||||
else:
|
||||
setup_wasm_target_template(env, opts, target)
|
||||
|
||||
if not os.path.isfile(path_join(opts.mono_source_root, 'configure')):
|
||||
runtime.run_autogen(opts)
|
||||
|
||||
wasm_run_configure(env, opts, product, target, get_emsdk_root())
|
||||
|
||||
|
||||
def make(opts: RuntimeOpts, product: str, target: str):
|
||||
env = {}
|
||||
|
||||
emsdk_root = get_emsdk_root()
|
||||
|
||||
build_dir = path_join(opts.configure_dir, '%s-%s-%s' % (product, target, opts.configuration))
|
||||
install_dir = path_join(opts.install_dir, '%s-%s-%s' % (product, target, opts.configuration))
|
||||
|
||||
make_args = ['-C', build_dir]
|
||||
make_args += ['V=1'] if opts.verbose_make else []
|
||||
|
||||
make_env = os.environ.copy()
|
||||
make_env['PATH'] = emsdk_root + ':' + make_env['PATH']
|
||||
|
||||
run_command('emmake', args=['make'] + make_args, env=make_env, name='make')
|
||||
|
||||
run_command('make', args=['-C', '%s/mono' % build_dir, 'install'], name='make install mono')
|
||||
|
||||
# Copy support headers
|
||||
|
||||
from shutil import copy
|
||||
|
||||
headers = ['crc32.h', 'deflate.h', 'inffast.h', 'inffixed.h', 'inflate.h', 'inftrees.h', 'trees.h', 'zconf.h', 'zlib.h', 'zutil.h']
|
||||
src_support_dir = '%s/support' % opts.mono_source_root
|
||||
dst_support_dir = '%s/include/support' % install_dir
|
||||
|
||||
mkdir_p(dst_support_dir)
|
||||
|
||||
for header in headers:
|
||||
copy(path_join(src_support_dir, header), dst_support_dir)
|
||||
|
||||
# Copy wasm src files
|
||||
|
||||
wasm_src_files = [
|
||||
'driver.c',
|
||||
'zlib-helper.c',
|
||||
'corebindings.c',
|
||||
'pinvoke-tables-default.h',
|
||||
'pinvoke-tables-default-netcore.h',
|
||||
'library_mono.js',
|
||||
'binding_support.js',
|
||||
'dotnet_support.js'
|
||||
]
|
||||
|
||||
dst_wasm_src_dir = path_join(install_dir, 'src')
|
||||
|
||||
mkdir_p(dst_wasm_src_dir)
|
||||
|
||||
for wasm_src_file in wasm_src_files:
|
||||
copy(path_join(opts.mono_source_root, 'sdks/wasm/src', wasm_src_file), dst_wasm_src_dir)
|
||||
|
||||
|
||||
def clean(opts: RuntimeOpts, product: str, target: str):
|
||||
rm_rf(
|
||||
path_join(opts.configure_dir, '%s-%s-%s' % (product, target, opts.configuration)),
|
||||
path_join(opts.configure_dir, '%s-%s-%s.config.cache' % (product, target, opts.configuration)),
|
||||
path_join(opts.install_dir, '%s-%s-%s' % (product, target, opts.configuration))
|
||||
)
|
||||
|
||||
|
||||
def main(raw_args):
|
||||
import cmd_utils
|
||||
from collections import OrderedDict
|
||||
from typing import Callable
|
||||
|
||||
target_shortcuts = {'all-runtime': runtime_targets}
|
||||
|
||||
target_values = runtime_targets + cross_targets + cross_mxe_targets + list(target_shortcuts)
|
||||
|
||||
actions = OrderedDict()
|
||||
actions['configure'] = configure
|
||||
actions['make'] = make
|
||||
actions['clean'] = clean
|
||||
|
||||
parser = cmd_utils.build_arg_parser(description='Builds the Mono runtime for WebAssembly')
|
||||
|
||||
emsdk_root_default = os.environ.get('EMSDK_ROOT', default='')
|
||||
|
||||
default_help = 'default: %(default)s'
|
||||
|
||||
parser.add_argument('action', choices=['configure', 'make', 'clean'])
|
||||
parser.add_argument('--target', choices=target_values, action='append', required=True)
|
||||
|
||||
cmd_utils.add_runtime_arguments(parser, default_help)
|
||||
|
||||
args = parser.parse_args(raw_args)
|
||||
|
||||
input_action = args.action
|
||||
input_targets = args.target
|
||||
|
||||
opts = runtime_opts_from_args(args)
|
||||
|
||||
if not os.path.isdir(opts.mono_source_root):
|
||||
print('Mono sources directory not found: ' + opts.mono_source_root)
|
||||
sys.exit(1)
|
||||
|
||||
targets = cmd_utils.expand_input_targets(input_targets, target_shortcuts)
|
||||
action = actions[input_action]
|
||||
|
||||
try:
|
||||
for target in targets:
|
||||
action(opts, 'wasm', target)
|
||||
except BuildError as e:
|
||||
sys.exit(e.message)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sys import argv
|
||||
main(argv[1:])
|
Loading…
Reference in New Issue
Block a user