From 9251e3bf2ca607b3d6778c246c708916a29aaa88 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Wed, 19 Jun 2019 21:56:00 +0300 Subject: Add basic Webassembly support via Emscripten. --- cross/wasm.txt | 19 +++++++++++++++++++ docs/markdown/Reference-tables.md | 4 ++++ docs/markdown/snippets/wasm.md | 5 +++++ mesonbuild/build.py | 2 ++ mesonbuild/compilers/__init__.py | 2 ++ mesonbuild/compilers/c.py | 25 +++++++++++++++++++++++++ mesonbuild/compilers/compilers.py | 1 + mesonbuild/compilers/cpp.py | 35 ++++++++++++++++++++++++++++++++++- mesonbuild/envconfig.py | 3 +++ mesonbuild/environment.py | 7 +++++++ mesonbuild/minstall.py | 7 +++++++ test cases/wasm/1 basic/hello.cpp | 7 +++++++ test cases/wasm/1 basic/hello.html | 8 ++++++++ test cases/wasm/1 basic/meson.build | 3 +++ 14 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 cross/wasm.txt create mode 100644 docs/markdown/snippets/wasm.md create mode 100644 test cases/wasm/1 basic/hello.cpp create mode 100644 test cases/wasm/1 basic/hello.html create mode 100644 test cases/wasm/1 basic/meson.build diff --git a/cross/wasm.txt b/cross/wasm.txt new file mode 100644 index 000000000..a43636fde --- /dev/null +++ b/cross/wasm.txt @@ -0,0 +1,19 @@ +[binaries] +c = '/home/jpakkane/emsdk/fastcomp/emscripten/emcc' +cpp = '/home/jpakkane/emsdk/fastcomp/emscripten/em++' +ar = '/home/jpakkane/emsdk/fastcomp/emscripten/emar' + +[properties] + +c_args = ['-s', 'WASM=1', '-s', 'EXPORT_ALL=1'] +c_link_args = ['-s','EXPORT_ALL=1'] +cpp_args = ['-s', 'WASM=1', '-s', 'EXPORT_ALL=1'] +cpp_link_args = ['-s', 'EXPORT_ALL=1'] + +[host_machine] + +system = 'emscripten' +cpu_family = 'wasm32' +cpu = 'wasm32' +endian = 'little' + diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index 84ce06f41..41dd23852 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -13,6 +13,7 @@ These are return values of the `get_id` (Compiler family) and | clang | The Clang compiler | gcc | | clang-cl | The Clang compiler (MSVC compatible driver) | msvc | | dmd | D lang reference compiler | | +| emscripten| Emscripten WASM compiler | | | flang | Flang Fortran compiler | | | g95 | The G95 Fortran compiler | | | gcc | The GNU Compiler Collection | gcc | @@ -66,6 +67,8 @@ set in the cross file. | s390x | IBM zSystem s390x | | sparc | 32 bit SPARC | | sparc64 | SPARC v9 processor | +| wasm32 | 32 bit Webassembly | +| wasm64 | 64 bit Webassembly | | x86 | 32 bit x86 processor | | x86_64 | 64 bit x86 processor | @@ -86,6 +89,7 @@ These are provided by the `.system()` method call. | cygwin | The Cygwin environment for Windows | | darwin | Either OSX or iOS | | dragonfly | DragonFly BSD | +| emscripten | Emscripten's Javascript environment | | freebsd | FreeBSD and its derivatives | | gnu | GNU Hurd | | haiku | | diff --git a/docs/markdown/snippets/wasm.md b/docs/markdown/snippets/wasm.md new file mode 100644 index 000000000..04fbf4916 --- /dev/null +++ b/docs/markdown/snippets/wasm.md @@ -0,0 +1,5 @@ +## Experimental Webassembly support via Emscripten + +Meson now supports compiling code to Webassembly using the Emscripten +compiler. As with most things regarding Webassembly, this support is +subject to change. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index d5814ffd8..b77995ac2 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1432,6 +1432,8 @@ class Executable(BuildTarget): # Executable for Windows or C#/Mono if machine.is_windows() or machine.is_cygwin() or 'cs' in self.compilers: self.suffix = 'exe' + elif machine.system.startswith('wasm') or machine.system == 'emscripten': + self.suffix = 'js' elif ('c' in self.compilers and self.compilers['c'].get_id().startswith('arm') or 'cpp' in self.compilers and self.compilers['cpp'].get_id().startswith('arm')): self.suffix = 'axf' diff --git a/mesonbuild/compilers/__init__.py b/mesonbuild/compilers/__init__.py index 6d9e8148f..5cd56b871 100644 --- a/mesonbuild/compilers/__init__.py +++ b/mesonbuild/compilers/__init__.py @@ -126,6 +126,7 @@ from .c import ( ClangClCCompiler, GnuCCompiler, ElbrusCCompiler, + EmscriptenCCompiler, IntelCCompiler, IntelClCCompiler, PGICCompiler, @@ -140,6 +141,7 @@ from .cpp import ( ClangClCPPCompiler, GnuCPPCompiler, ElbrusCPPCompiler, + EmscriptenCPPCompiler, IntelCPPCompiler, IntelClCPPCompiler, PGICPPCompiler, diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index eff716106..f50b77cdf 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -119,6 +119,31 @@ class ClangCCompiler(ClangCompiler, CCompiler): return basic +class EmscriptenCCompiler(ClangCCompiler): + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): + if not is_cross: + raise MesonException('Emscripten compiler can only be used for cross compilation.') + ClangCCompiler.__init__(self, exelist, version, compiler_type, for_machine, is_cross, exe_wrapper, **kwargs) + self.id = 'emscripten' + + def get_option_link_args(self, options): + return [] + + def get_linker_always_args(self): + return [] + + def get_asneeded_args(self): + return [] + + def get_lundef_args(self): + return [] + + def build_rpath_args(self, *args, **kwargs): + return [] + + def get_soname_args(self, *args, **kwargs): + raise MesonException('Emscripten does not support shared libraries.') + class ArmclangCCompiler(ArmclangCompiler, CCompiler): def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 3b61e6141..4502750ff 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1204,6 +1204,7 @@ class CompilerType(enum.Enum): CLANG_STANDARD = 10 CLANG_OSX = 11 CLANG_MINGW = 12 + CLANG_EMSCRIPTEN = 13 # Possibly clang-cl? ICC_STANDARD = 20 diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 6ae267323..5808b2e7c 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -131,7 +131,7 @@ class CPPCompiler(CLikeCompiler, Compiler): } # Currently, remapping is only supported for Clang, Elbrus and GCC - assert(self.id in frozenset(['clang', 'lcc', 'gcc'])) + assert(self.id in frozenset(['clang', 'lcc', 'gcc', 'emscripten'])) if cpp_std not in CPP_FALLBACKS: # 'c++03' and 'c++98' don't have fallback types @@ -183,6 +183,39 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler): return ['-lstdc++'] +class EmscriptenCPPCompiler(ClangCPPCompiler): + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): + if not is_cross: + raise MesonException('Emscripten compiler can only be used for cross compilation.') + ClangCPPCompiler.__init__(self, exelist, version, compiler_type, for_machine, is_cross, exe_wrapper, **kwargs) + self.id = 'emscripten' + + def get_option_compile_args(self, options): + args = [] + std = options['cpp_std'] + if std.value != 'none': + args.append(self._find_best_cpp_std(std.value)) + return args + + def get_option_link_args(self, options): + return [] + + def get_linker_always_args(self): + return [] + + def get_asneeded_args(self): + return [] + + def get_lundef_args(self): + return [] + + def build_rpath_args(self, *args, **kwargs): + return [] + + def get_soname_args(self, *args, **kwargs): + raise MesonException('Emscripten does not support shared libraries.') + + class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py index 011ab5d50..15d937b14 100644 --- a/mesonbuild/envconfig.py +++ b/mesonbuild/envconfig.py @@ -53,6 +53,8 @@ known_cpu_families = ( 's390x', 'sparc', 'sparc64', + 'wasm32', + 'wasm64', 'x86', 'x86_64' ) @@ -66,6 +68,7 @@ CPU_FAMILES_64_BIT = [ 'ppc64', 'riscv64', 'sparc64', + 'wasm64', 'x86_64', ] diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 6c30fc197..096cd090f 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -60,6 +60,8 @@ from .compilers import ( ElbrusCCompiler, ElbrusCPPCompiler, ElbrusFortranCompiler, + EmscriptenCCompiler, + EmscriptenCPPCompiler, IntelCCompiler, IntelCPPCompiler, IntelClCCompiler, @@ -716,6 +718,11 @@ class Environment: cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines, full_version=full_version) + if 'Emscripten' in out: + cls = EmscriptenCCompiler if lang == 'c' else EmscriptenCPPCompiler + compiler_type = CompilerType.CLANG_EMSCRIPTEN + return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version) + if 'armclang' in out: # The compiler version is not present in the first line of output, # instead it is present in second line, startswith 'Component:'. diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index ed82c3791..8b0768e76 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -465,6 +465,13 @@ class Installer: pdb_outname = os.path.splitext(outname)[0] + '.pdb' self.do_copyfile(pdb_filename, pdb_outname) set_mode(pdb_outname, install_mode, d.install_umask) + if fname.endswith('.js'): + # Emscripten outputs js files and optionally a wasm file. + # If one was generated, install it as well. + wasm_source = os.path.splitext(fname)[0] + '.wasm' + if os.path.exists(wasm_source): + wasm_output = os.path.splitext(outname)[0] + '.wasm' + self.do_copyfile(wasm_source, wasm_output) elif os.path.isdir(fname): fname = os.path.join(d.build_dir, fname.rstrip('/')) outname = os.path.join(outdir, os.path.basename(fname)) diff --git a/test cases/wasm/1 basic/hello.cpp b/test cases/wasm/1 basic/hello.cpp new file mode 100644 index 000000000..6ce13daef --- /dev/null +++ b/test cases/wasm/1 basic/hello.cpp @@ -0,0 +1,7 @@ +#include + +int main() { + std::cout << "Hello World" << std::endl; + return 0; +} + diff --git a/test cases/wasm/1 basic/hello.html b/test cases/wasm/1 basic/hello.html new file mode 100644 index 000000000..637bc2074 --- /dev/null +++ b/test cases/wasm/1 basic/hello.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test cases/wasm/1 basic/meson.build b/test cases/wasm/1 basic/meson.build new file mode 100644 index 000000000..8fe713c73 --- /dev/null +++ b/test cases/wasm/1 basic/meson.build @@ -0,0 +1,3 @@ +project('emcctest', 'cpp') + +executable('hello', 'hello.cpp') -- cgit v1.2.1