2016-12-30 15:11:20 +00:00
/****************************************************************************
* *
* * Copyright ( C ) 2016 The Qt Company Ltd .
* * Contact : https : //www.qt.io/licensing/
* *
* * This file is part of the QtQml module of the Qt Toolkit .
* *
* * $ QT_BEGIN_LICENSE : GPL - EXCEPT $
* * Commercial License Usage
* * Licensees holding valid commercial Qt licenses may use this file in
* * accordance with the commercial license agreement provided with the
* * Software or , alternatively , in accordance with the terms contained in
* * a written agreement between you and The Qt Company . For licensing terms
* * and conditions see https : //www.qt.io/terms-conditions. For further
* * information use the contact form at https : //www.qt.io/contact-us.
* *
* * GNU General Public License Usage
* * Alternatively , this file may be used under the terms of the GNU
* * General Public License version 3 as published by the Free Software
* * Foundation with exceptions as appearing in the file LICENSE . GPL3 - EXCEPT
* * included in the packaging of this file . Please review the following
* * information to ensure the GNU General Public License requirements will
* * be met : https : //www.gnu.org/licenses/gpl-3.0.html.
* *
* * $ QT_END_LICENSE $
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <QCoreApplication>
# include <QStringList>
# include <QCommandLineParser>
# include <QFile>
# include <QFileInfo>
# include <QDateTime>
2017-03-14 18:26:14 +00:00
# include <QHashFunctions>
2018-01-22 15:46:03 +00:00
# include <QSaveFile>
2018-08-16 11:06:22 +00:00
# include <QScopedPointer>
# include <QScopeGuard>
2016-12-30 15:11:20 +00:00
# include <private/qqmlirbuilder_p.h>
# include <private/qqmljsparser_p.h>
2018-02-12 13:03:13 +00:00
# include <private/qqmljslexer_p.h>
2016-12-30 15:11:20 +00:00
2018-01-22 15:46:03 +00:00
# include "resourcefilemapper.h"
2019-01-02 12:08:40 +00:00
# include <algorithm>
2019-07-09 12:30:24 +00:00
using namespace QQmlJS ;
2018-01-22 15:46:03 +00:00
int filterResourceFile ( const QString & input , const QString & output ) ;
2019-01-02 12:08:40 +00:00
bool generateLoader ( const QStringList & compiledFiles , const QStringList & retainedFiles ,
const QString & output , const QStringList & resourceFileMappings ,
QString * errorString ) ;
2018-01-22 15:46:03 +00:00
QString symbolNamespaceForPath ( const QString & relativePath ) ;
2018-01-15 14:36:25 +00:00
QSet < QString > illegalNames ;
void setupIllegalNames ( )
{
2018-12-22 08:41:10 +00:00
for ( const char * * g = QV4 : : Compiler : : Codegen : : s_globalNames ; * g ! = nullptr ; + + g )
illegalNames . insert ( QString : : fromLatin1 ( * g ) ) ;
2018-01-15 14:36:25 +00:00
}
2016-12-30 15:11:20 +00:00
struct Error
{
QString message ;
void print ( ) ;
Error augment ( const QString & contextErrorMessage ) const ;
2018-08-16 11:06:22 +00:00
void appendDiagnostics ( const QString & inputFileName , const QList < QQmlJS : : DiagnosticMessage > & diagnostics ) ;
2019-07-04 11:18:55 +00:00
void appendDiagnostic ( const QString & inputFileName , const DiagnosticMessage & diagnostic ) ;
2016-12-30 15:11:20 +00:00
} ;
void Error : : print ( )
{
fprintf ( stderr , " %s \n " , qPrintable ( message ) ) ;
}
Error Error : : augment ( const QString & contextErrorMessage ) const
{
Error augmented ;
augmented . message = contextErrorMessage + message ;
return augmented ;
}
QString diagnosticErrorMessage ( const QString & fileName , const QQmlJS : : DiagnosticMessage & m )
{
QString message ;
2019-05-23 12:57:09 +00:00
message = fileName + QLatin1Char ( ' : ' ) + QString : : number ( m . line ) + QLatin1Char ( ' : ' ) ;
if ( m . column > 0 )
message + = QString : : number ( m . column ) + QLatin1Char ( ' : ' ) ;
2016-12-30 15:11:20 +00:00
if ( m . isError ( ) )
message + = QLatin1String ( " error: " ) ;
else
message + = QLatin1String ( " warning: " ) ;
message + = m . message ;
return message ;
}
2019-07-04 11:18:55 +00:00
void Error : : appendDiagnostic ( const QString & inputFileName , const DiagnosticMessage & diagnostic )
{
if ( ! message . isEmpty ( ) )
message + = QLatin1Char ( ' \n ' ) ;
message + = diagnosticErrorMessage ( inputFileName , diagnostic ) ;
}
2018-08-16 11:06:22 +00:00
void Error : : appendDiagnostics ( const QString & inputFileName , const QList < DiagnosticMessage > & diagnostics )
{
2019-07-04 11:18:55 +00:00
for ( const QQmlJS : : DiagnosticMessage & diagnostic : diagnostics )
appendDiagnostic ( inputFileName , diagnostic ) ;
2018-08-16 11:06:22 +00:00
}
2017-03-10 08:17:35 +00:00
// Ensure that ListElement objects keep all property assignments in their string form
static void annotateListElements ( QmlIR : : Document * document )
{
QStringList listElementNames ;
2019-01-04 14:03:27 +00:00
for ( const QV4 : : CompiledData : : Import * import : qAsConst ( document - > imports ) ) {
2017-03-10 08:17:35 +00:00
const QString uri = document - > stringAt ( import - > uriIndex ) ;
if ( uri ! = QStringLiteral ( " QtQml.Models " ) & & uri ! = QStringLiteral ( " QtQuick " ) )
continue ;
QString listElementName = QStringLiteral ( " ListElement " ) ;
const QString qualifier = document - > stringAt ( import - > qualifierIndex ) ;
if ( ! qualifier . isEmpty ( ) ) {
listElementName . prepend ( QLatin1Char ( ' . ' ) ) ;
listElementName . prepend ( qualifier ) ;
}
listElementNames . append ( listElementName ) ;
}
if ( listElementNames . isEmpty ( ) )
return ;
2019-01-04 14:03:27 +00:00
for ( QmlIR : : Object * object : qAsConst ( document - > objects ) ) {
2017-03-10 08:17:35 +00:00
if ( ! listElementNames . contains ( document - > stringAt ( object - > inheritedTypeNameIndex ) ) )
continue ;
for ( QmlIR : : Binding * binding = object - > firstBinding ( ) ; binding ; binding = binding - > next ) {
if ( binding - > type ! = QV4 : : CompiledData : : Binding : : Type_Script )
continue ;
binding - > stringIndex = document - > registerString ( object - > bindingAsString ( document , binding - > value . compiledScriptIndex ) ) ;
}
}
}
2017-09-12 15:20:47 +00:00
static bool checkArgumentsObjectUseInSignalHandlers ( const QmlIR : : Document & doc , Error * error )
{
for ( QmlIR : : Object * object : qAsConst ( doc . objects ) ) {
for ( auto binding = object - > bindingsBegin ( ) ; binding ! = object - > bindingsEnd ( ) ; + + binding ) {
if ( binding - > type ! = QV4 : : CompiledData : : Binding : : Type_Script )
continue ;
const QString propName = doc . stringAt ( binding - > propertyNameIndex ) ;
if ( ! propName . startsWith ( QLatin1String ( " on " ) )
| | propName . length ( ) < 3
| | ! propName . at ( 2 ) . isUpper ( ) )
continue ;
auto compiledFunction = doc . jsModule . functions . value ( object - > runtimeFunctionIndices . at ( binding - > value . compiledScriptIndex ) ) ;
if ( ! compiledFunction )
continue ;
2017-10-22 10:05:18 +00:00
if ( compiledFunction - > usesArgumentsObject = = QV4 : : Compiler : : Context : : ArgumentsObjectUsed ) {
2017-09-12 15:20:47 +00:00
error - > message = QLatin1Char ( ' : ' ) + QString : : number ( compiledFunction - > line ) + QLatin1Char ( ' : ' ) ;
if ( compiledFunction - > column > 0 )
error - > message + = QString : : number ( compiledFunction - > column ) + QLatin1Char ( ' : ' ) ;
2018-06-27 07:22:19 +00:00
error - > message + = QLatin1String ( " error: The use of eval() or the use of the arguments object in signal handlers is \n "
" not supported when compiling qml files ahead of time. That is because it's ambiguous if \n "
" any signal parameter is called \" arguments \" . Similarly the string passed to eval might use \n "
" \" arguments \" . Unfortunately we cannot distinguish between it being a parameter or the \n "
" JavaScript arguments object at this point. \n "
" Consider renaming the parameter of the signal if applicable or moving the code into a \n "
" helper function. " ) ;
2017-09-12 15:20:47 +00:00
return false ;
}
}
}
return true ;
}
2019-05-13 09:07:39 +00:00
using SaveFunction = std : : function < bool ( const QV4 : : CompiledData : : SaveableUnitPointer & , QString * ) > ;
2018-01-22 15:46:03 +00:00
static bool compileQmlFile ( const QString & inputFileName , SaveFunction saveFunction , Error * error )
2016-12-30 15:11:20 +00:00
{
QmlIR : : Document irDocument ( /*debugMode*/ false ) ;
QString sourceCode ;
{
QFile f ( inputFileName ) ;
if ( ! f . open ( QIODevice : : ReadOnly ) ) {
error - > message = QLatin1String ( " Error opening " ) + inputFileName + QLatin1Char ( ' : ' ) + f . errorString ( ) ;
return false ;
}
sourceCode = QString : : fromUtf8 ( f . readAll ( ) ) ;
if ( f . error ( ) ! = QFileDevice : : NoError ) {
error - > message = QLatin1String ( " Error reading from " ) + inputFileName + QLatin1Char ( ' : ' ) + f . errorString ( ) ;
return false ;
}
}
{
QmlIR : : IRBuilder irBuilder ( illegalNames ) ;
if ( ! irBuilder . generateFromQml ( sourceCode , inputFileName , & irDocument ) ) {
2018-08-16 11:06:22 +00:00
error - > appendDiagnostics ( inputFileName , irBuilder . errors ) ;
2016-12-30 15:11:20 +00:00
return false ;
}
}
2017-03-10 08:17:35 +00:00
annotateListElements ( & irDocument ) ;
2016-12-30 15:11:20 +00:00
{
2019-07-10 15:23:39 +00:00
QmlIR : : JSCodeGen v4CodeGen ( & irDocument , illegalNames ) ;
2016-12-30 15:11:20 +00:00
for ( QmlIR : : Object * object : qAsConst ( irDocument . objects ) ) {
if ( object - > functionsAndExpressions - > count = = 0 )
continue ;
QList < QmlIR : : CompiledFunctionOrExpression > functionsToCompile ;
2019-01-03 14:44:34 +00:00
for ( QmlIR : : CompiledFunctionOrExpression * foe = object - > functionsAndExpressions - > first ; foe ; foe = foe - > next )
2016-12-30 15:11:20 +00:00
functionsToCompile < < * foe ;
const QVector < int > runtimeFunctionIndices = v4CodeGen . generateJSCodeForFunctionsAndBindings ( functionsToCompile ) ;
2019-07-04 11:18:55 +00:00
if ( v4CodeGen . hasError ( ) ) {
error - > appendDiagnostic ( inputFileName , v4CodeGen . error ( ) ) ;
2016-12-30 15:11:20 +00:00
return false ;
}
QQmlJS : : MemoryPool * pool = irDocument . jsParserEngine . pool ( ) ;
object - > runtimeFunctionIndices . allocate ( pool , runtimeFunctionIndices ) ;
}
2017-09-12 15:20:47 +00:00
if ( ! checkArgumentsObjectUseInSignalHandlers ( irDocument , error ) ) {
* error = error - > augment ( inputFileName ) ;
return false ;
}
2016-12-30 15:11:20 +00:00
QmlIR : : QmlUnitGenerator generator ;
2017-06-22 08:01:17 +00:00
irDocument . javaScriptCompilationUnit = v4CodeGen . generateCompilationUnit ( /*generate unit*/ false ) ;
2018-07-26 09:05:08 +00:00
generator . generate ( irDocument ) ;
2016-12-30 15:11:20 +00:00
2019-05-13 09:07:39 +00:00
const quint32 saveFlags
= QV4 : : CompiledData : : Unit : : StaticData
| QV4 : : CompiledData : : Unit : : PendingTypeCompilation ;
2019-06-14 09:30:47 +00:00
QV4 : : CompiledData : : SaveableUnitPointer saveable ( irDocument . javaScriptCompilationUnit . data ,
2019-05-13 09:07:39 +00:00
saveFlags ) ;
if ( ! saveFunction ( saveable , & error - > message ) )
2016-12-30 15:11:20 +00:00
return false ;
}
return true ;
}
2018-01-22 15:46:03 +00:00
static bool compileJSFile ( const QString & inputFileName , const QString & inputFileUrl , SaveFunction saveFunction , Error * error )
2016-12-30 15:11:20 +00:00
{
2019-05-07 10:47:33 +00:00
QV4 : : CompiledData : : CompilationUnit unit ;
2016-12-30 15:11:20 +00:00
QString sourceCode ;
{
QFile f ( inputFileName ) ;
if ( ! f . open ( QIODevice : : ReadOnly ) ) {
error - > message = QLatin1String ( " Error opening " ) + inputFileName + QLatin1Char ( ' : ' ) + f . errorString ( ) ;
return false ;
}
sourceCode = QString : : fromUtf8 ( f . readAll ( ) ) ;
if ( f . error ( ) ! = QFileDevice : : NoError ) {
error - > message = QLatin1String ( " Error reading from " ) + inputFileName + QLatin1Char ( ' : ' ) + f . errorString ( ) ;
return false ;
}
}
2018-08-16 11:06:22 +00:00
const bool isModule = inputFileName . endsWith ( QLatin1String ( " .mjs " ) ) ;
if ( isModule ) {
QList < QQmlJS : : DiagnosticMessage > diagnostics ;
// Precompiled files are relocatable and the final location will be set when loading.
QString url ;
2019-05-08 11:29:50 +00:00
unit = QV4 : : Compiler : : Codegen : : compileModule ( /*debugMode*/ false , url , sourceCode ,
QDateTime ( ) , & diagnostics ) ;
2018-08-16 11:06:22 +00:00
error - > appendDiagnostics ( inputFileName , diagnostics ) ;
2019-05-07 10:47:33 +00:00
if ( ! unit . unitData ( ) )
2018-08-16 11:06:22 +00:00
return false ;
} else {
QmlIR : : Document irDocument ( /*debugMode*/ false ) ;
2016-12-30 15:11:20 +00:00
2018-08-16 11:06:22 +00:00
QQmlJS : : Engine * engine = & irDocument . jsParserEngine ;
QmlIR : : ScriptDirectivesCollector directivesCollector ( & irDocument ) ;
QQmlJS : : Directives * oldDirs = engine - > directives ( ) ;
engine - > setDirectives ( & directivesCollector ) ;
auto directivesGuard = qScopeGuard ( [ engine , oldDirs ] {
engine - > setDirectives ( oldDirs ) ;
} ) ;
2016-12-30 15:11:20 +00:00
2018-08-16 11:06:22 +00:00
QQmlJS : : AST : : Program * program = nullptr ;
2016-12-30 15:11:20 +00:00
2018-08-16 11:06:22 +00:00
{
QQmlJS : : Lexer lexer ( engine ) ;
lexer . setCode ( sourceCode , /*line*/ 1 , /*parseAsBinding*/ false ) ;
QQmlJS : : Parser parser ( engine ) ;
2016-12-30 15:11:20 +00:00
2018-08-16 11:06:22 +00:00
bool parsed = parser . parseProgram ( ) ;
2016-12-30 15:11:20 +00:00
2018-08-16 11:06:22 +00:00
error - > appendDiagnostics ( inputFileName , parser . diagnosticMessages ( ) ) ;
2016-12-30 15:11:20 +00:00
2018-08-16 11:06:22 +00:00
if ( ! parsed )
return false ;
2016-12-30 15:11:20 +00:00
2018-08-16 11:06:22 +00:00
program = QQmlJS : : AST : : cast < QQmlJS : : AST : : Program * > ( parser . rootNode ( ) ) ;
if ( ! program ) {
lexer . setCode ( QStringLiteral ( " undefined; " ) , 1 , false ) ;
parsed = parser . parseProgram ( ) ;
Q_ASSERT ( parsed ) ;
program = QQmlJS : : AST : : cast < QQmlJS : : AST : : Program * > ( parser . rootNode ( ) ) ;
Q_ASSERT ( program ) ;
2016-12-30 15:11:20 +00:00
}
}
2018-08-16 11:06:22 +00:00
{
2019-07-10 15:23:39 +00:00
QmlIR : : JSCodeGen v4CodeGen ( & irDocument , illegalNames ) ;
2018-08-16 11:06:22 +00:00
v4CodeGen . generateFromProgram ( inputFileName , inputFileUrl , sourceCode , program ,
2018-10-05 12:17:05 +00:00
& irDocument . jsModule , QV4 : : Compiler : : ContextType : : ScriptImportedByQML ) ;
2019-07-04 11:18:55 +00:00
if ( v4CodeGen . hasError ( ) ) {
error - > appendDiagnostic ( inputFileName , v4CodeGen . error ( ) ) ;
2018-08-16 11:06:22 +00:00
return false ;
}
2016-12-30 15:11:20 +00:00
2018-08-16 11:06:22 +00:00
// Precompiled files are relocatable and the final location will be set when loading.
irDocument . jsModule . fileName . clear ( ) ;
irDocument . jsModule . finalUrl . clear ( ) ;
irDocument . javaScriptCompilationUnit = v4CodeGen . generateCompilationUnit ( /*generate unit*/ false ) ;
QmlIR : : QmlUnitGenerator generator ;
generator . generate ( irDocument ) ;
2019-05-07 10:47:33 +00:00
unit = std : : move ( irDocument . javaScriptCompilationUnit ) ;
2016-12-30 15:11:20 +00:00
}
}
2018-08-16 11:06:22 +00:00
2019-06-14 09:30:47 +00:00
return saveFunction ( QV4 : : CompiledData : : SaveableUnitPointer ( unit . data ) , & error - > message ) ;
2016-12-30 15:11:20 +00:00
}
2018-07-26 09:05:08 +00:00
static bool saveUnitAsCpp ( const QString & inputFileName , const QString & outputFileName ,
2019-05-13 09:07:39 +00:00
const QV4 : : CompiledData : : SaveableUnitPointer & unit ,
2019-05-07 10:47:33 +00:00
QString * errorString )
2018-01-22 15:46:03 +00:00
{
QSaveFile f ( outputFileName ) ;
if ( ! f . open ( QIODevice : : WriteOnly | QIODevice : : Truncate ) ) {
* errorString = f . errorString ( ) ;
return false ;
}
auto writeStr = [ & f , errorString ] ( const QByteArray & data ) {
if ( f . write ( data ) ! = data . size ( ) ) {
* errorString = f . errorString ( ) ;
return false ;
}
return true ;
} ;
if ( ! writeStr ( " // " ) )
return false ;
if ( ! writeStr ( inputFileName . toUtf8 ( ) ) )
return false ;
if ( ! writeStr ( " \n " ) )
return false ;
if ( ! writeStr ( QByteArrayLiteral ( " namespace QmlCacheGeneratedCode { \n namespace " ) ) )
return false ;
if ( ! writeStr ( symbolNamespaceForPath ( inputFileName ) . toUtf8 ( ) ) )
return false ;
if ( ! writeStr ( QByteArrayLiteral ( " { \n extern const unsigned char qmlData alignas(16) [] = { \n " ) ) )
return false ;
2019-06-14 09:30:47 +00:00
unit . saveToDisk < uchar > ( [ & writeStr ] ( const uchar * begin , quint32 size ) {
QByteArray hexifiedData ;
{
QTextStream stream ( & hexifiedData ) ;
const uchar * end = begin + size ;
stream < < hex ;
int col = 0 ;
for ( const uchar * data = begin ; data < end ; + + data , + + col ) {
if ( data > begin )
stream < < ' , ' ;
if ( col % 8 = = 0 ) {
stream < < ' \n ' ;
col = 0 ;
}
stream < < " 0x " < < * data ;
2018-01-22 15:46:03 +00:00
}
2019-06-14 09:30:47 +00:00
stream < < ' \n ' ;
2018-01-22 15:46:03 +00:00
}
2019-06-14 09:30:47 +00:00
return writeStr ( hexifiedData ) ;
} ) ;
2018-01-22 15:46:03 +00:00
if ( ! writeStr ( " }; \n } \n } \n " ) )
return false ;
if ( ! f . commit ( ) ) {
* errorString = f . errorString ( ) ;
return false ;
}
return true ;
}
2016-12-30 15:11:20 +00:00
int main ( int argc , char * * argv )
{
// Produce reliably the same output for the same input by disabling QHash's random seeding.
2017-03-14 18:26:14 +00:00
qSetGlobalQHashSeed ( 0 ) ;
2016-12-30 15:11:20 +00:00
QCoreApplication app ( argc , argv ) ;
QCoreApplication : : setApplicationName ( QStringLiteral ( " qmlcachegen " ) ) ;
QCoreApplication : : setApplicationVersion ( QLatin1String ( QT_VERSION_STR ) ) ;
QCommandLineParser parser ;
parser . addHelpOption ( ) ;
parser . addVersionOption ( ) ;
2018-01-22 15:46:03 +00:00
QCommandLineOption filterResourceFileOption ( QStringLiteral ( " filter-resource-file " ) , QCoreApplication : : translate ( " main " , " Filter out QML/JS files from a resource file that can be cached ahead of time instead " ) ) ;
parser . addOption ( filterResourceFileOption ) ;
QCommandLineOption resourceFileMappingOption ( QStringLiteral ( " resource-file-mapping " ) , QCoreApplication : : translate ( " main " , " Path from original resource file to new one " ) , QCoreApplication : : translate ( " main " , " old-name:new-name " ) ) ;
parser . addOption ( resourceFileMappingOption ) ;
QCommandLineOption resourceOption ( QStringLiteral ( " resource " ) , QCoreApplication : : translate ( " main " , " Qt resource file that might later contain one of the compiled files " ) , QCoreApplication : : translate ( " main " , " resource-file-name " ) ) ;
parser . addOption ( resourceOption ) ;
2019-01-02 12:08:40 +00:00
QCommandLineOption retainOption ( QStringLiteral ( " retain " ) , QCoreApplication : : translate ( " main " , " Qt resource file the contents of which should not be replaced by empty stubs " ) , QCoreApplication : : translate ( " main " , " resource-file-name " ) ) ;
parser . addOption ( retainOption ) ;
2018-01-22 15:46:03 +00:00
QCommandLineOption resourcePathOption ( QStringLiteral ( " resource-path " ) , QCoreApplication : : translate ( " main " , " Qt resource file path corresponding to the file being compiled " ) , QCoreApplication : : translate ( " main " , " resource-path " ) ) ;
parser . addOption ( resourcePathOption ) ;
2017-03-02 14:52:38 +00:00
QCommandLineOption outputFileOption ( QStringLiteral ( " o " ) , QCoreApplication : : translate ( " main " , " Output file name " ) , QCoreApplication : : translate ( " main " , " file name " ) ) ;
parser . addOption ( outputFileOption ) ;
2016-12-30 15:11:20 +00:00
parser . addPositionalArgument ( QStringLiteral ( " [qml file] " ) ,
QStringLiteral ( " QML source file to generate cache for. " ) ) ;
2018-01-22 15:46:03 +00:00
parser . setSingleDashWordOptionMode ( QCommandLineParser : : ParseAsLongOptions ) ;
2016-12-30 15:11:20 +00:00
parser . process ( app ) ;
2018-02-02 14:22:44 +00:00
enum Output {
GenerateCpp ,
GenerateCacheFile ,
GenerateLoader
} target = GenerateCacheFile ;
QString outputFileName ;
if ( parser . isSet ( outputFileOption ) )
outputFileName = parser . value ( outputFileOption ) ;
if ( outputFileName . endsWith ( QLatin1String ( " .cpp " ) ) ) {
target = GenerateCpp ;
if ( outputFileName . endsWith ( QLatin1String ( " qmlcache_loader.cpp " ) ) )
target = GenerateLoader ;
}
2017-03-03 09:35:13 +00:00
const QStringList sources = parser . positionalArguments ( ) ;
if ( sources . isEmpty ( ) ) {
parser . showHelp ( ) ;
2018-02-02 14:22:44 +00:00
} else if ( sources . count ( ) > 1 & & target ! = GenerateLoader ) {
2017-03-03 09:35:13 +00:00
fprintf ( stderr , " %s \n " , qPrintable ( QStringLiteral ( " Too many input files specified: ' " ) + sources . join ( QStringLiteral ( " ' ' " ) ) + QLatin1Char ( ' \' ' ) ) ) ;
return EXIT_FAILURE ;
}
2018-02-02 14:22:44 +00:00
const QString inputFile = sources . first ( ) ;
if ( outputFileName . isEmpty ( ) )
outputFileName = inputFile + QLatin1Char ( ' c ' ) ;
2017-03-02 14:52:38 +00:00
2018-01-22 15:46:03 +00:00
if ( parser . isSet ( filterResourceFileOption ) ) {
return filterResourceFile ( inputFile , outputFileName ) ;
}
2018-02-02 14:22:44 +00:00
if ( target = = GenerateLoader ) {
ResourceFileMapper mapper ( sources ) ;
2019-01-02 12:08:40 +00:00
ResourceFileMapper retain ( parser . values ( retainOption ) ) ;
2018-01-22 15:46:03 +00:00
2018-02-02 14:22:44 +00:00
Error error ;
2019-01-02 12:08:40 +00:00
QStringList retainedFiles = retain . qmlCompilerFiles ( ) ;
std : : sort ( retainedFiles . begin ( ) , retainedFiles . end ( ) ) ;
if ( ! generateLoader ( mapper . qmlCompilerFiles ( ) , retainedFiles , outputFileName ,
parser . values ( resourceFileMappingOption ) , & error . message ) ) {
2018-01-22 15:46:03 +00:00
error . augment ( QLatin1String ( " Error generating loader stub: " ) ) . print ( ) ;
return EXIT_FAILURE ;
}
return EXIT_SUCCESS ;
}
QString inputFileUrl = inputFile ;
SaveFunction saveFunction ;
2018-02-02 14:22:44 +00:00
if ( target = = GenerateCpp ) {
2018-01-22 15:46:03 +00:00
ResourceFileMapper fileMapper ( parser . values ( resourceOption ) ) ;
QString inputResourcePath = parser . value ( resourcePathOption ) ;
if ( ! inputResourcePath . isEmpty ( ) & & ! fileMapper . isEmpty ( ) ) {
fprintf ( stderr , " --%s and --%s are mutually exclusive. \n " ,
qPrintable ( resourcePathOption . names ( ) . first ( ) ) ,
qPrintable ( resourceOption . names ( ) . first ( ) ) ) ;
return EXIT_FAILURE ;
}
// If the user didn't specify the resource path corresponding to the file on disk being
// compiled, try to determine it from the resource file, if one was supplied.
if ( inputResourcePath . isEmpty ( ) ) {
const QStringList resourcePaths = fileMapper . resourcePaths ( inputFile ) ;
if ( resourcePaths . isEmpty ( ) ) {
fprintf ( stderr , " No resource path for file: %s \n " , qPrintable ( inputFile ) ) ;
return EXIT_FAILURE ;
}
if ( resourcePaths . size ( ) ! = 1 ) {
fprintf ( stderr , " Multiple resource paths for file %s. "
" Use the --%s option to disambiguate: \n " ,
qPrintable ( inputFile ) ,
qPrintable ( resourcePathOption . names ( ) . first ( ) ) ) ;
for ( const QString & resourcePath : resourcePaths )
fprintf ( stderr , " \t %s \n " , qPrintable ( resourcePath ) ) ;
return EXIT_FAILURE ;
}
inputResourcePath = resourcePaths . first ( ) ;
}
inputFileUrl = QStringLiteral ( " qrc:// " ) + inputResourcePath ;
2019-05-07 10:47:33 +00:00
saveFunction = [ inputResourcePath , outputFileName ] (
2019-05-13 09:07:39 +00:00
const QV4 : : CompiledData : : SaveableUnitPointer & unit ,
2019-05-07 10:47:33 +00:00
QString * errorString ) {
2018-01-22 15:46:03 +00:00
return saveUnitAsCpp ( inputResourcePath , outputFileName , unit , errorString ) ;
} ;
} else {
2019-05-13 09:07:39 +00:00
saveFunction = [ outputFileName ] ( const QV4 : : CompiledData : : SaveableUnitPointer & unit ,
2019-05-07 10:47:33 +00:00
QString * errorString ) {
2019-06-14 09:30:47 +00:00
return unit . saveToDisk < char > (
[ & outputFileName , errorString ] ( const char * data , quint32 size ) {
return QV4 : : CompiledData : : SaveableUnitPointer : : writeDataToFile (
outputFileName , data , size , errorString ) ;
} ) ;
2018-01-22 15:46:03 +00:00
} ;
}
2018-01-18 09:31:08 +00:00
setupIllegalNames ( ) ;
2018-01-22 15:46:03 +00:00
2016-12-30 15:11:20 +00:00
if ( inputFile . endsWith ( QLatin1String ( " .qml " ) ) ) {
2018-02-02 14:22:44 +00:00
Error error ;
2018-01-22 15:46:03 +00:00
if ( ! compileQmlFile ( inputFile , saveFunction , & error ) ) {
2016-12-30 15:11:20 +00:00
error . augment ( QLatin1String ( " Error compiling qml file: " ) ) . print ( ) ;
return EXIT_FAILURE ;
}
2018-08-16 11:06:22 +00:00
} else if ( inputFile . endsWith ( QLatin1String ( " .js " ) ) | | inputFile . endsWith ( QLatin1String ( " .mjs " ) ) ) {
2018-02-02 14:22:44 +00:00
Error error ;
2018-01-22 15:46:03 +00:00
if ( ! compileJSFile ( inputFile , inputFileUrl , saveFunction , & error ) ) {
2018-02-20 15:21:38 +00:00
error . augment ( QLatin1String ( " Error compiling js file: " ) ) . print ( ) ;
2016-12-30 15:11:20 +00:00
return EXIT_FAILURE ;
}
} else {
2018-02-02 14:22:44 +00:00
fprintf ( stderr , " Ignoring %s input file as it is not QML source code - maybe remove from QML_FILES? \n " , qPrintable ( inputFile ) ) ;
}
2016-12-30 15:11:20 +00:00
return EXIT_SUCCESS ;
}