introduce ability to build projects for the host system

when qmake runs into the new option(host_build) command, it will restart
the project evaluation with a host spec.

the new default host spec is called default-host (gasp!). it is
overridden with the pre-exising -spec / -platform option, while the new
-xspec / -xplatform option overrides the pre-existing default spec.
specifying -spec but not -xspec will set the xspec, too, so the behavior
is backwards-compatible. same for the XQMAKESPEC override read from
.qmake.cache and the environment variable.
the cleaner solution would be adding -hostspec, to be symmetrical with
the override semantics, but that would deviate from configure in turn.

Change-Id: I4297c873780af16ab7928421b434ce0f1d3820da
Reviewed-by: Joerg Bornemann <joerg.bornemann@nokia.com>
This commit is contained in:
Oswald Buddenhagen 2012-01-31 18:36:18 +01:00
parent 528192a78b
commit 14bbab09c1
10 changed files with 128 additions and 55 deletions

12
configure vendored
View File

@ -3491,8 +3491,9 @@ if true; then ###[ '!' -f "$outpath/bin/qmake" ];
mv -f "$QMAKE_QCONFIG_H" "$QCONFIG_H" mv -f "$QMAKE_QCONFIG_H" "$QCONFIG_H"
#mkspecs/default is used as a (gasp!) default mkspec so QMAKESPEC needn't be set once configured #mkspecs/default is used as a (gasp!) default mkspec so QMAKESPEC needn't be set once configured
rm -rf mkspecs/default rm -rf mkspecs/default mkspecs/default-host
ln -s `echo $XQMAKESPEC | sed "s,^${relpath}/mkspecs/,,"` mkspecs/default ln -s `echo $XQMAKESPEC | sed "s,^${relpath}/mkspecs/,,"` mkspecs/default
ln -s `echo $QMAKESPEC | sed "s,^${relpath}/mkspecs/,,"` mkspecs/default-host
mkdir -p "$outpath/qmake" || exit mkdir -p "$outpath/qmake" || exit
# fix makefiles # fix makefiles
for mkfile in GNUmakefile Makefile; do for mkfile in GNUmakefile Makefile; do
@ -5906,9 +5907,14 @@ EOF
#dump the qmake spec #dump the qmake spec
if [ -d "$outpath/mkspecs/$XPLATFORM" ]; then if [ -d "$outpath/mkspecs/$XPLATFORM" ]; then
echo "QMAKESPEC = \$\$QT_BUILD_TREE/mkspecs/$XPLATFORM" >> "$CACHEFILE.tmp" echo "XQMAKESPEC = \$\$QT_BUILD_TREE/mkspecs/$XPLATFORM" >> "$CACHEFILE.tmp"
else else
echo "QMAKESPEC = $XPLATFORM" >> "$CACHEFILE.tmp" echo "XQMAKESPEC = $XPLATFORM" >> "$CACHEFILE.tmp"
fi
if [ -d "$outpath/mkspecs/$PLATFORM" ]; then
echo "QMAKESPEC = \$\$QT_BUILD_TREE/mkspecs/$PLATFORM" >> "$CACHEFILE.tmp"
else
echo "QMAKESPEC = $PLATFORM" >> "$CACHEFILE.tmp"
fi fi
# replace .qmake.cache if it differs from the newly created temp file # replace .qmake.cache if it differs from the newly created temp file

View File

@ -2193,7 +2193,9 @@ QString MakefileGenerator::buildArgs(const QString &outdir)
if(!Option::mkfile::do_dep_heuristics) if(!Option::mkfile::do_dep_heuristics)
ret += " -nodependheuristics"; ret += " -nodependheuristics";
if(!Option::mkfile::qmakespec_commandline.isEmpty()) if(!Option::mkfile::qmakespec_commandline.isEmpty())
ret += " -spec " + specdir(outdir); ret += " -spec " + specdir(outdir, 1);
if (!Option::mkfile::xqmakespec_commandline.isEmpty())
ret += " -xspec " + specdir(outdir, 0);
if (Option::target_mode_overridden) { if (Option::target_mode_overridden) {
if (Option::target_mode == Option::TARG_MACX_MODE) if (Option::target_mode == Option::TARG_MACX_MODE)
ret += " -macx"; ret += " -macx";
@ -3046,13 +3048,14 @@ QStringList
} }
QString QString
MakefileGenerator::specdir(const QString &outdir) MakefileGenerator::specdir(const QString &outdir, int host_build)
{ {
#if 0 #if 0
if(!spec.isEmpty()) if(!spec.isEmpty())
return spec; return spec;
#endif #endif
spec = fileFixify(Option::mkfile::qmakespec, outdir); spec = fileFixify((host_build >= 0 ? bool(host_build) : project->isHostBuild())
? Option::mkfile::qmakespec : Option::mkfile::xqmakespec, outdir);
return spec; return spec;
} }

