2011-04-27 10:05:43 +00:00
/****************************************************************************
* *
2013-01-02 11:13:29 +00:00
* * Copyright ( C ) 2013 Digia Plc and / or its subsidiary ( - ies ) .
2012-09-19 12:28:29 +00:00
* * Contact : http : //www.qt-project.org/legal
2011-04-27 10:05:43 +00:00
* *
* * This file is part of the qmake application of the Qt Toolkit .
* *
* * $ QT_BEGIN_LICENSE : LGPL $
2012-09-19 12:28:29 +00:00
* * 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 Digia . For licensing terms and
* * conditions see http : //qt.digia.com/licensing. For further information
* * use the contact form at http : //qt.digia.com/contact-us.
* *
2011-04-27 10:05:43 +00:00
* * GNU Lesser General Public License Usage
2012-09-19 12:28:29 +00:00
* * Alternatively , this file may be used under the terms of the GNU Lesser
* * General Public License version 2.1 as published by the Free Software
* * Foundation and appearing in the file LICENSE . LGPL included in the
* * packaging of this file . Please review the following information to
* * ensure the GNU Lesser General Public License version 2.1 requirements
* * will be met : http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
2011-04-27 10:05:43 +00:00
* *
2012-09-19 12:28:29 +00:00
* * In addition , as a special exception , Digia gives you certain additional
* * rights . These rights are described in the Digia Qt LGPL Exception
2011-04-27 10:05:43 +00:00
* * version 1.1 , included in the file LGPL_EXCEPTION . txt in this package .
* *
2011-05-24 09:34:08 +00:00
* * GNU General Public License Usage
2012-09-19 12:28:29 +00:00
* * Alternatively , this file may be used under the terms of the GNU
* * General Public License version 3.0 as published by the Free Software
* * Foundation and appearing in the file LICENSE . GPL included in the
* * packaging of this file . Please review the following information to
* * ensure the GNU General Public License version 3.0 requirements will be
* * met : http : //www.gnu.org/copyleft/gpl.html.
2011-04-27 10:05:43 +00:00
* *
2012-01-24 06:17:24 +00:00
* *
2011-04-27 10:05:43 +00:00
* * $ QT_END_LICENSE $
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "metamakefile.h"
# include "qregexp.h"
# include "qdir.h"
# include "qdebug.h"
# include "makefile.h"
# include "project.h"
# include "cachekeys.h"
# define BUILDSMETATYPE 1
# define SUBDIRSMETATYPE 2
QT_BEGIN_NAMESPACE
MetaMakefileGenerator : : ~ MetaMakefileGenerator ( )
{
if ( own_project )
delete project ;
}
# ifndef QT_QMAKE_PARSER_ONLY
class BuildsMetaMakefileGenerator : public MetaMakefileGenerator
{
private :
bool init_flag ;
struct Build {
QString name , build ;
MakefileGenerator * makefile ;
} ;
QList < Build * > makefiles ;
void clearBuilds ( ) ;
2012-09-06 10:21:38 +00:00
MakefileGenerator * processBuild ( const ProString & ) ;
2011-04-27 10:05:43 +00:00
public :
BuildsMetaMakefileGenerator ( QMakeProject * p , const QString & n , bool op ) : MetaMakefileGenerator ( p , n , op ) , init_flag ( false ) { }
virtual ~ BuildsMetaMakefileGenerator ( ) { clearBuilds ( ) ; }
virtual bool init ( ) ;
virtual int type ( ) const { return BUILDSMETATYPE ; }
virtual bool write ( const QString & ) ;
} ;
void
BuildsMetaMakefileGenerator : : clearBuilds ( )
{
for ( int i = 0 ; i < makefiles . count ( ) ; i + + ) {
Build * build = makefiles [ i ] ;
if ( QMakeProject * p = build - > makefile - > projectFile ( ) ) {
if ( p ! = project )
delete p ;
}
delete build - > makefile ;
delete build ;
}
makefiles . clear ( ) ;
}
bool
BuildsMetaMakefileGenerator : : init ( )
{
if ( init_flag )
return false ;
init_flag = true ;
2012-09-06 10:21:38 +00:00
const ProStringList & builds = project - > values ( " BUILDS " ) ;
2011-04-27 10:05:43 +00:00
bool use_single_build = builds . isEmpty ( ) ;
if ( builds . count ( ) > 1 & & Option : : output . fileName ( ) = = " - " ) {
use_single_build = true ;
warn_msg ( WarnLogic , " Cannot direct to stdout when using multiple BUILDS. " ) ;
} else if ( 0 & & ! use_single_build & & project - > first ( " TEMPLATE " ) = = " subdirs " ) {
use_single_build = true ;
warn_msg ( WarnLogic , " Cannot specify multiple builds with TEMPLATE subdirs. " ) ;
}
if ( ! use_single_build ) {
for ( int i = 0 ; i < builds . count ( ) ; i + + ) {
2012-09-06 10:21:38 +00:00
ProString build = builds [ i ] ;
2011-04-27 10:05:43 +00:00
MakefileGenerator * makefile = processBuild ( build ) ;
if ( ! makefile )
return false ;
if ( ! makefile - > supportsMetaBuild ( ) ) {
warn_msg ( WarnLogic , " QMAKESPEC does not support multiple BUILDS. " ) ;
clearBuilds ( ) ;
use_single_build = true ;
break ;
} else {
Build * b = new Build ;
b - > name = name ;
if ( builds . count ( ) ! = 1 )
2012-09-06 10:21:38 +00:00
b - > build = build . toQString ( ) ;
2011-04-27 10:05:43 +00:00
b - > makefile = makefile ;
makefiles + = b ;
}
}
}
if ( use_single_build ) {
Build * build = new Build ;
build - > name = name ;
build - > makefile = createMakefileGenerator ( project , false ) ;
if ( build - > makefile ) {
makefiles + = build ;
} else {
delete build ;
return false ;
}
}
return true ;
}
bool
BuildsMetaMakefileGenerator : : write ( const QString & oldpwd )
{
Build * glue = 0 ;
if ( ! makefiles . isEmpty ( ) & & ! makefiles . first ( ) - > build . isNull ( ) ) {
glue = new Build ;
glue - > name = name ;
glue - > makefile = createMakefileGenerator ( project , true ) ;
makefiles + = glue ;
}
bool ret = true ;
const QString & output_name = Option : : output . fileName ( ) ;
for ( int i = 0 ; ret & & i < makefiles . count ( ) ; i + + ) {
Option : : output . setFileName ( output_name ) ;
Build * build = makefiles [ i ] ;
bool using_stdout = false ;
if ( build - > makefile & & ( Option : : qmake_mode = = Option : : QMAKE_GENERATE_MAKEFILE | |
Option : : qmake_mode = = Option : : QMAKE_GENERATE_PROJECT )
& & ( ! build - > makefile - > supportsMergedBuilds ( )
| | ( build - > makefile - > supportsMergedBuilds ( ) & & ( ! glue | | build = = glue ) ) ) ) {
//open output
if ( ! ( Option : : output . isOpen ( ) ) ) {
if ( Option : : output . fileName ( ) = = " - " ) {
Option : : output . setFileName ( " " ) ;
Option : : output_dir = qmake_getpwd ( ) ;
Option : : output . open ( stdout , QIODevice : : WriteOnly | QIODevice : : Text ) ;
using_stdout = true ;
} else {
if ( Option : : output . fileName ( ) . isEmpty ( ) & &
Option : : qmake_mode = = Option : : QMAKE_GENERATE_MAKEFILE )
2012-09-06 10:21:38 +00:00
Option : : output . setFileName ( project - > first ( " QMAKE_MAKEFILE " ) . toQString ( ) ) ;
2011-04-27 10:05:43 +00:00
Option : : output_dir = oldpwd ;
QString build_name = build - > name ;
if ( ! build - > build . isEmpty ( ) ) {
if ( ! build_name . isEmpty ( ) )
build_name + = " . " ;
build_name + = build - > build ;
}
if ( ! build - > makefile - > openOutput ( Option : : output , build_name ) ) {
fprintf ( stderr , " Failure to open file: %s \n " ,
Option : : output . fileName ( ) . isEmpty ( ) ? " (stdout) " :
Option : : output . fileName ( ) . toLatin1 ( ) . constData ( ) ) ;
return false ;
}
}
}
} else {
using_stdout = true ; //kind of..
}
if ( ! build - > makefile ) {
ret = false ;
} else if ( build = = glue ) {
ret = build - > makefile - > writeProjectMakefile ( ) ;
} else {
ret = build - > makefile - > write ( ) ;
if ( glue & & glue - > makefile - > supportsMergedBuilds ( ) )
ret = glue - > makefile - > mergeBuildProject ( build - > makefile ) ;
}
if ( ! using_stdout ) {
Option : : output . close ( ) ;
if ( ! ret )
Option : : output . remove ( ) ;
}
}
return ret ;
}
MakefileGenerator
2012-09-06 10:21:38 +00:00
* BuildsMetaMakefileGenerator : : processBuild ( const ProString & build )
2011-04-27 10:05:43 +00:00
{
if ( project ) {
debug_msg ( 1 , " Meta Generator: Parsing '%s' for build [%s]. " ,
project - > projectFile ( ) . toLatin1 ( ) . constData ( ) , build . toLatin1 ( ) . constData ( ) ) ;
//initialize the base
2012-09-06 10:21:38 +00:00
ProValueMap basevars ;
ProStringList basecfgs = project - > values ( ProKey ( build + " .CONFIG " ) ) ;
2012-02-21 11:44:27 +00:00
basecfgs + = build ;
basecfgs + = " build_pass " ;
2012-09-06 10:21:38 +00:00
basevars [ " BUILD_PASS " ] = ProStringList ( build ) ;
ProStringList buildname = project - > values ( ProKey ( build + " .name " ) ) ;
basevars [ " BUILD_NAME " ] = ( buildname . isEmpty ( ) ? ProStringList ( build ) : buildname ) ;
2011-04-27 10:05:43 +00:00
//create project
2012-09-05 16:29:19 +00:00
QMakeProject * build_proj = new QMakeProject ;
2012-02-21 11:56:47 +00:00
build_proj - > setExtraVars ( basevars ) ;
2012-02-21 11:44:27 +00:00
build_proj - > setExtraConfigs ( basecfgs ) ;
2011-04-27 10:05:43 +00:00
build_proj - > read ( project - > projectFile ( ) ) ;
//done
return createMakefileGenerator ( build_proj ) ;
}
return 0 ;
}
class SubdirsMetaMakefileGenerator : public MetaMakefileGenerator
{
protected :
bool init_flag ;
struct Subdir {
Subdir ( ) : makefile ( 0 ) , indent ( 0 ) { }
~ Subdir ( ) { delete makefile ; }
QString input_dir ;
QString output_dir , output_file ;
MetaMakefileGenerator * makefile ;
int indent ;
} ;
QList < Subdir * > subs ;
MakefileGenerator * processBuild ( const QString & ) ;
public :
SubdirsMetaMakefileGenerator ( QMakeProject * p , const QString & n , bool op ) : MetaMakefileGenerator ( p , n , op ) , init_flag ( false ) { }
virtual ~ SubdirsMetaMakefileGenerator ( ) ;
virtual bool init ( ) ;
virtual int type ( ) const { return SUBDIRSMETATYPE ; }
virtual bool write ( const QString & ) ;
} ;
bool
SubdirsMetaMakefileGenerator : : init ( )
{
if ( init_flag )
return false ;
init_flag = true ;
bool hasError = false ;
2012-05-04 18:02:35 +00:00
bool recurse = Option : : recursive ;
2012-05-10 14:49:13 +00:00
if ( recurse & & project - > isActiveConfig ( " dont_recurse " ) )
recurse = false ;
2011-04-27 10:05:43 +00:00
if ( recurse ) {
QString old_output_dir = Option : : output_dir ;
QString old_output = Option : : output . fileName ( ) ;
QString oldpwd = qmake_getpwd ( ) ;
QString thispwd = oldpwd ;
if ( ! thispwd . endsWith ( ' / ' ) )
thispwd + = ' / ' ;
2012-09-06 10:21:38 +00:00
const ProStringList & subdirs = project - > values ( " SUBDIRS " ) ;
2011-04-27 10:05:43 +00:00
static int recurseDepth = - 1 ;
+ + recurseDepth ;
for ( int i = 0 ; i < subdirs . size ( ) ; + + i ) {
Subdir * sub = new Subdir ;
sub - > indent = recurseDepth ;
2012-09-06 10:21:38 +00:00
QFileInfo subdir ( subdirs . at ( i ) . toQString ( ) ) ;
const ProKey fkey ( subdirs . at ( i ) + " .file " ) ;
if ( ! project - > isEmpty ( fkey ) ) {
subdir = project - > first ( fkey ) . toQString ( ) ;
} else {
const ProKey skey ( subdirs . at ( i ) + " .subdir " ) ;
if ( ! project - > isEmpty ( skey ) )
subdir = project - > first ( skey ) . toQString ( ) ;
}
2011-04-27 10:05:43 +00:00
QString sub_name ;
if ( subdir . isDir ( ) )
subdir = QFileInfo ( subdir . filePath ( ) + " / " + subdir . fileName ( ) + Option : : pro_ext ) ;
else
sub_name = subdir . baseName ( ) ;
if ( ! subdir . isRelative ( ) ) { //we can try to make it relative
QString subdir_path = subdir . filePath ( ) ;
if ( subdir_path . startsWith ( thispwd ) )
subdir = QFileInfo ( subdir_path . mid ( thispwd . length ( ) ) ) ;
}
//handle sub project
2012-09-05 16:29:19 +00:00
QMakeProject * sub_proj = new QMakeProject ;
2011-04-27 10:05:43 +00:00
for ( int ind = 0 ; ind < sub - > indent ; + + ind )
printf ( " " ) ;
sub - > input_dir = subdir . absolutePath ( ) ;
if ( subdir . isRelative ( ) & & old_output_dir ! = oldpwd ) {
2012-05-14 13:13:12 +00:00
sub - > output_dir = old_output_dir + ( subdir . path ( ) ! = " . " ? " / " + subdir . path ( ) : QString ( ) ) ;
2011-04-27 10:05:43 +00:00
printf ( " Reading %s [%s] \n " , subdir . absoluteFilePath ( ) . toLatin1 ( ) . constData ( ) , sub - > output_dir . toLatin1 ( ) . constData ( ) ) ;
} else { //what about shadow builds?
sub - > output_dir = sub - > input_dir ;
printf ( " Reading %s \n " , subdir . absoluteFilePath ( ) . toLatin1 ( ) . constData ( ) ) ;
}
qmake_setpwd ( sub - > input_dir ) ;
Option : : output_dir = sub - > output_dir ;
bool tmpError = ! sub_proj - > read ( subdir . fileName ( ) ) ;
2012-04-23 16:08:16 +00:00
if ( ! sub_proj - > isEmpty ( " QMAKE_FAILED_REQUIREMENTS " ) ) {
2011-04-27 10:05:43 +00:00
fprintf ( stderr , " Project file(%s) not recursed because all requirements not met: \n \t %s \n " ,
subdir . fileName ( ) . toLatin1 ( ) . constData ( ) ,
2012-05-18 18:00:23 +00:00
sub_proj - > values ( " QMAKE_FAILED_REQUIREMENTS " ) . join ( ' ' ) . toLatin1 ( ) . constData ( ) ) ;
2011-04-27 10:05:43 +00:00
delete sub ;
delete sub_proj ;
Option : : output_dir = old_output_dir ;
qmake_setpwd ( oldpwd ) ;
continue ;
} else {
hasError | = tmpError ;
}
sub - > makefile = MetaMakefileGenerator : : createMetaGenerator ( sub_proj , sub_name ) ;
if ( 0 & & sub - > makefile - > type ( ) = = SUBDIRSMETATYPE ) {
subs . append ( sub ) ;
} else {
const QString output_name = Option : : output . fileName ( ) ;
Option : : output . setFileName ( sub - > output_file ) ;
hasError | = ! sub - > makefile - > write ( sub - > output_dir ) ;
delete sub ;
qmakeClearCaches ( ) ;
sub = 0 ;
Option : : output . setFileName ( output_name ) ;
}
Option : : output_dir = old_output_dir ;
qmake_setpwd ( oldpwd ) ;
}
- - recurseDepth ;
Option : : output . setFileName ( old_output ) ;
Option : : output_dir = old_output_dir ;
qmake_setpwd ( oldpwd ) ;
}
Subdir * self = new Subdir ;
self - > input_dir = qmake_getpwd ( ) ;
self - > output_dir = Option : : output_dir ;
if ( ! recurse | | ( ! Option : : output . fileName ( ) . endsWith ( Option : : dir_sep ) & & ! QFileInfo ( Option : : output ) . isDir ( ) ) )
self - > output_file = Option : : output . fileName ( ) ;
self - > makefile = new BuildsMetaMakefileGenerator ( project , name , false ) ;
self - > makefile - > init ( ) ;
subs . append ( self ) ;
return ! hasError ;
}
bool
SubdirsMetaMakefileGenerator : : write ( const QString & oldpwd )
{
bool ret = true ;
const QString & pwd = qmake_getpwd ( ) ;
const QString & output_dir = Option : : output_dir ;
const QString & output_name = Option : : output . fileName ( ) ;
for ( int i = 0 ; ret & & i < subs . count ( ) ; i + + ) {
const Subdir * sub = subs . at ( i ) ;
qmake_setpwd ( subs . at ( i ) - > input_dir ) ;
Option : : output_dir = QFileInfo ( subs . at ( i ) - > output_dir ) . absoluteFilePath ( ) ;
if ( Option : : output_dir . at ( Option : : output_dir . length ( ) - 1 ) ! = QLatin1Char ( ' / ' ) )
Option : : output_dir + = QLatin1Char ( ' / ' ) ;
Option : : output . setFileName ( subs . at ( i ) - > output_file ) ;
if ( i ! = subs . count ( ) - 1 ) {
for ( int ind = 0 ; ind < sub - > indent ; + + ind )
printf ( " " ) ;
printf ( " Writing %s \n " , QDir : : cleanPath ( Option : : output_dir + " / " +
Option : : output . fileName ( ) ) . toLatin1 ( ) . constData ( ) ) ;
}
QString writepwd = Option : : fixPathToLocalOS ( qmake_getpwd ( ) ) ;
if ( ! writepwd . startsWith ( Option : : fixPathToLocalOS ( oldpwd ) ) )
writepwd = oldpwd ;
if ( ! ( ret = subs . at ( i ) - > makefile - > write ( writepwd ) ) )
break ;
//restore because I'm paranoid
qmake_setpwd ( pwd ) ;
Option : : output . setFileName ( output_name ) ;
Option : : output_dir = output_dir ;
}
return ret ;
}
SubdirsMetaMakefileGenerator : : ~ SubdirsMetaMakefileGenerator ( )
{
for ( int i = 0 ; i < subs . count ( ) ; i + + )
delete subs [ i ] ;
subs . clear ( ) ;
}
//Factory things
QT_BEGIN_INCLUDE_NAMESPACE
# include "unixmake.h"
# include "mingw_make.h"
# include "projectgenerator.h"
# include "pbuilder_pbx.h"
# include "msvc_nmake.h"
# include "msvc_vcproj.h"
# include "msvc_vcxproj.h"
# include "gbuild.h"
QT_END_INCLUDE_NAMESPACE
MakefileGenerator *
MetaMakefileGenerator : : createMakefileGenerator ( QMakeProject * proj , bool noIO )
{
2012-03-07 12:31:04 +00:00
Option : : postProcessProject ( proj ) ;
2011-04-27 10:05:43 +00:00
MakefileGenerator * mkfile = NULL ;
if ( Option : : qmake_mode = = Option : : QMAKE_GENERATE_PROJECT ) {
mkfile = new ProjectGenerator ;
mkfile - > setProjectFile ( proj ) ;
return mkfile ;
}
2012-09-06 10:21:38 +00:00
ProString gen = proj - > first ( " MAKEFILE_GENERATOR " ) ;
2011-04-27 10:05:43 +00:00
if ( gen . isEmpty ( ) ) {
fprintf ( stderr , " MAKEFILE_GENERATOR variable not set as a result of parsing : %s. Possibly qmake was not able to find files included using \" include(..) \" - enable qmake debugging to investigate more. \n " ,
proj - > projectFile ( ) . toLatin1 ( ) . constData ( ) ) ;
} else if ( gen = = " UNIX " ) {
mkfile = new UnixMakefileGenerator ;
} else if ( gen = = " MINGW " ) {
mkfile = new MingwMakefileGenerator ;
} else if ( gen = = " PROJECTBUILDER " | | gen = = " XCODE " ) {
mkfile = new ProjectBuilderMakefileGenerator ;
} else if ( gen = = " MSVC.NET " ) {
if ( proj - > first ( " TEMPLATE " ) . startsWith ( " vc " ) )
mkfile = new VcprojGenerator ;
else
mkfile = new NmakeMakefileGenerator ;
} else if ( gen = = " MSBUILD " ) {
// Visual Studio >= v11.0
if ( proj - > first ( " TEMPLATE " ) . startsWith ( " vc " ) )
mkfile = new VcxprojGenerator ;
else
mkfile = new NmakeMakefileGenerator ;
} else if ( gen = = " GBUILD " ) {
mkfile = new GBuildMakefileGenerator ;
} else {
fprintf ( stderr , " Unknown generator specified: %s \n " , gen . toLatin1 ( ) . constData ( ) ) ;
}
if ( mkfile ) {
mkfile - > setNoIO ( noIO ) ;
mkfile - > setProjectFile ( proj ) ;
}
return mkfile ;
}
MetaMakefileGenerator *
MetaMakefileGenerator : : createMetaGenerator ( QMakeProject * proj , const QString & name , bool op , bool * success )
{
2012-03-07 12:31:04 +00:00
Option : : postProcessProject ( proj ) ;
2011-04-27 10:05:43 +00:00
MetaMakefileGenerator * ret = 0 ;
if ( ( Option : : qmake_mode = = Option : : QMAKE_GENERATE_MAKEFILE | |
Option : : qmake_mode = = Option : : QMAKE_GENERATE_PRL ) ) {
if ( proj - > first ( " TEMPLATE " ) . endsWith ( " subdirs " ) )
ret = new SubdirsMetaMakefileGenerator ( proj , name , op ) ;
}
if ( ! ret )
ret = new BuildsMetaMakefileGenerator ( proj , name , op ) ;
bool res = ret - > init ( ) ;
if ( success )
* success = res ;
return ret ;
}
# endif // QT_QMAKE_PARSER_ONLY
QT_END_NAMESPACE