Add basic Webassembly support via Emscripten.

pull/5774/head
Jussi Pakkanen 5 years ago
parent ddbf60f86d
commit f41bdae368
  1. 19
      cross/wasm.txt
  2. 4
      docs/markdown/Reference-tables.md
  3. 5
      docs/markdown/snippets/wasm.md
  4. 2
      mesonbuild/build.py
  5. 2
      mesonbuild/compilers/__init__.py
  6. 25
      mesonbuild/compilers/c.py
  7. 1
      mesonbuild/compilers/compilers.py
  8. 35
      mesonbuild/compilers/cpp.py
  9. 3
      mesonbuild/envconfig.py
  10. 7
      mesonbuild/environment.py
  11. 7
      mesonbuild/minstall.py
  12. 7
      test cases/wasm/1 basic/hello.cpp
  13. 8
      test cases/wasm/1 basic/hello.html
  14. 3
      test cases/wasm/1 basic/meson.build

@ -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'

@ -13,6 +13,7 @@ These are return values of the `get_id` (Compiler family) and
| clang | The Clang compiler | gcc | | clang | The Clang compiler | gcc |
| clang-cl | The Clang compiler (MSVC compatible driver) | msvc | | clang-cl | The Clang compiler (MSVC compatible driver) | msvc |
| dmd | D lang reference compiler | | | dmd | D lang reference compiler | |
| emscripten| Emscripten WASM compiler | |
| flang | Flang Fortran compiler | | | flang | Flang Fortran compiler | |
| g95 | The G95 Fortran compiler | | | g95 | The G95 Fortran compiler | |
| gcc | The GNU Compiler Collection | gcc | | gcc | The GNU Compiler Collection | gcc |
@ -66,6 +67,8 @@ set in the cross file.
| s390x | IBM zSystem s390x | | s390x | IBM zSystem s390x |
| sparc | 32 bit SPARC | | sparc | 32 bit SPARC |
| sparc64 | SPARC v9 processor | | sparc64 | SPARC v9 processor |
| wasm32 | 32 bit Webassembly |
| wasm64 | 64 bit Webassembly |
| x86 | 32 bit x86 processor | | x86 | 32 bit x86 processor |
| x86_64 | 64 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 | | cygwin | The Cygwin environment for Windows |
| darwin | Either OSX or iOS | | darwin | Either OSX or iOS |
| dragonfly | DragonFly BSD | | dragonfly | DragonFly BSD |
| emscripten | Emscripten's Javascript environment |
| freebsd | FreeBSD and its derivatives | | freebsd | FreeBSD and its derivatives |
| gnu | GNU Hurd | | gnu | GNU Hurd |
| haiku | | | haiku | |

@ -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.

@ -1432,6 +1432,8 @@ class Executable(BuildTarget):
# Executable for Windows or C#/Mono # Executable for Windows or C#/Mono
if machine.is_windows() or machine.is_cygwin() or 'cs' in self.compilers: if machine.is_windows() or machine.is_cygwin() or 'cs' in self.compilers:
self.suffix = 'exe' 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 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')): 'cpp' in self.compilers and self.compilers['cpp'].get_id().startswith('arm')):
self.suffix = 'axf' self.suffix = 'axf'

@ -126,6 +126,7 @@ from .c import (
ClangClCCompiler, ClangClCCompiler,
GnuCCompiler, GnuCCompiler,
ElbrusCCompiler, ElbrusCCompiler,
EmscriptenCCompiler,
IntelCCompiler, IntelCCompiler,
IntelClCCompiler, IntelClCCompiler,
PGICCompiler, PGICCompiler,
@ -140,6 +141,7 @@ from .cpp import (
ClangClCPPCompiler, ClangClCPPCompiler,
GnuCPPCompiler, GnuCPPCompiler,
ElbrusCPPCompiler, ElbrusCPPCompiler,
EmscriptenCPPCompiler,
IntelCPPCompiler, IntelCPPCompiler,
IntelClCPPCompiler, IntelClCPPCompiler,
PGICPPCompiler, PGICPPCompiler,

@ -119,6 +119,31 @@ class ClangCCompiler(ClangCompiler, CCompiler):
return basic 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): class ArmclangCCompiler(ArmclangCompiler, CCompiler):
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): 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) CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs)

@ -1204,6 +1204,7 @@ class CompilerType(enum.Enum):
CLANG_STANDARD = 10 CLANG_STANDARD = 10
CLANG_OSX = 11 CLANG_OSX = 11
CLANG_MINGW = 12 CLANG_MINGW = 12
CLANG_EMSCRIPTEN = 13
# Possibly clang-cl? # Possibly clang-cl?
ICC_STANDARD = 20 ICC_STANDARD = 20

@ -131,7 +131,7 @@ class CPPCompiler(CLikeCompiler, Compiler):
} }
# Currently, remapping is only supported for Clang, Elbrus and GCC # 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: if cpp_std not in CPP_FALLBACKS:
# 'c++03' and 'c++98' don't have fallback types # 'c++03' and 'c++98' don't have fallback types
@ -183,6 +183,39 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler):
return ['-lstdc++'] 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): class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler):
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): 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) CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs)

@ -53,6 +53,8 @@ known_cpu_families = (
's390x', 's390x',
'sparc', 'sparc',
'sparc64', 'sparc64',
'wasm32',
'wasm64',
'x86', 'x86',
'x86_64' 'x86_64'
) )
@ -66,6 +68,7 @@ CPU_FAMILES_64_BIT = [
'ppc64', 'ppc64',
'riscv64', 'riscv64',
'sparc64', 'sparc64',
'wasm64',
'x86_64', 'x86_64',
] ]

@ -60,6 +60,8 @@ from .compilers import (
ElbrusCCompiler, ElbrusCCompiler,
ElbrusCPPCompiler, ElbrusCPPCompiler,
ElbrusFortranCompiler, ElbrusFortranCompiler,
EmscriptenCCompiler,
EmscriptenCPPCompiler,
IntelCCompiler, IntelCCompiler,
IntelCPPCompiler, IntelCPPCompiler,
IntelClCCompiler, IntelClCCompiler,
@ -707,6 +709,11 @@ class Environment:
cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler 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) 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: if 'armclang' in out:
# The compiler version is not present in the first line of output, # The compiler version is not present in the first line of output,
# instead it is present in second line, startswith 'Component:'. # instead it is present in second line, startswith 'Component:'.

@ -465,6 +465,13 @@ class Installer:
pdb_outname = os.path.splitext(outname)[0] + '.pdb' pdb_outname = os.path.splitext(outname)[0] + '.pdb'
self.do_copyfile(pdb_filename, pdb_outname) self.do_copyfile(pdb_filename, pdb_outname)
set_mode(pdb_outname, install_mode, d.install_umask) 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): elif os.path.isdir(fname):
fname = os.path.join(d.build_dir, fname.rstrip('/')) fname = os.path.join(d.build_dir, fname.rstrip('/'))
outname = os.path.join(outdir, os.path.basename(fname)) outname = os.path.join(outdir, os.path.basename(fname))

@ -0,0 +1,7 @@
#include<iostream>
int main() {
std::cout << "Hello World" << std::endl;
return 0;
}

@ -0,0 +1,8 @@
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script src="hello.js"></script>
</body>
</html>

@ -0,0 +1,3 @@
project('emcctest', 'cpp')
executable('hello', 'hello.cpp')
Loading…
Cancel
Save