View File

@ -187,7 +187,7 @@ protected:
//subclasses can use these to query information about how the generator was "run" //subclasses can use these to query information about how the generator was "run"
QString buildArgs(const QString &outdir=QString()); QString buildArgs(const QString &outdir=QString());
QString specdir(const QString &outdir=QString()); QString specdir(const QString &outdir = QString(), int host_build = -1);
virtual QStringList &findDependencies(const QString &file); virtual QStringList &findDependencies(const QString &file);
virtual bool doDepends() const { return Option::mkfile::do_deps; } virtual bool doDepends() const { return Option::mkfile::do_deps; }

View File

@ -649,12 +649,15 @@ nextfile:
t << _slnProjConfBeg; t << _slnProjConfBeg;
for(QList<VcsolutionDepend*>::Iterator it = solution_cleanup.begin(); it != solution_cleanup.end(); ++it) { for(QList<VcsolutionDepend*>::Iterator it = solution_cleanup.begin(); it != solution_cleanup.end(); ++it) {
QString platform = is64Bit ? "x64" : "Win32"; QString platform = is64Bit ? "x64" : "Win32";
QString xplatform = platform;
if (!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH")) if (!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH"))
platform = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")"; xplatform = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag1).arg(platform) << platform; if (!project->isHostBuild())
t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag2).arg(platform) << platform; platform = xplatform;
t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag1).arg(platform) << platform; t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag1).arg(xplatform) << platform;
t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag2).arg(platform) << platform; t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag2).arg(xplatform) << platform;
t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag1).arg(xplatform) << platform;
t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag2).arg(xplatform) << platform;
} }
t << _slnProjConfEnd; t << _slnProjConfEnd;
t << _slnExtSections; t << _slnExtSections;
@ -858,7 +861,7 @@ void VcprojGenerator::initProject()
} }
vcProject.Keyword = project->first("VCPROJ_KEYWORD"); vcProject.Keyword = project->first("VCPROJ_KEYWORD");
if (project->isEmpty("CE_SDK") || project->isEmpty("CE_ARCH")) { if (project->isHostBuild() || project->isEmpty("CE_SDK") || project->isEmpty("CE_ARCH")) {
vcProject.PlatformName = (is64Bit ? "x64" : "Win32"); vcProject.PlatformName = (is64Bit ? "x64" : "Win32");
} else { } else {
vcProject.PlatformName = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")"; vcProject.PlatformName = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
@ -922,7 +925,7 @@ void VcprojGenerator::initConfiguration()
if (conf.Name.isEmpty()) if (conf.Name.isEmpty())
conf.Name = isDebug ? "Debug" : "Release"; conf.Name = isDebug ? "Debug" : "Release";
conf.ConfigurationName = conf.Name; conf.ConfigurationName = conf.Name;
if (project->isEmpty("CE_SDK") || project->isEmpty("CE_ARCH")) { if (project->isHostBuild() || project->isEmpty("CE_SDK") || project->isEmpty("CE_ARCH")) {
conf.Name += (is64Bit ? "|x64" : "|Win32"); conf.Name += (is64Bit ? "|x64" : "|Win32");
} else { } else {
conf.Name += "|" + project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")"; conf.Name += "|" + project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
@ -948,7 +951,7 @@ void VcprojGenerator::initConfiguration()
initPreBuildEventTools(); initPreBuildEventTools();
initPostBuildEventTools(); initPostBuildEventTools();
// Only deploy for CE projects // Only deploy for CE projects
if (!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH")) if (!project->isHostBuild() && !project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH"))
initDeploymentTool(); initDeploymentTool();
initPreLinkEventTools(); initPreLinkEventTools();
@ -1084,7 +1087,7 @@ void VcprojGenerator::initPostBuildEventTools()
QString signature = !project->isEmpty("SIGNATURE_FILE") ? var("SIGNATURE_FILE") : var("DEFAULT_SIGNATURE"); QString signature = !project->isEmpty("SIGNATURE_FILE") ? var("SIGNATURE_FILE") : var("DEFAULT_SIGNATURE");
bool useSignature = !signature.isEmpty() && !project->isActiveConfig("staticlib") && bool useSignature = !signature.isEmpty() && !project->isActiveConfig("staticlib") &&
!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH"); !project->isHostBuild() && !project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH");
if (useSignature) { if (useSignature) {
conf.postBuild.CommandLine.prepend( conf.postBuild.CommandLine.prepend(
QLatin1String("signtool sign /F ") + signature + QLatin1String(" \"$(TargetPath)\"")); QLatin1String("signtool sign /F ") + signature + QLatin1String(" \"$(TargetPath)\""));
@ -1578,7 +1581,8 @@ QString VcprojGenerator::findTemplate(QString file)
{ {
QString ret; QString ret;
if(!exists((ret = file)) && if(!exists((ret = file)) &&
!exists((ret = QString(Option::mkfile::qmakespec + "/" + file))) && !exists((ret = QString((project->isHostBuild()
? Option::mkfile::qmakespec : Option::mkfile::xqmakespec) + '/' + file))) &&
!exists((ret = QString(QLibraryInfo::location(QLibraryInfo::HostDataPath) + "/win32-msvc.net/" + file))) && !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::HostDataPath) + "/win32-msvc.net/" + file))) &&
!exists((ret = QString(QLibraryInfo::location(QLibraryInfo::HostDataPath) + "/win32-msvc2002/" + file))) && !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::HostDataPath) + "/win32-msvc2002/" + file))) &&
!exists((ret = QString(QLibraryInfo::location(QLibraryInfo::HostDataPath) + "/win32-msvc2003/" + file))) && !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::HostDataPath) + "/win32-msvc2003/" + file))) &&

