66using CppSharp . Passes ;
77using CppSharp ;
88using CppSharp . Parser ;
9+ using System . Threading ;
910
1011namespace QtSharp
1112{
@@ -22,71 +23,35 @@ public CompileInlinesPass(string qmake, string make)
2223
2324 public override bool VisitASTContext ( ASTContext context )
2425 {
25- string error ;
26- const string qtVersionVariable = "QT_VERSION" ;
27- var qtVersion = ProcessHelper . Run ( this . qmake , string . Format ( "-query {0}" , qtVersionVariable ) , out error ) ;
28- var qtVersionFile = Path . Combine ( this . Context . Options . OutputDir , qtVersionVariable ) ;
29- var qtVersionFileInfo = new FileInfo ( qtVersionFile ) ;
30- var text = string . Empty ;
31- if ( ! qtVersionFileInfo . Exists || ( text = File . ReadAllText ( qtVersionFile ) ) != qtVersion )
32- {
33- File . WriteAllText ( qtVersionFile , qtVersion ) ;
34- qtVersionFileInfo = new FileInfo ( qtVersionFile ) ;
35- }
3626 var dir = Platform . IsMacOS ? this . Context . Options . OutputDir : Path . Combine ( this . Context . Options . OutputDir , "release" ) ;
27+ var findSymbolsPass = this . Context . TranslationUnitPasses . FindPass < FindSymbolsPass > ( ) ;
28+ findSymbolsPass . Wait = true ;
29+ remainingCompilationTasks = this . Context . Options . Modules . Count ;
3730 foreach ( var module in this . Context . Options . Modules )
3831 {
3932 var inlines = Path . GetFileName ( string . Format ( "{0}{1}.{2}" , Platform . IsWindows ? string . Empty : "lib" ,
4033 module . InlinesLibraryName , Platform . IsMacOS ? "dylib" : "dll" ) ) ;
41- var libFile = Path . Combine ( dir , inlines ) ;
42- var inlinesFileInfo = new FileInfo ( libFile ) ;
43- if ( ! inlinesFileInfo . Exists || qtVersionFileInfo . LastWriteTimeUtc > inlinesFileInfo . LastWriteTimeUtc )
44- {
45- if ( ! this . CompileInlines ( module ) )
46- {
47- continue ;
48- }
49- }
50- var parserOptions = new ParserOptions ( ) ;
51- parserOptions . AddLibraryDirs ( dir ) ;
52- parserOptions . LibraryFile = inlines ;
53- using ( var parserResult = CppSharp . Parser . ClangParser . ParseLibrary ( parserOptions ) )
54- {
55- if ( parserResult . Kind == ParserResultKind . Success )
56- {
57- var nativeLibrary = CppSharp . ClangParser . ConvertLibrary ( parserResult . Library ) ;
58- this . Context . Symbols . Libraries . Add ( nativeLibrary ) ;
59- this . Context . Symbols . IndexSymbols ( ) ;
60- parserResult . Library . Dispose ( ) ;
61- }
62- }
34+ this . CompileInlines ( module , dir , inlines ) ;
6335 }
6436 return true ;
6537 }
6638
67- private bool CompileInlines ( Module module )
39+ private void CompileInlines ( Module module , string dir , string inlines )
6840 {
6941 var pro = string . Format ( "{0}.pro" , module . InlinesLibraryName ) ;
7042 var path = Path . Combine ( this . Context . Options . OutputDir , pro ) ;
7143 var proBuilder = new StringBuilder ( ) ;
7244 var qtModules = string . Join ( " " , from header in module . Headers
7345 where ! header . EndsWith ( ".h" , StringComparison . Ordinal )
7446 select header . Substring ( "Qt" . Length ) . ToLowerInvariant ( ) ) ;
75- switch ( qtModules )
47+ // QtTest is only library which has a "lib" suffix to its module alias for qmake
48+ if ( qtModules == "test" )
7649 {
77- // QtTest is only library which has a "lib" suffix to its module alias for qmake
78- case "test" :
79- qtModules += "lib" ;
80- break ;
81- // HACK: work around https://bugreports.qt.io/browse/QTBUG-54030
82- case "bluetooth" :
83- qtModules += " network" ;
84- break ;
50+ qtModules += "lib" ;
8551 }
8652
8753 proBuilder . AppendFormat ( "QT += {0}\n " , qtModules ) ;
8854 proBuilder . Append ( "CONFIG += c++11\n " ) ;
89- proBuilder . Append ( "QMAKE_CXXFLAGS += -fkeep-inline-functions\n " ) ;
9055 proBuilder . AppendFormat ( "TARGET = {0}\n " , module . InlinesLibraryName ) ;
9156 proBuilder . Append ( "TEMPLATE = lib\n " ) ;
9257 proBuilder . AppendFormat ( "SOURCES += {0}\n " , Path . ChangeExtension ( pro , "cpp" ) ) ;
@@ -95,32 +60,92 @@ private bool CompileInlines(Module module)
9560 proBuilder . Append ( "LIBS += -loleaut32 -lole32" ) ;
9661 }
9762 File . WriteAllText ( path , proBuilder . ToString ( ) ) ;
63+ // HACK: work around https://bugreports.qt.io/browse/QTBUG-55952
64+ if ( module . LibraryName == "Qt3DRender.Sharp" )
65+ {
66+ var cpp = Path . ChangeExtension ( pro , "cpp" ) ;
67+ var unlinkable = new [ ]
68+ {
69+ "&Qt3DRender::QSortCriterion::tr;" ,
70+ "&Qt3DRender::QSortCriterion::trUtf8;" ,
71+ "&Qt3DRender::qt_getEnumMetaObject;"
72+ } ;
73+ var linkable = ( from line in File . ReadLines ( cpp )
74+ where unlinkable . All ( ul => ! line . EndsWith ( ul , StringComparison . Ordinal ) )
75+ select line ) . ToList ( ) ;
76+ File . WriteAllLines ( cpp , linkable ) ;
77+ }
9878 string error ;
99- // HACK: Clang does not support -fkeep-inline-functions so force compilation with (the real) GCC on OS X
100- ProcessHelper . Run ( this . qmake , string . Format ( "{0}\" {1}\" " , Platform . IsMacOS ? "-spec macx-g++ " : string . Empty , path ) , out error ) ;
79+ ProcessHelper . Run ( this . qmake , $ "\" { path } \" ", out error ) ;
10180 if ( ! string . IsNullOrEmpty ( error ) )
10281 {
10382 Console . WriteLine ( error ) ;
104- return false ;
83+ return ;
10584 }
10685 var makefile = File . Exists ( Path . Combine ( this . Context . Options . OutputDir , "Makefile.Release" ) ) ? "Makefile.Release" : "Makefile" ;
107- if ( Platform . IsMacOS )
86+ InvokeCompiler ( dir , inlines , makefile ) ;
87+ }
88+
89+ private void InvokeCompiler ( string dir , string inlines , string makefile )
90+ {
91+ new Thread ( ( ) =>
92+ {
93+ try
94+ {
95+ string error ;
96+ ProcessHelper . Run ( this . make , string . Format ( "-j{0} -f {1}" , Environment . ProcessorCount + 1 , makefile ) , out error , true ) ;
97+ if ( string . IsNullOrEmpty ( error ) )
98+ {
99+ var parserOptions = new ParserOptions ( ) ;
100+ parserOptions . AddLibraryDirs ( dir ) ;
101+ parserOptions . LibraryFile = inlines ;
102+ using ( var parserResult = CppSharp . Parser . ClangParser . ParseLibrary ( parserOptions ) )
103+ {
104+ if ( parserResult . Kind == ParserResultKind . Success )
105+ {
106+ var nativeLibrary = CppSharp . ClangParser . ConvertLibrary ( parserResult . Library ) ;
107+ lock ( @lock )
108+ {
109+ this . Context . Symbols . Libraries . Add ( nativeLibrary ) ;
110+ this . Context . Symbols . IndexSymbols ( ) ;
111+ }
112+ parserResult . Library . Dispose ( ) ;
113+ }
114+ }
115+ }
116+ else
117+ {
118+ Console . WriteLine ( error ) ;
119+ }
120+ }
121+ finally
122+ {
123+ RemainingCompilationTasks -- ;
124+ }
125+ } ) . Start ( ) ;
126+ }
127+
128+ private int RemainingCompilationTasks
129+ {
130+ get
108131 {
109- // HACK: Clang does not support -fkeep-inline-functions so force compilation with (the real) GCC on OS X
110- var makefilePath = Path . Combine ( this . Context . Options . OutputDir , makefile ) ;
111- var script = new StringBuilder ( File . ReadAllText ( makefilePath ) ) ;
112- var xcodePath = XcodeToolchain . GetXcodePath ( ) ;
113- script . Replace ( Path . Combine ( xcodePath , "Contents" , "Developer" , "usr" , "bin" , "gcc" ) , "/usr/local/bin/gcc" ) ;
114- script . Replace ( Path . Combine ( xcodePath , "Contents" , "Developer" , "usr" , "bin" , "g++" ) , "/usr/local/bin/g++" ) ;
115- File . WriteAllText ( makefilePath , script . ToString ( ) ) ;
132+ return remainingCompilationTasks ;
116133 }
117- ProcessHelper . Run ( this . make , string . Format ( "-j{0} -f {1}" , Environment . ProcessorCount + 1 , makefile ) , out error , true ) ;
118- if ( ! string . IsNullOrEmpty ( error ) )
134+ set
119135 {
120- Console . WriteLine ( error ) ;
121- return false ;
136+ if ( remainingCompilationTasks != value )
137+ {
138+ remainingCompilationTasks = value ;
139+ if ( remainingCompilationTasks == 0 )
140+ {
141+ var findSymbolsPass = this . Context . TranslationUnitPasses . FindPass < FindSymbolsPass > ( ) ;
142+ findSymbolsPass . Wait = false ;
143+ }
144+ }
122145 }
123- return true ;
124146 }
147+
148+ private int remainingCompilationTasks ;
149+ private static readonly object @lock = new object ( ) ;
125150 }
126151}
0 commit comments