@@ -523,8 +523,8 @@ abstract class SimCompare {
523523 /// Returns the directory containing systemc.h.gch, or null on failure.
524524 ///
525525 /// In CI, the PCH is pre-built by `tool/gh_actions/setup_systemc_pch.sh`
526- /// before tests run, so this first looks for the shared CI path. Locally,
527- /// each test process builds its own PCH directory to avoid parallel races .
526+ /// before tests run. Locally, tests lazily build the same shared PCH under a
527+ /// file lock so parallel test isolates can reuse it without racing .
528528 static String ? _ensurePch (String scHome, String cxxStd) {
529529 if (_pchPath != null ) {
530530 return _pchPath;
@@ -533,43 +533,57 @@ abstract class SimCompare {
533533 const dir = 'tmp_test' ;
534534 const sharedPchDir = '$dir /pch' ;
535535 const sharedGchFile = '$sharedPchDir /systemc.h.gch' ;
536+ const lockFile = '$dir /pch.lock' ;
536537
537538 // Reuse the CI-prebuilt PCH if available.
538539 if (File (sharedGchFile).existsSync ()) {
539540 return _pchPath = sharedPchDir;
540541 }
541542
542- final pchDir = '$dir /${_systemCTempPrefix }_pch' ;
543- final gchFile = '$pchDir /systemc.h.gch' ;
544-
545- // Reuse if this process already built it on disk.
546- if (File (gchFile).existsSync ()) {
547- return _pchPath = pchDir;
548- }
543+ Directory (dir).createSync (recursive: true );
544+ RandomAccessFile ? lock;
545+ try {
546+ lock = File (lockFile).openSync (mode: FileMode .append)..lockSync ();
549547
550- Directory (pchDir).createSync (recursive: true );
548+ if (File (sharedGchFile).existsSync ()) {
549+ return _pchPath = sharedPchDir;
550+ }
551551
552- // Copy the original header next to the .gch so g++ matches them.
553- final pchHeader = '$pchDir /systemc.h' ;
554- File ('$scHome /systemc.h' ).copySync (pchHeader);
552+ Directory (sharedPchDir).createSync (recursive: true );
553+
554+ // Copy the original header next to the .gch so g++ matches them.
555+ const pchHeader = '$sharedPchDir /systemc.h' ;
556+ File ('$scHome /systemc.h' ).copySync (pchHeader);
557+
558+ final args = [
559+ '-std=$cxxStd ' ,
560+ '-I$scHome ' ,
561+ '-x' ,
562+ 'c++-header' ,
563+ '-o' ,
564+ sharedGchFile,
565+ pchHeader,
566+ ];
567+ final result = Process .runSync ('g++' , args);
568+ if (result.exitCode != 0 ) {
569+ print ('PCH compilation failed (falling back to normal headers):' );
570+ print (result.stderr);
571+ Directory (sharedPchDir).deleteSync (recursive: true );
572+ return null ;
573+ }
555574
556- final args = [
557- '-std=$cxxStd ' ,
558- '-I$scHome ' ,
559- '-x' ,
560- 'c++-header' ,
561- '-o' ,
562- gchFile,
563- pchHeader,
564- ];
565- final result = Process .runSync ('g++' , args);
566- if (result.exitCode != 0 ) {
567- print ('PCH compilation failed (falling back to normal headers):' );
568- print (result.stderr);
575+ return _pchPath = sharedPchDir;
576+ } on Exception catch (e) {
577+ print ('PCH setup failed (falling back to normal headers): $e ' );
569578 return null ;
579+ } finally {
580+ if (lock != null ) {
581+ try {
582+ lock.unlockSync ();
583+ } on Exception catch (_) {}
584+ lock.closeSync ();
585+ }
570586 }
571-
572- return _pchPath = pchDir;
573587 }
574588
575589 /// Resolves SystemC home/lib paths. If explicit paths are given, uses them.
@@ -638,6 +652,11 @@ abstract class SimCompare {
638652 continue ;
639653 }
640654
655+ if (! keepPch && name == 'pch.lock' ) {
656+ entity.deleteSync ();
657+ continue ;
658+ }
659+
641660 // Leave everything else (iverilog files from parallel tests) alone
642661 }
643662 }
0 commit comments