blob: 239cdb348996a3fd72cd28867333263ac1620408 [file] [log] [blame] [view]
# Linking Issues with Native Assets
This document describes common linking issues that can occur when using native
assets in Dart and provides workarounds.
## Conflicting with Embedder Library Dependencies
When a native asset provides a library that is also a dependency of the
embedder, you may encounter runtime crashes. This is because the symbols from
the already-loaded library can conflict with the symbols from the native asset.
This can happen, for example, when using a hook that bundles sqlite3 in a
Flutter application on Linux. The Flutter embedder already depends on
`libsqlite3.so`, so when the Dart code tries to load the `sqlite3` native asset,
the dynamic linker can get confused and resolve symbols to the wrong library,
leading to a crash.
This issue only happens on Linux, as the other OSes use some kind of namespacing
for symbols by default. On Linux, trying to use namespacing leads to issues with
using sanitizers, so on Linux Dart and Flutter do not enable namespacing. See
[GitHub issue #2724](https://github.com/dart-lang/native/issues/2724) for more
details.
### Workaround 1: Symbol Prefixing
Create a wrapper library that statically links the conflicting library (e.g.,
SQLite) and re-exposes its symbols with a unique prefix. This avoids name
collisions with the library loaded by the embedder.
If your library enables end-users to load either a custom native library or one
from the operating system via a user-define, you can design the wrapper to
dynamically link against that library while still re-exposing the symbols with a
prefix. This prevents having to duplicate the `@Native` bindings for supporting
that user-define.
### Workaround 2: Symbol Versioning and Export Maps
Use `ffigen` to generate a list of symbols that need to be accessed from
Dart. Then, use the `-Wl,--version-script=` linker flag with a script that
marks only those necessary symbols as global and all others as local. This
reduces the list of symbols that could conflict with the embedder. If one of the
required symbols clashes with the embedder, this method doesn't work.
### Workaround 3: `-Bsymbolic` Linker Flag
Adding `DF_SYMBOLIC` as an ELF dynamic entry via the `-Wl,-Bsymbolic` linker
flag can resolve conflicts within a single dynamic library. This flag tells
the dynamic linker to resolve symbol references within the library first,
before searching in other libraries. This is similar in effect to using the
`RTLD_DEEPBIND` flag with `dlopen`.