| # 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`. |