@@ -23,12 +23,15 @@ class MbedBSPGenerator
23
23
24
24
public readonly string Version ;
25
25
26
+ LinkerScriptCache _LinkerScriptCache ;
27
+
26
28
public MbedBSPGenerator ( string version )
27
29
{
28
30
Directory . CreateDirectory ( outputDir ) ;
29
31
mbedRoot = Path . GetFullPath ( Path . Combine ( outputDir , "mbed" ) ) ;
30
32
Version = version ;
31
33
34
+ _LinkerScriptCache = new LinkerScriptCache ( toolchainDir , mbedRoot ) ;
32
35
nameRules = new List < KeyValuePair < Regex , string > > ( ) ;
33
36
foreach ( var line in File . ReadAllLines ( Path . Combine ( dataDir , "DeviceNameRules.txt" ) ) )
34
37
{
@@ -91,21 +94,6 @@ public void UpdateGitAndRescanTargets(bool skipRescan = false)
91
94
if ( proc . ExitCode != 0 )
92
95
throw new Exception ( "Git exited with code " + proc . ExitCode ) ;
93
96
94
- foreach ( var lds in Directory . GetFiles ( mbedRoot , "*.ld" , SearchOption . AllDirectories ) )
95
- {
96
- if ( File . ReadAllText ( lds ) . Contains ( "\n #if" ) )
97
- {
98
- ProcessStartInfo preprocessInfo = new ProcessStartInfo ( $@ "{ toolchainDir } \bin\arm-eabi-cpp.exe", $ "-P -C { lds } -o { lds } .preprocessed") ;
99
- preprocessInfo . UseShellExecute = false ;
100
- preprocessInfo . EnvironmentVariables [ "PATH" ] += $@ ";{ toolchainDir } \bin";
101
- proc = Process . Start ( preprocessInfo ) ;
102
- proc . WaitForExit ( ) ;
103
-
104
- File . Copy ( lds + ".preprocessed" , lds , true ) ;
105
- File . Delete ( lds + ".preprocessed" ) ;
106
- }
107
- }
108
-
109
97
var patchedFile = Path . Combine ( mbedRoot , @"tools\config\__init__.py" ) ;
110
98
var lines = File . ReadAllLines ( patchedFile ) . ToList ( ) ;
111
99
var idx2 = Enumerable . Range ( 0 , lines . Count ) . First ( i => lines [ i ] . Contains ( "self.value = int(value) if isinstance(value, bool) else value" ) ) ;
@@ -225,28 +213,130 @@ public string[] ConvertPaths(IEnumerable<string> rawPaths)
225
213
{
226
214
if ( fn . Length == mbedRoot . Length && fn . ToLower ( ) == mbedRoot . ToLower ( ) )
227
215
return "$$SYS:BSP_ROOT$$" ;
228
- if ( fn . StartsWith ( mbedRoot , StringComparison . InvariantCulture ) )
216
+ if ( fn . StartsWith ( mbedRoot , StringComparison . InvariantCultureIgnoreCase ) )
229
217
return "$$SYS:BSP_ROOT$$/" + fn . Substring ( mbedRoot . Length + 1 ) . Replace ( '\\ ' , '/' ) ;
230
218
throw new Exception ( "Source path is not inside the mbed BSP: " + fn ) ;
231
219
} ) . ToArray ( ) ;
232
220
}
233
221
222
+ public string ConvertPath ( string physicalPath ) => ConvertPaths ( new [ ] { physicalPath } ) [ 0 ] ;
223
+
234
224
public struct ConvertedHexFile
235
225
{
236
226
public uint LoadAddress ;
237
227
public int Size ;
238
228
public string RelativePath ;
239
229
public string SectionName ;
230
+
231
+ public int End => ( int ) LoadAddress + Size ;
240
232
}
241
233
242
234
Dictionary < string , ConvertedHexFile > _ConvertedHexFiles = new Dictionary < string , ConvertedHexFile > ( ) ;
243
- Dictionary < string , string > _PatchedLinkerScripts = new Dictionary < string , string > ( StringComparer . InvariantCultureIgnoreCase ) ;
244
- Dictionary < string , string > _PatchedLinkerScriptsReverse = new Dictionary < string , string > ( StringComparer . InvariantCultureIgnoreCase ) ;
245
235
246
- public void ConvertSoftdevicesAndPatchTarget ( MCU mcu , string [ ] hexFiles )
236
+ static int AlignHexFileSize ( int size )
247
237
{
248
- string baseDir = Path . Combine ( mbedRoot , "SysprogsGenerated" ) ;
249
- Directory . CreateDirectory ( baseDir ) ;
238
+ const int alignment = 4096 ;
239
+ return ( ( size + alignment - 1 ) / alignment ) * alignment ;
240
+ }
241
+
242
+ class LinkerScriptCache
243
+ {
244
+ public readonly string BaseDir ;
245
+ readonly string _ToolchainDir ;
246
+ readonly string _MBEDRoot ;
247
+
248
+ public LinkerScriptCache ( string toolchainDir , string mbedRoot )
249
+ {
250
+ _ToolchainDir = toolchainDir ;
251
+ _MBEDRoot = mbedRoot ;
252
+ BaseDir = Path . Combine ( mbedRoot , "SysprogsGenerated" ) ;
253
+ Directory . CreateDirectory ( BaseDir ) ;
254
+ }
255
+
256
+ Dictionary < KeyValuePair < string , int > , string > _PreprocessedScripts = new Dictionary < KeyValuePair < string , int > , string > ( ) ;
257
+ HashSet < string > _UsedGeneratedPaths = new HashSet < string > ( StringComparer . InvariantCultureIgnoreCase ) ;
258
+
259
+ public string ProvidePreprocessedLinkerScript ( string baseScript , int appStart )
260
+ {
261
+ baseScript = baseScript . Replace ( "$$SYS:BSP_ROOT$$" , _MBEDRoot ) ;
262
+
263
+ var key = new KeyValuePair < string , int > ( baseScript , appStart ) ;
264
+ if ( _PreprocessedScripts . TryGetValue ( key , out var val ) )
265
+ return val ;
266
+
267
+ if ( ! File . ReadAllText ( baseScript ) . Contains ( "\n #if" ) )
268
+ return _PreprocessedScripts [ key ] = baseScript ;
269
+
270
+ ProcessStartInfo preprocessInfo = new ProcessStartInfo ( $@ "{ _ToolchainDir } \bin\arm-eabi-cpp.exe", $ "-P -C { baseScript } -o { baseScript } .preprocessed") ;
271
+ if ( appStart != 0 )
272
+ preprocessInfo . Arguments += $ " -DMBED_APP_START=0x{ appStart : x} ";
273
+
274
+ preprocessInfo . UseShellExecute = false ;
275
+ preprocessInfo . EnvironmentVariables [ "PATH" ] += $@ ";{ _ToolchainDir } \bin";
276
+ var proc = Process . Start ( preprocessInfo ) ;
277
+ proc . WaitForExit ( ) ;
278
+
279
+ string nameBase = $ "{ BaseDir } \\ { Path . GetFileNameWithoutExtension ( baseScript ) } -{ appStart : x} ";
280
+ for ( int iter = 0 ; iter < 100000 ; iter ++ )
281
+ {
282
+ string newName = nameBase ;
283
+ if ( iter > 0 )
284
+ newName += $ "-{ iter } ";
285
+
286
+ newName += ".ld" ;
287
+ if ( _UsedGeneratedPaths . Contains ( newName ) )
288
+ continue ;
289
+
290
+ _UsedGeneratedPaths . Add ( newName ) ;
291
+
292
+ File . Copy ( baseScript + ".preprocessed" , newName , true ) ;
293
+ File . Delete ( baseScript + ".preprocessed" ) ;
294
+ return _PreprocessedScripts [ key ] = newName ;
295
+ }
296
+
297
+ throw new Exception ( "Failed to locate a name for preprocessed " + baseScript ) ;
298
+ }
299
+
300
+ Dictionary < string , string > _PatchedScripts = new Dictionary < string , string > ( ) ;
301
+
302
+ public string ProvideNameForPatchedScript ( string originalScript , out bool alreadyCreated )
303
+ {
304
+ if ( _PatchedScripts . TryGetValue ( originalScript , out var result ) )
305
+ {
306
+ alreadyCreated = true ;
307
+ return result ;
308
+ }
309
+
310
+ alreadyCreated = false ;
311
+ string nameBase = $ "{ BaseDir } \\ { Path . GetFileNameWithoutExtension ( originalScript ) } -sd";
312
+
313
+ for ( int iter = 0 ; iter < 100000 ; iter ++ )
314
+ {
315
+ string newName = nameBase ;
316
+ if ( iter > 0 )
317
+ newName += $ "-{ iter } ";
318
+
319
+ newName += ".ld" ;
320
+ if ( _UsedGeneratedPaths . Contains ( newName ) )
321
+ continue ;
322
+
323
+ _UsedGeneratedPaths . Add ( newName ) ;
324
+ return newName ;
325
+ }
326
+
327
+ throw new Exception ( "Failed to locate a name for patched " + originalScript ) ;
328
+ }
329
+ }
330
+
331
+ public string PreprocessLinkerScriptIfNeeded ( string linkerScript )
332
+ {
333
+ return _LinkerScriptCache . ProvidePreprocessedLinkerScript ( linkerScript , 0 ) ;
334
+ }
335
+
336
+ //Returns true if the linker script was preprocessed.
337
+ public bool ConvertSoftdevicesAndPatchTarget ( MCU mcu , string [ ] hexFiles )
338
+ {
339
+ var baseDir = _LinkerScriptCache . BaseDir ;
250
340
File . WriteAllText ( Path . Combine ( baseDir , ".mbedignore" ) , "*" ) ;
251
341
252
342
foreach ( var hexFile in hexFiles )
@@ -281,33 +371,25 @@ public void ConvertSoftdevicesAndPatchTarget(MCU mcu, string[] hexFiles)
281
371
282
372
if ( ! generatedCFile . StartsWith ( mbedRoot , StringComparison . InvariantCultureIgnoreCase ) )
283
373
throw new Exception ( "HEX file outside mbed root" ) ;
284
- _ConvertedHexFiles [ hexFile ] = new ConvertedHexFile { LoadAddress = parsedFile . LoadAddress , RelativePath = generatedCFile . Substring ( mbedRoot . Length + 1 ) , SectionName = sectionName , Size = parsedFile . Data . Length } ;
374
+ _ConvertedHexFiles [ hexFile ] = new ConvertedHexFile
375
+ {
376
+ LoadAddress = parsedFile . LoadAddress ,
377
+ RelativePath = generatedCFile . Substring ( mbedRoot . Length + 1 ) ,
378
+ SectionName = sectionName ,
379
+ Size = AlignHexFileSize ( parsedFile . Data . Length )
380
+ } ;
285
381
}
286
382
287
383
var hexFileList = hexFiles . Select ( hf => _ConvertedHexFiles [ hf ] ) . ToList ( ) ;
288
384
if ( hexFiles . Length == 0 )
289
- return ;
385
+ return false ;
290
386
291
387
hexFileList . Sort ( ( a , b ) => a . LoadAddress . CompareTo ( b . LoadAddress ) ) ;
292
- var linkerScript = mcu . CompilationFlags . LinkerScript ;
293
- string patchedLinkerScript ;
388
+ var linkerScript = _LinkerScriptCache . ProvidePreprocessedLinkerScript ( mcu . CompilationFlags . LinkerScript , hexFileList . Last ( ) . End ) ;
294
389
295
- if ( ! _PatchedLinkerScripts . TryGetValue ( linkerScript , out patchedLinkerScript ) )
390
+ string patchedLinkerScript = _LinkerScriptCache . ProvideNameForPatchedScript ( linkerScript , out bool scriptAlreadyPatched ) ;
391
+ if ( ! scriptAlreadyPatched )
296
392
{
297
- patchedLinkerScript = Path . Combine ( baseDir , Path . GetFileName ( mcu . CompilationFlags . LinkerScript ) ) ;
298
- if ( _PatchedLinkerScriptsReverse . TryGetValue ( patchedLinkerScript , out string tmp ) && tmp != linkerScript )
299
- {
300
- for ( int i = 2 ; ; i ++ )
301
- {
302
- patchedLinkerScript = Path . Combine ( baseDir , Path . GetFileNameWithoutExtension ( mcu . CompilationFlags . LinkerScript ) + "_x" + i + Path . GetExtension ( mcu . CompilationFlags . LinkerScript ) ) ;
303
- if ( ! _PatchedLinkerScriptsReverse . ContainsKey ( patchedLinkerScript ) )
304
- break ;
305
- }
306
-
307
- }
308
- _PatchedLinkerScripts [ linkerScript ] = patchedLinkerScript ;
309
- _PatchedLinkerScriptsReverse [ patchedLinkerScript ] = linkerScript ;
310
-
311
393
List < string > linkerScriptLines = File . ReadAllLines ( linkerScript . Replace ( "$$SYS:BSP_ROOT$$" , mbedRoot ) ) . ToList ( ) ;
312
394
313
395
int firstMemorySectionLine = Enumerable . Range ( 0 , linkerScript . Length )
@@ -338,13 +420,16 @@ public void ConvertSoftdevicesAndPatchTarget(MCU mcu, string[] hexFiles)
338
420
File . WriteAllLines ( patchedLinkerScript . Replace ( "$$SYS:BSP_ROOT$$" , mbedRoot ) , linkerScriptLines ) ;
339
421
}
340
422
341
- mcu . CompilationFlags . LinkerScript = ConvertPaths ( new [ ] { patchedLinkerScript } ) [ 0 ] ;
423
+ mcu . CompilationFlags . LinkerScript = ConvertPath ( patchedLinkerScript ) ;
342
424
mcu . AdditionalSourceFiles = mcu . AdditionalSourceFiles . Concat ( hexFileList . Select ( h => "$$SYS:BSP_ROOT$$/" + h . RelativePath . Replace ( '\\ ' , '/' ) ) ) . ToArray ( ) ;
425
+ return true ;
343
426
}
344
427
345
428
public void DetectAndApplyMemorySizes ( MCU mcu , string linkerScript )
346
429
{
347
430
Console . Write ( "." ) ;
431
+ linkerScript = _LinkerScriptCache . ProvidePreprocessedLinkerScript ( linkerScript , 0 ) ;
432
+
348
433
string tmpFile = Path . GetTempPath ( ) + "LinkerScriptQuery.c" ;
349
434
File . WriteAllText ( tmpFile , "" ) ;
350
435
string mapFile = Path . ChangeExtension ( tmpFile , ".map" ) ;
0 commit comments