Merge pull request #6688 from dcbaker/emcc-linker-bugs

Emcc linker bugs and improvments
pull/6756/head
Jussi Pakkanen 5 years ago committed by GitHub
commit 7234316dc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 34
      docs/markdown/Builtin-options.md
  2. 3
      docs/markdown/Reference-tables.md
  3. 6
      docs/markdown/snippets/emscripten_threads.md
  4. 5
      docs/markdown/snippets/wasm_ld.md
  5. 4
      mesonbuild/compilers/c.py
  6. 4
      mesonbuild/compilers/cpp.py
  7. 29
      mesonbuild/compilers/mixins/emscripten.py
  8. 9
      mesonbuild/compilers/mixins/islinker.py
  9. 12
      mesonbuild/environment.py
  10. 29
      mesonbuild/linkers.py
  11. 7
      test cases/wasm/1 basic/hello.c
  12. 3
      test cases/wasm/1 basic/meson.build
  13. 10
      test cases/wasm/2 threads/meson.build
  14. 21
      test cases/wasm/2 threads/threads.c
  15. 13
      test cases/wasm/2 threads/threads.cpp

@ -151,20 +151,22 @@ The following options are available. Note that both the options themselves and
the possible values they can take will depend on the target platform or
compiler being used:
| Option | Default value | Possible values | Description |
| ------ | ------------- | --------------- | ----------- |
| c_args | | free-form comma-separated list | C compile arguments to use |
| c_link_args | | free-form comma-separated list | C link arguments to use |
| c_std | none | none, c89, c99, c11, c17, c18, gnu89, gnu99, gnu11, gnu17, gnu18 | C language standard to use |
| c_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against |
| cpp_args | | free-form comma-separated list | C++ compile arguments to use |
| cpp_link_args| | free-form comma-separated list | C++ link arguments to use |
| cpp_std | none | none, c++98, c++03, c++11, c++14, c++17, <br/>c++1z, gnu++03, gnu++11, gnu++14, gnu++17, gnu++1z, <br/> vc++14, vc++17, vc++latest | C++ language standard to use |
| cpp_debugstl | false | true, false | C++ STL debug mode |
| cpp_eh | default | none, default, a, s, sc | C++ exception handling type |
| cpp_rtti | true | true, false | Whether to enable RTTI (runtime type identification) |
| cpp_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against |
| fortran_std | none | [none, legacy, f95, f2003, f2008, f2018] | Fortran language standard to use |
| Option | Default value | Possible values | Description |
| ------ | ------------- | --------------- | ----------- |
| c_args | | free-form comma-separated list | C compile arguments to use |
| c_link_args | | free-form comma-separated list | C link arguments to use |
| c_std | none | none, c89, c99, c11, c17, c18, gnu89, gnu99, gnu11, gnu17, gnu18 | C language standard to use |
| c_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against |
| c_thread_count | 4 | integer value ≥ 0 | Number of threads to use with emcc when using threads |
| cpp_args | | free-form comma-separated list | C++ compile arguments to use |
| cpp_link_args | | free-form comma-separated list | C++ link arguments to use |
| cpp_std | none | none, c++98, c++03, c++11, c++14, c++17, <br/>c++1z, gnu++03, gnu++11, gnu++14, gnu++17, gnu++1z, <br/> vc++14, vc++17, vc++latest | C++ language standard to use |
| cpp_debugstl | false | true, false | C++ STL debug mode |
| cpp_eh | default | none, default, a, s, sc | C++ exception handling type |
| cpp_rtti | true | true, false | Whether to enable RTTI (runtime type identification) |
| cpp_thread_count | 4 | integer value ≥ 0 | Number of threads to use with emcc when using threads |
| cpp_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against |
| fortran_std | none | [none, legacy, f95, f2003, f2008, f2018] | Fortran language standard to use |
The default values of `c_winlibs` and `cpp_winlibs` are in compiler-specific
argument forms, but the libraries are: kernel32, user32, gdi32, winspool,
@ -179,3 +181,7 @@ while the `cpp_eh=[value]` will result in `/EH[value]`.
Since *0.51.0* `cpp_eh=default` will result in `/EHsc` on MSVC. When using
gcc-style compilers, nothing is passed (allowing exceptions to work), while
`cpp_eh=none` passes `-fno-exceptions`.
Since *0.54.0* The `<lang>_thread_count` option can be used to control the
value passed to `-s PTHREAD_POOL_SIZE` when using emcc. No other c/c++
compiler supports this option.

