4
4
5
5
import 'dart:io' ;
6
6
7
+ import 'package:code_assets/code_assets.dart' ;
8
+
7
9
import '../native_toolchain/tool_likeness.dart' ;
8
10
import '../tool/tool.dart' ;
9
11
@@ -14,7 +16,7 @@ import '../tool/tool.dart';
14
16
/// the [LinkerOptions.treeshake] constructor can be used.
15
17
class LinkerOptions {
16
18
/// The flags to be passed to the linker. As they depend on the linker being
17
- /// invoked, the actual usage is via the [postSourcesFlags ] method.
19
+ /// invoked, the actual usage is via the [sourceFilesToFlags ] method.
18
20
final List <String > _linkerFlags;
19
21
20
22
/// Enable garbage collection of unused input sections.
@@ -27,37 +29,38 @@ class LinkerOptions {
27
29
/// See also the `ld` man page at https://linux.die.net/man/1/ld.
28
30
final Uri ? linkerScript;
29
31
30
- /// Whether to include all symbols from the sources.
32
+ /// Whether to strip debugging symbols from the binary.
33
+ final bool stripDebug;
34
+
35
+ /// The symbols to keep in the resulting binaries.
31
36
///
32
- /// This is achieved by setting the `whole-archive` flag before passing the
33
- /// sources, and the `no-whole-archive` flag after.
34
- final bool _wholeArchiveSandwich;
37
+ /// If null all symbols will be kept.
38
+ final List <String >? _symbolsToKeep;
35
39
36
40
/// Create linking options manually for fine-grained control.
37
41
LinkerOptions .manual ({
38
42
List <String >? flags,
39
43
bool ? gcSections,
40
44
this .linkerScript,
45
+ this .stripDebug = true ,
46
+ Iterable <String >? symbolsToKeep,
41
47
}) : _linkerFlags = flags ?? [],
42
48
gcSections = gcSections ?? true ,
43
- _wholeArchiveSandwich = false ;
49
+ _symbolsToKeep = symbolsToKeep ? . toList (growable : false ) ;
44
50
45
51
/// Create linking options to tree-shake symbols from the input files.
46
52
///
47
53
/// The [symbols] specify the symbols which should be kept.
48
54
LinkerOptions .treeshake ({
49
55
Iterable <String >? flags,
50
56
required Iterable <String >? symbols,
51
- }) : _linkerFlags = < String > [
52
- ...flags ?? [],
53
- '--strip-debug' ,
54
- if (symbols != null ) ...symbols.map ((e) => '-u,$e ' ),
55
- ].toList (),
57
+ this .stripDebug = true ,
58
+ }) : _linkerFlags = flags? .toList (growable: false ) ?? [],
59
+ _symbolsToKeep = symbols? .toList (growable: false ),
56
60
gcSections = true ,
57
- _wholeArchiveSandwich = symbols == null ,
58
61
linkerScript = _createLinkerScript (symbols);
59
62
60
- Iterable <String > _toLinkerSyntax (Tool linker, List <String > flagList) {
63
+ Iterable <String > _toLinkerSyntax (Tool linker, Iterable <String > flagList) {
61
64
if (linker.isClangLike) {
62
65
return flagList.map ((e) => '-Wl,$e ' );
63
66
} else if (linker.isLdLike) {
@@ -85,38 +88,48 @@ class LinkerOptions {
85
88
}
86
89
87
90
extension LinkerOptionsExt on LinkerOptions {
88
- /// The flags for the specified [linker] , which are inserted _before_ the
89
- /// sources.
90
- ///
91
- /// This is mainly used for the whole-archive ... no-whole-archive
92
- /// trick, which includes all symbols when linking object files.
93
- ///
94
- /// Throws if the [linker] is not supported.
95
- Iterable <String > preSourcesFlags (Tool linker, Iterable <String > sourceFiles) =>
96
- _toLinkerSyntax (
97
- linker,
98
- sourceFiles.any ((source) => source.endsWith ('.a' )) ||
99
- _wholeArchiveSandwich
100
- ? ['--whole-archive' ]
101
- : [],
102
- );
103
-
104
- /// The flags for the specified [linker] , which are inserted _after_ the
105
- /// sources.
106
- ///
107
- /// This is mainly used for the whole-archive ... no-whole-archive
108
- /// trick, which includes all symbols when linking object files.
109
- ///
110
- /// Throws if the [linker] is not supported.
111
- Iterable <String > postSourcesFlags (
112
- Tool linker,
91
+ /// Takes [sourceFiles] and turns it into flags for the compiler driver while
92
+ /// considering the current [LinkerOptions] .
93
+ Iterable <String > sourceFilesToFlags (
94
+ Tool tool,
113
95
Iterable <String > sourceFiles,
114
- ) => _toLinkerSyntax (linker, [
115
- ..._linkerFlags,
116
- if (gcSections) '--gc-sections' ,
117
- if (linkerScript != null ) '--version-script=${linkerScript !.toFilePath ()}' ,
118
- if (sourceFiles.any ((source) => source.endsWith ('.a' )) ||
119
- _wholeArchiveSandwich)
120
- '--no-whole-archive' ,
121
- ]);
96
+ OS targetOS,
97
+ ) {
98
+ final includeAllSymbols = _symbolsToKeep == null ;
99
+
100
+ switch (targetOS) {
101
+ case OS .macOS:
102
+ return [
103
+ if (! includeAllSymbols) ...sourceFiles,
104
+ ..._toLinkerSyntax (tool, [
105
+ if (includeAllSymbols) ...sourceFiles.map ((e) => '-force_load,$e ' ),
106
+ ..._linkerFlags,
107
+ ..._symbolsToKeep? .map ((symbol) => '-u,_$symbol ' ) ?? [],
108
+ if (stripDebug) '-S' ,
109
+ if (gcSections) '-dead_strip' ,
110
+ ]),
111
+ ];
112
+
113
+ case OS .android || OS .linux:
114
+ final wholeArchiveSandwich =
115
+ sourceFiles.any ((source) => source.endsWith ('.a' )) ||
116
+ includeAllSymbols;
117
+ return [
118
+ if (wholeArchiveSandwich)
119
+ ..._toLinkerSyntax (tool, ['--whole-archive' ]),
120
+ ...sourceFiles,
121
+ ..._toLinkerSyntax (tool, [
122
+ ..._linkerFlags,
123
+ ..._symbolsToKeep? .map ((symbol) => '-u,$symbol ' ) ?? [],
124
+ if (stripDebug) '--strip-debug' ,
125
+ if (gcSections) '--gc-sections' ,
126
+ if (linkerScript != null )
127
+ '--version-script=${linkerScript !.toFilePath ()}' ,
128
+ if (wholeArchiveSandwich) '--no-whole-archive' ,
129
+ ]),
130
+ ];
131
+ case OS ():
132
+ throw UnimplementedError ();
133
+ }
134
+ }
122
135
}
0 commit comments