View File

@ -107,6 +107,7 @@ QStringList Option::projfile::project_dirs;
//QMAKE_GENERATE_MAKEFILE stuff //QMAKE_GENERATE_MAKEFILE stuff
QString Option::mkfile::qmakespec; QString Option::mkfile::qmakespec;
QString Option::mkfile::xqmakespec;
int Option::mkfile::cachefile_depth = -1; int Option::mkfile::cachefile_depth = -1;
bool Option::mkfile::do_deps = true; bool Option::mkfile::do_deps = true;
bool Option::mkfile::do_mocs = true; bool Option::mkfile::do_mocs = true;
@ -117,6 +118,7 @@ bool Option::mkfile::do_cache = true;
QString Option::mkfile::cachefile; QString Option::mkfile::cachefile;
QStringList Option::mkfile::project_files; QStringList Option::mkfile::project_files;
QString Option::mkfile::qmakespec_commandline; QString Option::mkfile::qmakespec_commandline;
QString Option::mkfile::xqmakespec_commandline;
static Option::QMAKE_MODE default_mode(QString progname) static Option::QMAKE_MODE default_mode(QString progname)
{ {
@ -327,6 +329,9 @@ Option::parseCommandLine(int argc, char **argv, int skip)
} else if(opt == "platform" || opt == "spec") { } else if(opt == "platform" || opt == "spec") {
Option::mkfile::qmakespec = cleanSpec(argv[++x]); Option::mkfile::qmakespec = cleanSpec(argv[++x]);
Option::mkfile::qmakespec_commandline = argv[x]; Option::mkfile::qmakespec_commandline = argv[x];
} else if (opt == "xplatform" || opt == "xspec") {
Option::mkfile::xqmakespec = cleanSpec(argv[++x]);
Option::mkfile::xqmakespec_commandline = argv[x];
} else { } else {
fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData()); fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR; return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
@ -381,6 +386,9 @@ Option::parseCommandLine(int argc, char **argv, int skip)
if (!user_configs.isEmpty()) if (!user_configs.isEmpty())
Option::before_user_vars += "CONFIG += " + user_configs.join(" "); Option::before_user_vars += "CONFIG += " + user_configs.join(" ");
if (Option::mkfile::xqmakespec.isEmpty())
Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
return Option::QMAKE_CMDLINE_SUCCESS; return Option::QMAKE_CMDLINE_SUCCESS;
} }
@ -536,8 +544,13 @@ Option::init(int argc, char **argv)
//last chance for defaults //last chance for defaults
if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
Option::qmake_mode == Option::QMAKE_GENERATE_PRL) { Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
if(Option::mkfile::qmakespec.isNull() || Option::mkfile::qmakespec.isEmpty()) if (Option::mkfile::xqmakespec.isEmpty())
Option::mkfile::xqmakespec = QString::fromLocal8Bit(qgetenv("XQMAKESPEC").constData());
if (Option::mkfile::qmakespec.isEmpty()) {
Option::mkfile::qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").constData()); Option::mkfile::qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").constData());
if (Option::mkfile::xqmakespec.isEmpty())
Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
}
//try REALLY hard to do it for them, lazy.. //try REALLY hard to do it for them, lazy..
if(Option::mkfile::project_files.isEmpty()) { if(Option::mkfile::project_files.isEmpty()) {

View File

@ -196,6 +196,7 @@ struct Option
//QMAKE_GENERATE_MAKEFILE options //QMAKE_GENERATE_MAKEFILE options
struct mkfile { struct mkfile {
static QString qmakespec; static QString qmakespec;
static QString xqmakespec;
static bool do_cache; static bool do_cache;
static bool do_deps; static bool do_deps;
static bool do_mocs; static bool do_mocs;
@ -206,6 +207,7 @@ struct Option
static int cachefile_depth; static int cachefile_depth;
static QStringList project_files; static QStringList project_files;
static QString qmakespec_commandline; static QString qmakespec_commandline;
static QString xqmakespec_commandline;
}; };
private: private:

View File

@ -531,7 +531,7 @@ static void qmake_error_msg(const QString &msg)
1) features/(unix|win32|macx)/ 1) features/(unix|win32|macx)/
2) features/ 2) features/
*/ */
QStringList qmake_feature_paths(QMakeProperty *prop=0) QStringList qmake_feature_paths(QMakeProperty *prop, bool host_build)
{ {
const QString mkspecs_concat = QLatin1String("/mkspecs"); const QString mkspecs_concat = QLatin1String("/mkspecs");
const QString base_concat = QLatin1String("/features"); const QString base_concat = QLatin1String("/features");
@ -578,12 +578,13 @@ QStringList qmake_feature_paths(QMakeProperty *prop=0)
feature_roots << ((*it) + mkspecs_concat + (*concat_it)); feature_roots << ((*it) + mkspecs_concat + (*concat_it));
} }
} }
if(!Option::mkfile::qmakespec.isEmpty()) { QString *specp = host_build ? &Option::mkfile::qmakespec : &Option::mkfile::xqmakespec;
if (!specp->isEmpty()) {
// The spec is already platform-dependent, so no subdirs here. // The spec is already platform-dependent, so no subdirs here.
feature_roots << Option::mkfile::qmakespec + base_concat; feature_roots << *specp + base_concat;
// Also check directly under the root directory of the mkspecs collection // Also check directly under the root directory of the mkspecs collection
QFileInfo specfi(Option::mkfile::qmakespec); QFileInfo specfi(*specp);
QDir specrootdir(specfi.absolutePath()); QDir specrootdir(specfi.absolutePath());
while (!specrootdir.isRoot()) { while (!specrootdir.isRoot()) {
const QString specrootpath = specrootdir.path(); const QString specrootpath = specrootdir.path();
@ -629,16 +630,7 @@ QMakeProject::~QMakeProject()
{ {
if(own_prop) if(own_prop)
delete prop; delete prop;
for(QHash<QString, FunctionBlock*>::iterator it = replaceFunctions.begin(); it != replaceFunctions.end(); ++it) { cleanup();
if(!it.value()->deref())
delete it.value();
}
replaceFunctions.clear();
for(QHash<QString, FunctionBlock*>::iterator it = testFunctions.begin(); it != testFunctions.end(); ++it) {
if(!it.value()->deref())
delete it.value();
}
testFunctions.clear();
} }
@ -653,14 +645,29 @@ QMakeProject::init(QMakeProperty *p)
own_prop = false; own_prop = false;
} }
recursive = false; recursive = false;
host_build = false;
reset(); reset();
} }
void
QMakeProject::cleanup()
{
for (QHash<QString, FunctionBlock*>::iterator it = replaceFunctions.begin(); it != replaceFunctions.end(); ++it)
if (!it.value()->deref())
delete it.value();
replaceFunctions.clear();
for (QHash<QString, FunctionBlock*>::iterator it = testFunctions.begin(); it != testFunctions.end(); ++it)
if (!it.value()->deref())
delete it.value();
testFunctions.clear();
}
// Duplicate project. It is *not* allowed to call the complex read() functions on the copy. // Duplicate project. It is *not* allowed to call the complex read() functions on the copy.
QMakeProject::QMakeProject(QMakeProject *p, const QHash<QString, QStringList> *_vars) QMakeProject::QMakeProject(QMakeProject *p, const QHash<QString, QStringList> *_vars)
{ {
init(p->properties()); init(p->properties());
vars = _vars ? *_vars : p->variables(); vars = _vars ? *_vars : p->variables();
host_build = p->host_build;
for(QHash<QString, FunctionBlock*>::iterator it = p->replaceFunctions.begin(); it != p->replaceFunctions.end(); ++it) { for(QHash<QString, FunctionBlock*>::iterator it = p->replaceFunctions.begin(); it != p->replaceFunctions.end(); ++it) {
it.value()->ref(); it.value()->ref();
replaceFunctions.insert(it.key(), it.value()); replaceFunctions.insert(it.key(), it.value());
@ -680,6 +687,7 @@ QMakeProject::reset()
iterator = 0; iterator = 0;
function = 0; function = 0;
backslashWarned = false; backslashWarned = false;
need_restart = false;
} }
bool bool
@ -1226,6 +1234,8 @@ QMakeProject::read(QTextStream &file, QHash<QString, QStringList> &place)
} }
s = ""; s = "";
numLines = 0; numLines = 0;
if (need_restart)
break;
} }
} }
} }
@ -1271,7 +1281,7 @@ QMakeProject::read(const QString &file, QHash<QString, QStringList> &place)
if(!using_stdin) if(!using_stdin)
qfile.close(); qfile.close();
} }
if(scope_blocks.count() != 1) { if (!need_restart && scope_blocks.count() != 1) {
qmake_error_msg("Unterminated conditional block at end of file"); qmake_error_msg("Unterminated conditional block at end of file");
ret = false; ret = false;
} }
@ -1290,6 +1300,7 @@ QMakeProject::read(const QString &project, uchar cmd)
bool bool
QMakeProject::read(uchar cmd) QMakeProject::read(uchar cmd)
{ {
again:
if ((cmd & ReadSetup) && base_vars.isEmpty()) { if ((cmd & ReadSetup) && base_vars.isEmpty()) {
// hack to get the Option stuff in there // hack to get the Option stuff in there
base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext; base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext;
@ -1320,8 +1331,13 @@ QMakeProject::read(uchar cmd)
Option::mkfile::cachefile.clear(); Option::mkfile::cachefile.clear();
goto no_cache; goto no_cache;
} }
if (Option::mkfile::qmakespec.isEmpty() && !cache["QMAKESPEC"].isEmpty()) if (Option::mkfile::xqmakespec.isEmpty() && !cache["XQMAKESPEC"].isEmpty())
Option::mkfile::xqmakespec = cache["XQMAKESPEC"].first();
if (Option::mkfile::qmakespec.isEmpty() && !cache["QMAKESPEC"].isEmpty()) {
Option::mkfile::qmakespec = cache["QMAKESPEC"].first(); Option::mkfile::qmakespec = cache["QMAKESPEC"].first();
if (Option::mkfile::xqmakespec.isEmpty())
Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
}
if (Option::output_dir.startsWith(project_build_root)) if (Option::output_dir.startsWith(project_build_root))
Option::mkfile::cachefile_depth = Option::mkfile::cachefile_depth =
@ -1355,9 +1371,10 @@ QMakeProject::read(uchar cmd)
} }
{ // parse mkspec { // parse mkspec
QString qmakespec = Option::mkfile::qmakespec; QString *specp = host_build ? &Option::mkfile::qmakespec : &Option::mkfile::xqmakespec;
QString qmakespec = *specp;
if (qmakespec.isEmpty()) if (qmakespec.isEmpty())
qmakespec = "default"; qmakespec = host_build ? "default-host" : "default";
if (QDir::isRelativePath(qmakespec)) { if (QDir::isRelativePath(qmakespec)) {
QStringList mkspec_roots = qmake_mkspec_paths(); QStringList mkspec_roots = qmake_mkspec_paths();
debug_msg(2, "Looking for mkspec %s in (%s)", qmakespec.toLatin1().constData(), debug_msg(2, "Looking for mkspec %s in (%s)", qmakespec.toLatin1().constData(),
@ -1367,7 +1384,7 @@ QMakeProject::read(uchar cmd)
QString mkspec = (*it) + QLatin1Char('/') + qmakespec; QString mkspec = (*it) + QLatin1Char('/') + qmakespec;
if (QFile::exists(mkspec)) { if (QFile::exists(mkspec)) {
found_mkspec = true; found_mkspec = true;
Option::mkfile::qmakespec = qmakespec = mkspec; *specp = qmakespec = mkspec;
break; break;
} }
} }
@ -1441,6 +1458,11 @@ QMakeProject::read(uchar cmd)
pfile += Option::pro_ext; pfile += Option::pro_ext;
if(!read(pfile, vars)) if(!read(pfile, vars))
return false; return false;
if (need_restart) {
base_vars.clear();
cleanup();
goto again;
}
} }
if (cmd & ReadSetup) { if (cmd & ReadSetup) {
@ -1537,7 +1559,7 @@ QMakeProject::resolveSpec(QString *spec, const QString &qmakespec)
{ {
if (spec->isEmpty()) { if (spec->isEmpty()) {
*spec = QFileInfo(qmakespec).fileName(); *spec = QFileInfo(qmakespec).fileName();
if (*spec == "default") { if (*spec == "default" || *spec == "default-host") {
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
char buffer[1024]; char buffer[1024];
int l = readlink(qmakespec.toLatin1().constData(), buffer, 1023); int l = readlink(qmakespec.toLatin1().constData(), buffer, 1023);
@ -1586,9 +1608,14 @@ QMakeProject::isActiveConfig(const QString &x, bool regex, QHash<QString, QStrin
return Option::target_mode == Option::TARG_WIN_MODE; return Option::target_mode == Option::TARG_WIN_MODE;
} }
if (x == "host_build")
return host_build ? "true" : "false";
//mkspecs //mkspecs
static QString spec; static QString hspec, xspec;
resolveSpec(&spec, Option::mkfile::qmakespec); resolveSpec(&hspec, Option::mkfile::qmakespec);
resolveSpec(&xspec, Option::mkfile::xqmakespec);
const QString &spec = host_build ? hspec : xspec;
QRegExp re(x, Qt::CaseSensitive, QRegExp::Wildcard); QRegExp re(x, Qt::CaseSensitive, QRegExp::Wildcard);
if((regex && re.exactMatch(spec)) || (!regex && spec == x)) if((regex && re.exactMatch(spec)) || (!regex && spec == x))
return true; return true;
@ -1646,9 +1673,10 @@ QMakeProject::doProjectInclude(QString file, uchar flags, QHash<QString, QString
file += Option::prf_ext; file += Option::prf_ext;
validateModes(); // init dir_sep validateModes(); // init dir_sep
if(file.indexOf(QLatin1Char('/')) == -1 || !QFile::exists(file)) { if(file.indexOf(QLatin1Char('/')) == -1 || !QFile::exists(file)) {
static QStringList *feature_roots = 0; static QStringList *all_feature_roots[2] = { 0, 0 };
QStringList *&feature_roots = all_feature_roots[host_build];
if(!feature_roots) { if(!feature_roots) {
feature_roots = new QStringList(qmake_feature_paths(prop)); feature_roots = new QStringList(qmake_feature_paths(prop, host_build));
qmakeAddCacheClear(qmakeDeleteCacheClear<QStringList>, (void**)&feature_roots); qmakeAddCacheClear(qmakeDeleteCacheClear<QStringList>, (void**)&feature_roots);
} }
debug_msg(2, "Looking for feature '%s' in (%s)", file.toLatin1().constData(), debug_msg(2, "Looking for feature '%s' in (%s)", file.toLatin1().constData(),
@ -2742,6 +2770,11 @@ QMakeProject::doProjectTest(QString func, QList<QStringList> args_list, QHash<QS
} }
if (args.first() == "recursive") { if (args.first() == "recursive") {
recursive = true; recursive = true;
} else if (args.first() == "host_build") {
if (!host_build && isActiveConfig("cross_compile")) {
host_build = true;
need_restart = true;
}
} else { } else {
fprintf(stderr, "%s:%d: unrecognized option() argument '%s'.\n", fprintf(stderr, "%s:%d: unrecognized option() argument '%s'.\n",
parser.file.toLatin1().constData(), parser.line_no, parser.file.toLatin1().constData(), parser.line_no,

View File

@ -79,6 +79,8 @@ class QMakeProject
QHash<QString, FunctionBlock*> testFunctions, replaceFunctions; QHash<QString, FunctionBlock*> testFunctions, replaceFunctions;
bool recursive; bool recursive;
bool host_build;
bool need_restart;
bool own_prop; bool own_prop;
bool backslashWarned; bool backslashWarned;
QString pfile; QString pfile;
@ -107,6 +109,7 @@ class QMakeProject
bool doVariableReplace(QString &str, QHash<QString, QStringList> &place); bool doVariableReplace(QString &str, QHash<QString, QStringList> &place);
QStringList doVariableReplaceExpand(const QString &str, QHash<QString, QStringList> &place, bool *ok=0); QStringList doVariableReplaceExpand(const QString &str, QHash<QString, QStringList> &place, bool *ok=0);
void init(QMakeProperty *); void init(QMakeProperty *);
void cleanup();
QStringList &values(const QString &v, QHash<QString, QStringList> &place); QStringList &values(const QString &v, QHash<QString, QStringList> &place);
void validateModes(); void validateModes();
void resolveSpec(QString *spec, const QString &qmakespec); void resolveSpec(QString *spec, const QString &qmakespec);
@ -160,6 +163,7 @@ public:
QHash<QString, QStringList> &variables(); // No compat mapping and magic, obviously QHash<QString, QStringList> &variables(); // No compat mapping and magic, obviously
bool isRecursive() const { return recursive; } bool isRecursive() const { return recursive; }
bool isHostBuild() const { return host_build; }
protected: protected:
friend class MakefileGenerator; friend class MakefileGenerator;

View File

@ -118,15 +118,17 @@ INSTALLS += configtests
mkspecs.path = $$[QT_HOST_DATA]/mkspecs mkspecs.path = $$[QT_HOST_DATA]/mkspecs
mkspecs.files = $$OUT_PWD/mkspecs/qconfig.pri $$OUT_PWD/mkspecs/qmodule.pri $$OUT_PWD/mkspecs/qdevice.pri $$files($$PWD/mkspecs/*) mkspecs.files = $$OUT_PWD/mkspecs/qconfig.pri $$OUT_PWD/mkspecs/qmodule.pri $$OUT_PWD/mkspecs/qdevice.pri $$files($$PWD/mkspecs/*)
mkspecs.files -= $$PWD/mkspecs/modules mkspecs.files -= $$PWD/mkspecs/modules
unix { unix {
DEFAULT_QMAKESPEC = $$QMAKESPEC DEFAULT_QMAKESPEC = $$replace(QMAKESPEC, ^.*mkspecs/, )
DEFAULT_QMAKESPEC ~= s,^.*mkspecs/,,g DEFAULT_XQMAKESPEC = $$replace(XQMAKESPEC, ^.*mkspecs/, )
mkspecs.commands += $(DEL_FILE) $(INSTALL_ROOT)$$mkspecs.path/default; $(SYMLINK) $$DEFAULT_QMAKESPEC $(INSTALL_ROOT)$$mkspecs.path/default mkspecs.commands = \
mkspecs.files -= $$PWD/mkspecs/default $(DEL_FILE) $(INSTALL_ROOT)$$mkspecs.path/default-host $(INSTALL_ROOT)$$mkspecs.path/default; \
} $(SYMLINK) $$DEFAULT_QMAKESPEC $(INSTALL_ROOT)$$mkspecs.path/default-host && \
win32:!equals(OUT_PWD, $$PWD) { $(SYMLINK) $$DEFAULT_XQMAKESPEC $(INSTALL_ROOT)$$mkspecs.path/default
mkspecs.files -= $$PWD/mkspecs/default-host $$PWD/mkspecs/default
} else:!equals(OUT_PWD, $$PWD) {
# When shadow building on Windows, the default mkspec only exists in the build tree. # When shadow building on Windows, the default mkspec only exists in the build tree.
mkspecs.files += $$OUT_PWD/mkspecs/default mkspecs.files += $$OUT_PWD/mkspecs/default-host $$OUT_PWD/mkspecs/default
} }
INSTALLS += mkspecs INSTALLS += mkspecs

View File

@ -2583,13 +2583,18 @@ void Configure::generateCachefile()
moduleStream << "QMAKE_INCDIR_QT = $$QT_BUILD_TREE" << fixSeparators("/include", true) << endl; moduleStream << "QMAKE_INCDIR_QT = $$QT_BUILD_TREE" << fixSeparators("/include", true) << endl;
moduleStream << "QMAKE_LIBDIR_QT = $$QT_BUILD_TREE" << fixSeparators("/lib", true) << endl; moduleStream << "QMAKE_LIBDIR_QT = $$QT_BUILD_TREE" << fixSeparators("/lib", true) << endl;
QString hostSpec = dictionary[ "QMAKESPEC" ];
QString targetSpec = dictionary.contains("XQMAKESPEC") ? dictionary[ "XQMAKESPEC" ] : dictionary[ "QMAKESPEC" ]; QString targetSpec = dictionary.contains("XQMAKESPEC") ? dictionary[ "XQMAKESPEC" ] : hostSpec;
QString mkspec_path = fixSeparators(sourcePath + "/mkspecs/" + targetSpec); QString xmkspec_path = fixSeparators(sourcePath + "/mkspecs/" + targetSpec);
if (QFile::exists(xmkspec_path))
moduleStream << "XQMAKESPEC = " << escapeSeparators(xmkspec_path) << endl;
else
moduleStream << "XQMAKESPEC = " << fixSeparators(targetSpec, true) << endl;
QString mkspec_path = fixSeparators(sourcePath + "/mkspecs/" + hostSpec);
if (QFile::exists(mkspec_path)) if (QFile::exists(mkspec_path))
moduleStream << "QMAKESPEC = " << escapeSeparators(mkspec_path) << endl; moduleStream << "QMAKESPEC = " << escapeSeparators(mkspec_path) << endl;
else else
moduleStream << "QMAKESPEC = " << fixSeparators(targetSpec, true) << endl; moduleStream << "QMAKESPEC = " << fixSeparators(hostSpec, true) << endl;
if (dictionary["QT_EDITION"] != "QT_EDITION_OPENSOURCE") if (dictionary["QT_EDITION"] != "QT_EDITION_OPENSOURCE")
moduleStream << "DEFINES *= QT_EDITION=QT_EDITION_DESKTOP" << endl; moduleStream << "DEFINES *= QT_EDITION=QT_EDITION_DESKTOP" << endl;
@ -3109,7 +3114,8 @@ void Configure::generateConfigfiles()
} }
QString spec = dictionary.contains("XQMAKESPEC") ? dictionary["XQMAKESPEC"] : dictionary["QMAKESPEC"]; QString spec = dictionary.contains("XQMAKESPEC") ? dictionary["XQMAKESPEC"] : dictionary["QMAKESPEC"];
if (!copySpec("default", "", spec)) if (!copySpec("default", "", spec)
|| !copySpec("default-host", "host ", dictionary["QMAKESPEC"]))
return; return;
// Generate the new qconfig.cpp file // Generate the new qconfig.cpp file