@ -37,10 +37,11 @@ These are return values of the `get_linker_id` method in a compiler object.
| Value | Linker family |
| ----- | --------------- |
| ld.bfd | The GNU linker |
| ld.bfd | The GNU linker |
| ld.gold | The GNU gold linker |
| ld.lld | The LLVM linker, with the GNU interface |
| ld.solaris | Solaris and illumos |
| ld.wasm | emscripten's wasm-ld linker |
| ld64 | Apple ld64 |
| link | MSVC linker |
| lld-link | The LLVM linker, with the MSVC interface |

@ -0,0 +1,6 @@
## Emscripten (emcc) now supports threads
In addition to properly setting the compile and linker arguments, a new meson
builtin has been added to control the PTHREAD_POOL_SIZE option,
`-D<lang>_thread_count`, which may be set to any integer value greater than 0.
If it set to 0 then the PTHREAD_POOL_SIZE option will not be passed.

@ -0,0 +1,5 @@
## Property support emscripten's wasm-ld
Before 0.54.0 we treated emscripten as both compiler and linker, which isn't
really true. It does have a linker, called wasm-ld (meson's name is ld.wasm).
This is a special version of clang's lld. This will now be detected properly.

@ -27,7 +27,7 @@ from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler
from .mixins.clang import ClangCompiler
from .mixins.elbrus import ElbrusCompiler
from .mixins.pgi import PGICompiler
from .mixins.islinker import BasicLinkerIsCompilerMixin, LinkerEnvVarsMixin
from .mixins.islinker import LinkerEnvVarsMixin
from .mixins.emscripten import EmscriptenMixin
from .compilers import (
gnu_winlibs,
@ -139,7 +139,7 @@ class AppleClangCCompiler(ClangCCompiler):
_C18_VERSION = '>=11.0.0'
class EmscriptenCCompiler(LinkerEnvVarsMixin, EmscriptenMixin, BasicLinkerIsCompilerMixin, ClangCCompiler):
class EmscriptenCCompiler(EmscriptenMixin, LinkerEnvVarsMixin, ClangCCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice,
is_cross: bool, info: 'MachineInfo', exe_wrapper=None, **kwargs):
if not is_cross:

@ -36,7 +36,7 @@ from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler
from .mixins.clang import ClangCompiler
from .mixins.elbrus import ElbrusCompiler
from .mixins.pgi import PGICompiler
from .mixins.islinker import BasicLinkerIsCompilerMixin, LinkerEnvVarsMixin
from .mixins.islinker import LinkerEnvVarsMixin
from .mixins.emscripten import EmscriptenMixin
if T.TYPE_CHECKING:
@ -207,7 +207,7 @@ class AppleClangCPPCompiler(ClangCPPCompiler):
pass
class EmscriptenCPPCompiler(LinkerEnvVarsMixin, EmscriptenMixin, BasicLinkerIsCompilerMixin, ClangCPPCompiler):
class EmscriptenCPPCompiler(EmscriptenMixin, LinkerEnvVarsMixin, ClangCPPCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice,
is_cross: bool, info: 'MachineInfo', exe_wrapper=None, **kwargs):
if not is_cross:

@ -17,20 +17,13 @@
import os.path
import typing as T
from ...mesonlib import MesonException
from ... import coredata
class EmscriptenMixin:
def get_option_link_args(self, options):
return []
def get_soname_args(self, *args, **kwargs):
raise MesonException('Emscripten does not support shared libraries.')
if T.TYPE_CHECKING:
from ..environment import Environment
def get_allow_undefined_link_args(self) -> T.List[str]:
return ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=0']
def get_linker_output_args(self, output: str) -> T.List[str]:
return ['-o', output]
class EmscriptenMixin:
def _get_compile_output(self, dirname, mode):
# In pre-processor mode, the output is sent to stdout and discarded
@ -44,3 +37,17 @@ class EmscriptenMixin:
else:
suffix = 'wasm'
return os.path.join(dirname, 'output.' + suffix)
def thread_flags(self, env: 'Environment') -> T.List[str]:
return ['-s', 'USE_PTHREADS=1']
def get_options(self):
opts = super().get_options()
opts.update({
'{}_thread_count'.format(self.language): coredata.UserIntegerOption(
'Number of threads to use in web assembly, set to 0 to disable',
(0, None, 4), # Default was picked at random
),
})
return opts

@ -130,3 +130,12 @@ class BasicLinkerIsCompilerMixin:
def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]:
return []
def get_link_debugfile_name(self, target: str) -> str:
return ''
def thread_flags(self, env: 'Environment') -> T.List[str]:
return []
def thread_link_flags(self, env: 'Environment') -> T.List[str]:
return []

@ -58,6 +58,7 @@ from .linkers import (
XilinkDynamicLinker,
CudaLinker,
VisualStudioLikeLinkerMixin,
WASMDynamicLinker,
)
from functools import lru_cache
from .compilers import (
@ -963,9 +964,18 @@ class Environment:
if 'Emscripten' in out:
cls = EmscriptenCCompiler if lang == 'c' else EmscriptenCPPCompiler
self.coredata.add_lang_args(cls.language, cls, for_machine, self)
# emcc cannot be queried to get the version out of it (it
# ignores -Wl,--version and doesn't have an alternative).
# Further, wasm-id *is* lld and will return `LLD X.Y.Z` if you
# call `wasm-ld --version`, but a special version of lld that
# takes different options.
p, o, _ = Popen_safe(['wasm-ld', '--version'])
linker = WASMDynamicLinker(
compiler, for_machine, cls.LINKER_PREFIX,
[], version=search_version(o))
return cls(
ccache + compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version)
exe_wrap, linker=linker, full_version=full_version)
if 'armclang' in out:
# The compiler version is not present in the first line of output,

@ -693,6 +693,35 @@ class LLVMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, Dyna
return []
class WASMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):
"""Emscripten's wasm-ld."""
def __init__(self, *args, **kwargs):
super().__init__('ld.wasm', *args, **kwargs)
def thread_link_flags(self, env: 'Environment') -> T.List[str]:
args = ['-s', 'USE_PTHREADS=1']
count = env.coredata.compiler_options[self.for_machine]['{}_thread_count'.format(self.language)].value # type: int
if count:
args.extend(['-s', 'PTHREAD_POOL_SIZE={}'.format(count)])
return args
def get_allow_undefined_args(self) -> T.List[str]:
return ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=0']
def no_undefined_args(self) -> T.List[str]:
return ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1']
def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
is_shared_module: bool) -> T.List[str]:
raise mesonlib.MesonException('{} does not support shared libraries.'.format(self.id))
def get_asneeded_args(self) -> T.List[str]:
return []
class CcrxDynamicLinker(DynamicLinker):
"""Linker for Renesis CCrx compiler."""

