Skip to content

Commit e9910c3

Browse files
authored
[doc] Document how to avoid symbol clashes with embedder (#2740)
Closes: #2724 cc @simolus3
1 parent f75c068 commit e9910c3

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

pkgs/code_assets/doc/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# `package:code_assets` Documentation
2+
3+
This directory contains detailed documentation for the `package:code_assets` API.
4+
5+
## Available Documentation
6+
7+
* **[Linking Issues](./linking_issues.md)**: Learn about common linking issues that can occur when using native assets and how to work around them.
8+
9+
* **[Schema](./schema/README.md)**: Explore the JSON schema for the configuration files used by code assets.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Linking Issues with Native Assets
2+
3+
This document describes common linking issues that can occur when using native
4+
assets in Dart and provides workarounds.
5+
6+
## Conflicting with Embedder Library Dependencies
7+
8+
When a native asset provides a library that is also a dependency of the
9+
embedder, you may encounter runtime crashes. This is because the symbols from
10+
the already-loaded library can conflict with the symbols from the native asset.
11+
12+
This can happen, for example, when using a hook that bundles sqlite3 in a
13+
Flutter application on Linux. The Flutter embedder already depends on
14+
`libsqlite3.so`, so when the Dart code tries to load the `sqlite3` native asset,
15+
the dynamic linker can get confused and resolve symbols to the wrong library,
16+
leading to a crash.
17+
18+
This issue only happens on Linux, as the other OSes use some kind of namespacing
19+
for symbols by default. On Linux, trying to use namespacing leads to issues with
20+
using sanitizers, so on Linux Dart and Flutter do not enable namespacing. See
21+
[GitHub issue #2724](https://github.com/dart-lang/native/issues/2724) for more
22+
details.
23+
24+
### Workaround 1: Symbol Prefixing
25+
26+
Create a wrapper library that statically links the conflicting library (e.g.,
27+
SQLite) and re-exposes its symbols with a unique prefix. This avoids name
28+
collisions with the library loaded by the embedder.
29+
30+
If your library enables end-users to load either a custom native library or one
31+
from the operating system via a user-define, you can design the wrapper to
32+
dynamically link against that library while still re-exposing the symbols with a
33+
prefix. This prevents having to duplicate the `@Native` bindings for supporting
34+
that user-define.
35+
36+
### Workaround 2: Symbol Versioning and Export Maps
37+
38+
Use `ffigen` to generate a list of symbols that need to be accessed from
39+
Dart. Then, use the `-Wl,--version-script=` linker flag with a script that
40+
marks only those necessary symbols as global and all others as local. This
41+
reduces the list of symbols that could conflict with the embedder. If one of the
42+
required symbols clashes with the embedder, this method doesn't work.
43+
44+
### Workaround 3: `-Bsymbolic` Linker Flag
45+
46+
Adding `DF_SYMBOLIC` as an ELF dynamic entry via the `-Wl,-Bsymbolic` linker
47+
flag can resolve conflicts within a single dynamic library. This flag tells
48+
the dynamic linker to resolve symbol references within the library first,
49+
before searching in other libraries. This is similar in effect to using the
50+
`RTLD_DEEPBIND` flag with `dlopen`.

0 commit comments

Comments
 (0)