44
55import  'dart:io' ;
66
7+ import  'package:code_assets/code_assets.dart' ;
8+ 
79import  '../native_toolchain/tool_likeness.dart' ;
810import  '../tool/tool.dart' ;
911
@@ -14,7 +16,7 @@ import '../tool/tool.dart';
1416/// the [LinkerOptions.treeshake]  constructor can be used. 
1517class  LinkerOptions  {
1618  /// 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. 
1820final  List <String > _linkerFlags;
1921
2022  /// Enable garbage collection of unused input sections. 
@@ -27,37 +29,38 @@ class LinkerOptions {
2729  /// See also the `ld`  man page at https://linux.die.net/man/1/ld. 
2830final  Uri ?  linkerScript;
2931
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. 
3136  /// 
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;
3539
3640  /// Create linking options manually for fine-grained control. 
3741LinkerOptions .manual ({
3842    List <String >?  flags,
3943    bool ?  gcSections,
4044    this .linkerScript,
45+     this .stripDebug =  true ,
46+     Iterable <String >?  symbolsToKeep,
4147  }) :  _linkerFlags =  flags ??  [],
4248       gcSections =  gcSections ??  true ,
43-        _wholeArchiveSandwich  =  false ;
49+        _symbolsToKeep  =  symbolsToKeep ? . toList (growable :   false ) ;
4450
4551  /// Create linking options to tree-shake symbols from the input files. 
4652  /// 
4753  /// The [symbols]  specify the symbols which should be kept. 
4854LinkerOptions .treeshake ({
4955    Iterable <String >?  flags,
5056    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 ),
5660       gcSections =  true ,
57-        _wholeArchiveSandwich =  symbols ==  null ,
5861       linkerScript =  _createLinkerScript (symbols);
5962
60-   Iterable <String > _toLinkerSyntax (Tool  linker, List <String > flagList) {
63+   Iterable <String > _toLinkerSyntax (Tool  linker, Iterable <String > flagList) {
6164    if  (linker.isClangLike) {
6265      return  flagList.map ((e) =>  '-Wl,$e ' );
6366    } else  if  (linker.isLdLike) {
@@ -85,38 +88,48 @@ class LinkerOptions {
8588}
8689
8790extension  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,
11395    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+   }
122135}
0 commit comments