@ -0,0 +1,7 @@
#include <stdio.h>
int main() {
printf("Hello World\n");
return 0;
}

@ -1,3 +1,4 @@
project('emcctest', 'cpp')
project('emcctest', 'c', 'cpp')
executable('hello-c', 'hello.c')
executable('hello', 'hello.cpp')

@ -0,0 +1,10 @@
project(
'threads',
'c', 'cpp',
default_options : ['cpp_std=c++11'],
)
dep_threads = dependency('threads')
executable('threads-c', 'threads.c', dependencies : dep_threads)
executable('threads-c++', 'threads.cpp', dependencies : dep_threads)

@ -0,0 +1,21 @@
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
void inthread(void * args) {
sleep(1);
printf("In thread\n");
}
int main() {
#ifdef __EMSCRIPTEN_PTHREADS__
pthread_t thread_id;
printf("Before Thread\n");
pthread_create(&thread_id, NULL, (void *)*inthread, NULL);
pthread_join(thread_id, NULL);
printf("After Thread\n");
return 0;
#else
# error "threads not enabled\n"
#endif
}

@ -0,0 +1,13 @@
#include <unistd.h>
#include <iostream>
#include <thread>
int main(void) {
std::cout << "Before thread" << std::endl;
std::thread t([]() {
sleep(1);
std::cout << "In a thread." << std::endl;
});
t.join();
std::cout << "After thread" << std::endl;
}
Loading…
Cancel
Save