summaryrefslogtreecommitdiffstats
path: root/qmake
diff options
context:
space:
mode:
Diffstat (limited to 'qmake')
-rw-r--r--qmake/Makefile.unix7
-rw-r--r--qmake/Makefile.win322
-rw-r--r--qmake/Makefile.win32-g++3
-rw-r--r--qmake/generators/makefile.cpp188
-rw-r--r--qmake/generators/makefile.h8
-rw-r--r--qmake/generators/metamakefile.cpp4
-rw-r--r--qmake/generators/unix/unixmake.cpp2
-rw-r--r--qmake/generators/win32/cesdkhandler.cpp127
-rw-r--r--qmake/generators/win32/cesdkhandler.h94
-rw-r--r--qmake/generators/win32/msvc_nmake.cpp25
-rw-r--r--qmake/generators/win32/msvc_vcproj.cpp36
-rw-r--r--qmake/generators/win32/msvc_vcproj.h1
-rw-r--r--qmake/main.cpp5
-rw-r--r--qmake/option.cpp134
-rw-r--r--qmake/option.h14
-rw-r--r--qmake/project.cpp1020
-rw-r--r--qmake/project.h9
-rw-r--r--qmake/property.cpp10
-rw-r--r--qmake/qmake.pri6
-rw-r--r--qmake/qmake.pro1
20 files changed, 1347 insertions, 349 deletions
diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix
index ad430e2930..b1df49aab3 100644
--- a/qmake/Makefile.unix
+++ b/qmake/Makefile.unix
@@ -13,7 +13,7 @@ OBJS=project.o property.o main.o makefile.o unixmake2.o unixmake.o \
mingw_make.o option.o winmakefile.o projectgenerator.o \
meta.o makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o \
borland_bmake.o msvc_vcproj.o msvc_vcxproj.o msvc_nmake.o msvc_objectmodel.o msbuild_objectmodel.o \
- gbuild.o
+ gbuild.o cesdkhandler.o
#qt code
QOBJS=qtextcodec.o qutfcodec.o qstring.o qstringbuilder.o qtextstream.o qiodevice.o qmalloc.o qglobal.o \
@@ -36,7 +36,7 @@ DEPEND_SRC=project.cpp property.cpp meta.cpp main.cpp generators/makefile.cpp ge
generators/mac/pbuilder_pbx.cpp generators/mac/xmloutput.cpp generators/metamakefile.cpp \
generators/makefiledeps.cpp option.cpp generators/win32/mingw_make.cpp generators/makefile.cpp \
generators/win32/msvc_vcproj.cpp generators/win32/msvc_vcxproj.cpp generators/win32/msvc_objectmodel.cpp generators/win32/msbuild_objectmodel.cpp generators/win32/msbuild_objectmodel.cpp generators/win32/msvc_nmake.cpp generators/win32/borland_bmake.cpp \
- generators/integrity/gbuild.cpp \
+ generators/integrity/gbuild.cpp generators/win32/cesdkhandler.cpp \
$(SOURCE_PATH)/src/corelib/codecs/qtextcodec.cpp $(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp \
$(SOURCE_PATH)/src/corelib/tools/qstring.cpp $(SOURCE_PATH)/src/corelib/io/qfile.cpp \
$(SOURCE_PATH)/src/corelib/io/qfiledevice.cpp \
@@ -160,6 +160,9 @@ msvc_vcxproj.o: $(QMKSRC)/generators/win32/msvc_vcxproj.cpp
msvc_nmake.o: $(QMKSRC)/generators/win32/msvc_nmake.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
+cesdkhandler.o: $(QMKSRC)/generators/win32/cesdkhandler.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $<
+
pbuilder_pbx.o: $(QMKSRC)/generators/mac/pbuilder_pbx.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32
index 029546f69d..ad6d4448d7 100644
--- a/qmake/Makefile.win32
+++ b/qmake/Makefile.win32
@@ -61,7 +61,7 @@ OBJS = project.obj main.obj makefile.obj unixmake.obj unixmake2.obj mingw
makefiledeps.obj metamakefile.obj xmloutput.obj pbuilder_pbx.obj \
borland_bmake.obj msvc_nmake.obj msvc_vcproj.obj msvc_vcxproj.obj \
msvc_objectmodel.obj msbuild_objectmodel.obj registry.obj \
- gbuild.obj
+ gbuild.obj cesdkhandler.obj
!IFDEF QMAKE_OPENSOURCE_EDITION
CFLAGS = $(CFLAGS) -DQMAKE_OPENSOURCE_EDITION
diff --git a/qmake/Makefile.win32-g++ b/qmake/Makefile.win32-g++
index 1966a8bbbc..d06d958ca3 100644
--- a/qmake/Makefile.win32-g++
+++ b/qmake/Makefile.win32-g++
@@ -64,7 +64,8 @@ OBJS = project.o main.o makefile.o unixmake.o unixmake2.o mingw_make.o \
option.o winmakefile.o projectgenerator.o property.o meta.o \
makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o \
borland_bmake.o msvc_nmake.o msvc_vcproj.o msvc_vcxproj.o \
- msvc_objectmodel.o msbuild_objectmodel.o registry.o gbuild.o
+ msvc_objectmodel.o msbuild_objectmodel.o registry.o gbuild.o \
+ cesdkhandler.o
ifdef QMAKE_OPENSOURCE_EDITION
CFLAGS += -DQMAKE_OPENSOURCE_EDITION
diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp
index d37089ee35..83354b9114 100644
--- a/qmake/generators/makefile.cpp
+++ b/qmake/generators/makefile.cpp
@@ -93,17 +93,12 @@ bool MakefileGenerator::canExecute(const QStringList &cmdline, int *a) const
QString MakefileGenerator::mkdir_p_asstring(const QString &dir, bool escape) const
{
- QString ret = "@$(CHK_DIR_EXISTS) ";
+ QString ret = "@" + chkdir + " ";
if(escape)
ret += escapeFilePath(dir);
else
ret += dir;
- ret += " ";
- if(isWindowsShell())
- ret += "$(MKDIR)";
- else
- ret += "|| $(MKDIR)";
- ret += " ";
+ ret += " " + chkglue + "$(MKDIR) ";
if(escape)
ret += escapeFilePath(dir);
else
@@ -198,12 +193,12 @@ MakefileGenerator::initOutPaths()
QHash<QString, QStringList> &v = project->variables();
//for shadow builds
if(!v.contains("QMAKE_ABSOLUTE_SOURCE_PATH")) {
- if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty() &&
+ if (Option::mkfile::do_cache && !project->cacheFile().isEmpty() &&
v.contains("QMAKE_ABSOLUTE_SOURCE_ROOT")) {
QString root = v["QMAKE_ABSOLUTE_SOURCE_ROOT"].first();
root = QDir::fromNativeSeparators(root);
if(!root.isEmpty()) {
- QFileInfo fi = fileInfo(Option::mkfile::cachefile);
+ QFileInfo fi = fileInfo(project->cacheFile());
if(!fi.makeAbsolute()) {
QString cache_r = fi.path(), pwd = Option::output_dir;
if(pwd.startsWith(cache_r) && !pwd.startsWith(root)) {
@@ -431,6 +426,15 @@ MakefileGenerator::init()
init_already = true;
QHash<QString, QStringList> &v = project->variables();
+
+ chkdir = v["QMAKE_CHK_DIR_EXISTS"].join(" ");
+ chkfile = v["QMAKE_CHK_FILE_EXISTS"].join(" ");
+ if (chkfile.isEmpty()) // Backwards compat with Qt4 specs
+ chkfile = isWindowsShell() ? "if not exist" : "test -f";
+ chkglue = v["QMAKE_CHK_EXISTS_GLUE"].join(" ");
+ if (chkglue.isEmpty()) // Backwards compat with Qt4 specs
+ chkglue = isWindowsShell() ? "" : "|| ";
+
QStringList &quc = v["QMAKE_EXTRA_COMPILERS"];
//make sure the COMPILERS are in the correct input/output chain order
@@ -853,8 +857,8 @@ MakefileGenerator::init()
}
// escape qmake command
- QStringList &qmk = project->values("QMAKE_QMAKE");
- qmk = escapeFilePaths(qmk);
+ project->values("QMAKE_QMAKE") =
+ escapeFilePaths(QStringList(Option::fixPathToTargetOS(Option::qmake_abslocation, false)));
}
bool
@@ -1771,10 +1775,6 @@ MakefileGenerator::writeExtraTargets(QTextStream &t)
if(!cmd.isEmpty())
t << "\n\t" << cmd;
t << endl << endl;
-
- project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(targ);
- project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(targ)) << deps.split(" ", QString::SkipEmptyParts);
- project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(targ)) << cmd;
}
}
@@ -1973,17 +1973,13 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t)
QString cmd = replaceExtraCompilerVariables(tmp_cmd, escapeFilePaths(inputs), QStringList(tmp_out));
t << escapeDependencyPath(tmp_out) << ":";
- project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(tmp_out);
// compiler.CONFIG+=explicit_dependencies means that ONLY compiler.depends gets to cause Makefile dependencies
if(project->values((*it) + ".CONFIG").indexOf("explicit_dependencies") != -1) {
t << " " << valList(escapeDependencyPaths(fileFixify(tmp_dep, Option::output_dir, Option::output_dir)));
- project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(tmp_out)) << tmp_dep;
} else {
t << " " << valList(escapeDependencyPaths(inputs)) << " " << valList(escapeDependencyPaths(deps));
- project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(tmp_out)) << inputs << deps;
}
t << "\n\t" << cmd << endl << endl;
- project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(tmp_out)) << cmd;
continue;
}
for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) {
@@ -2087,9 +2083,6 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t)
}
t << escapeDependencyPath(out) << ": " << valList(escapeDependencyPaths(deps)) << "\n\t"
<< cmd << endl << endl;
- project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(out);
- project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(out)) << deps;
- project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(out)) << cmd;
}
}
t << "compiler_clean: " << clean_targets << endl << endl;
@@ -2193,7 +2186,9 @@ QString MakefileGenerator::buildArgs(const QString &outdir)
if(!Option::mkfile::do_dep_heuristics)
ret += " -nodependheuristics";
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 == Option::TARG_MACX_MODE)
ret += " -macx";
@@ -2307,7 +2302,7 @@ MakefileGenerator::findSubDirsSubTargets() const
if(!project->isEmpty(fixedSubdir + ".makefile")) {
st->makefile = project->first(fixedSubdir + ".makefile");
} else {
- st->makefile = "$(MAKEFILE)";
+ st->makefile = "Makefile";
if(!st->profile.isEmpty()) {
QString basename = st->in_directory;
int new_slsh = basename.lastIndexOf(Option::dir_sep);
@@ -2360,7 +2355,7 @@ void
MakefileGenerator::writeSubDirs(QTextStream &t)
{
QList<SubTarget*> targets = findSubDirsSubTargets();
- t << "first: make_default" << endl;
+ t << "first: make_first" << endl;
int flags = SubTargetInstalls;
if(project->isActiveConfig("ordered"))
flags |= SubTargetOrdered;
@@ -2377,6 +2372,22 @@ void MakefileGenerator::writeSubMakeCall(QTextStream &t, const QString &callPref
}
void
+MakefileGenerator::writeSubTargetCall(QTextStream &t,
+ const QString &in_directory, const QString &in, const QString &out_directory, const QString &out,
+ const QString &out_directory_cdin, const QString &makefilein, const QString &out_directory_cdout)
+{
+ QString pfx;
+ if (!in.isEmpty()) {
+ if (!in_directory.isEmpty())
+ t << "\n\t" << mkdir_p_asstring(out_directory);
+ pfx = "( " + chkfile + " " + out + " " + chkglue
+ + "$(QMAKE) " + in + buildArgs(in_directory) + " -o " + out
+ + " ) && ";
+ }
+ writeSubMakeCall(t, out_directory_cdin + pfx, makefilein, out_directory_cdout);
+}
+
+void
MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubTarget*> targets, int flags)
{
// blasted includes
@@ -2405,8 +2416,6 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
t << "SYMLINK = " << var("QMAKE_SYMBOLIC_LINK") << endl;
t << "DEL_DIR = " << var("QMAKE_DEL_DIR") << endl;
t << "MOVE = " << var("QMAKE_MOVE") << endl;
- t << "CHK_DIR_EXISTS= " << var("QMAKE_CHK_DIR_EXISTS") << endl;
- t << "MKDIR = " << var("QMAKE_MKDIR") << endl;
t << "SUBTARGETS = "; // subtargets are sub-directory
for(int target = 0; target < targets.size(); ++target)
t << " \\\n\t\t" << targets.at(target)->target;
@@ -2417,11 +2426,13 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
QStringList targetSuffixes;
const QString abs_source_path = project->first("QMAKE_ABSOLUTE_SOURCE_PATH");
if (!(flags & SubTargetSkipDefaultTargets)) {
- targetSuffixes << "make_default" << "make_first" << "all" << "clean" << "distclean"
+ targetSuffixes << "make_first" << "all" << "clean" << "distclean"
<< QString((flags & SubTargetInstalls) ? "install_subtargets" : "install")
<< QString((flags & SubTargetInstalls) ? "uninstall_subtargets" : "uninstall");
}
+ bool dont_recurse = project->isActiveConfig("dont_recurse");
+
// generate target rules
for(int target = 0; target < targets.size(); ++target) {
SubTarget *subtarget = targets.at(target);
@@ -2434,11 +2445,6 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path))
out_directory = Option::output_dir + out_directory.mid(abs_source_path.length());
- QString mkfile = subtarget->makefile;
- if(!in_directory.isEmpty())
- mkfile.prepend(out_directory);
-
- QString in_directory_cdin, in_directory_cdout, out_directory_cdin, out_directory_cdout;
#define MAKE_CD_IN_AND_OUT(directory) \
if(!directory.isEmpty()) { \
if(project->isActiveConfig("cd_change_global")) { \
@@ -2459,25 +2465,28 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
} else { \
directory ## _cdin = "\n\t"; \
}
- MAKE_CD_IN_AND_OUT(in_directory);
+
+ QString out_directory_cdin, out_directory_cdout;
MAKE_CD_IN_AND_OUT(out_directory);
+ QString makefilein = " -f " + subtarget->makefile;
+
//qmake it
+ QString out;
+ QString in;
if(!subtarget->profile.isEmpty()) {
- QString out = subtarget->makefile;
- QString in = escapeFilePath(fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute));
+ out = subtarget->makefile;
+ in = escapeFilePath(fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute));
if(out.startsWith(in_directory))
out = out.mid(in_directory.length());
- t << mkfile << ": " << "\n\t";
- if(!in_directory.isEmpty()) {
- t << mkdir_p_asstring(out_directory)
- << out_directory_cdin
- << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out
- << in_directory_cdout << endl;
+ t << subtarget->target << "-qmake_all: ";
+ if (flags & SubTargetOrdered) {
+ if (target)
+ t << targets.at(target - 1)->target << "-qmake_all";
} else {
- t << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out << endl;
+ if (!subtarget->depends.isEmpty())
+ t << valGlue(subtarget->depends, QString(), "-qmake_all ", "-qmake_all");
}
- t << subtarget->target << "-qmake_all: ";
if(project->isEmpty("QMAKE_NOFORCE"))
t << " FORCE";
t << "\n\t";
@@ -2485,21 +2494,24 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
t << mkdir_p_asstring(out_directory)
<< out_directory_cdin
<< "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out
- << in_directory_cdout << endl;
+ << out_directory_cdout;
} else {
- t << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out << endl;
+ t << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out;
}
+ if (!dont_recurse)
+ writeSubMakeCall(t, out_directory_cdin, makefilein + " qmake_all", out_directory_cdout);
+ else
+ t << endl;
}
- QString makefilein = " -f " + subtarget->makefile;
-
{ //actually compile
- t << subtarget->target << ": " << mkfile;
+ t << subtarget->target << ":";
if(!subtarget->depends.isEmpty())
t << " " << valList(subtarget->depends);
if(project->isEmpty("QMAKE_NOFORCE"))
t << " FORCE";
- writeSubMakeCall(t, out_directory_cdin, makefilein, out_directory_cdout);
+ writeSubTargetCall(t, in_directory, in, out_directory, out,
+ out_directory_cdin, makefilein, out_directory_cdout);
}
for(int suffix = 0; suffix < targetSuffixes.size(); ++suffix) {
@@ -2509,34 +2521,31 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
else if(s == "uninstall_subtargets")
s = "uninstall";
else if(s == "make_first")
- s = "first";
- else if(s == "make_default")
s = QString();
if(flags & SubTargetOrdered) {
- t << subtarget->target << "-" << targetSuffixes.at(suffix) << "-ordered: " << mkfile;
+ t << subtarget->target << "-" << targetSuffixes.at(suffix) << "-ordered:";
if(target)
t << " " << targets.at(target-1)->target << "-" << targetSuffixes.at(suffix) << "-ordered ";
if(project->isEmpty("QMAKE_NOFORCE"))
t << " FORCE";
- writeSubMakeCall(t, out_directory_cdin, makefilein + " " + s, out_directory_cdout);
+ writeSubTargetCall(t, in_directory, in, out_directory, out,
+ out_directory_cdin, makefilein + " " + s, out_directory_cdout);
}
- t << subtarget->target << "-" << targetSuffixes.at(suffix) << ": " << mkfile;
+ t << subtarget->target << "-" << targetSuffixes.at(suffix) << ":";
if(!subtarget->depends.isEmpty())
t << " " << valGlue(subtarget->depends, QString(), "-" + targetSuffixes.at(suffix) + " ",
"-"+targetSuffixes.at(suffix));
if(project->isEmpty("QMAKE_NOFORCE"))
t << " FORCE";
- writeSubMakeCall(t, out_directory_cdin, makefilein + " " + s, out_directory_cdout);
+ writeSubTargetCall(t, in_directory, in, out_directory, out,
+ out_directory_cdin, makefilein + " " + s, out_directory_cdout);
}
}
t << endl;
if (!(flags & SubTargetSkipDefaultTargets)) {
- if(project->values("QMAKE_INTERNAL_QMAKE_DEPS").indexOf("qmake_all") == -1)
- project->values("QMAKE_INTERNAL_QMAKE_DEPS").append("qmake_all");
-
- writeMakeQmake(t);
+ writeMakeQmake(t, true);
t << "qmake_all:";
if(!targets.isEmpty()) {
@@ -2560,7 +2569,7 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
t << suffix << ":";
for(int target = 0; target < targets.size(); ++target) {
SubTarget *subTarget = targets.at(target);
- if((suffix == "make_first" || suffix == "make_default")
+ if (suffix == "make_first"
&& project->values(subTarget->name + ".CONFIG").indexOf("no_default_target") != -1) {
continue;
}
@@ -2629,28 +2638,31 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
if(!recurse.contains(subtarget->name))
continue;
- QString mkfile = subtarget->makefile;
- if(!in_directory.isEmpty()) {
- if(!out_directory.endsWith(Option::dir_sep))
- mkfile.prepend(out_directory + Option::dir_sep);
- else
- mkfile.prepend(out_directory);
- }
+
QString out_directory_cdin, out_directory_cdout;
MAKE_CD_IN_AND_OUT(out_directory);
QString makefilein = " -f " + subtarget->makefile;
+ QString out;
+ QString in;
+ if (!subtarget->profile.isEmpty()) {
+ out = subtarget->makefile;
+ in = escapeFilePath(fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute));
+ if (out.startsWith(in_directory))
+ out = out.mid(in_directory.length());
+ }
+
//write the rule/depends
if(flags & SubTargetOrdered) {
const QString dep = subtarget->target + "-" + (*qut_it) + "_ordered";
- t << dep << ": " << mkfile;
+ t << dep << ":";
if(target)
t << " " << targets.at(target-1)->target << "-" << (*qut_it) << "_ordered ";
deps += " " + dep;
} else {
const QString dep = subtarget->target + "-" + (*qut_it);
- t << dep << ": " << mkfile;
+ t << dep << ":";
if(!subtarget->depends.isEmpty())
t << " " << valGlue(subtarget->depends, QString(), "-" + (*qut_it) + " ", "-" + (*qut_it));
deps += " " + dep;
@@ -2661,12 +2673,8 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
sub_targ = project->first((*qut_it) + ".recurse_target");
//write the commands
- if(!out_directory.isEmpty()) {
- writeSubMakeCall(t, out_directory_cdin, makefilein + " " + sub_targ,
- out_directory_cdout);
- } else {
- writeSubMakeCall(t, "\n\t", makefilein + " " + sub_targ, QString());
- }
+ writeSubTargetCall(t, in_directory, in, out_directory, out,
+ out_directory_cdin, makefilein + " " + sub_targ, out_directory_cdout);
}
}
if(project->isEmpty("QMAKE_NOFORCE") &&
@@ -2688,7 +2696,7 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubT
}
void
-MakefileGenerator::writeMakeQmake(QTextStream &t)
+MakefileGenerator::writeMakeQmake(QTextStream &t, bool noDummyQmakeAll)
{
QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
if(project->isEmpty("QMAKE_FAILED_REQUIREMENTS") && !project->isEmpty("QMAKE_INTERNAL_PRL_FILE")) {
@@ -2702,8 +2710,12 @@ MakefileGenerator::writeMakeQmake(QTextStream &t)
QString qmake = build_args();
if(!ofile.isEmpty() && !project->isActiveConfig("no_autoqmake")) {
t << escapeFilePath(ofile) << ": " << escapeDependencyPath(fileFixify(pfile)) << " ";
- if(Option::mkfile::do_cache)
- t << escapeDependencyPath(fileFixify(Option::mkfile::cachefile)) << " ";
+ if (Option::mkfile::do_cache) {
+ if (!project->confFile().isEmpty())
+ t << escapeDependencyPath(fileFixify(project->confFile())) << " ";
+ if (!project->cacheFile().isEmpty())
+ t << escapeDependencyPath(fileFixify(project->cacheFile())) << " ";
+ }
if(!specdir().isEmpty()) {
if(exists(Option::fixPathToLocalOS(specdir()+QDir::separator()+"qmake.conf")))
t << escapeDependencyPath(specdir() + Option::dir_sep + "qmake.conf") << " ";
@@ -2718,11 +2730,18 @@ MakefileGenerator::writeMakeQmake(QTextStream &t)
}
}
if(project->first("QMAKE_ORIG_TARGET") != "qmake") {
- t << "qmake: " <<
- project->values("QMAKE_INTERNAL_QMAKE_DEPS").join(" \\\n\t\t");
+ t << "qmake:";
if(project->isEmpty("QMAKE_NOFORCE"))
t << " FORCE";
t << "\n\t" << "@" << qmake << endl << endl;
+ if (!noDummyQmakeAll) {
+ t << "qmake_all:";
+ if (project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ if (project->isActiveConfig("no_empty_targets"))
+ t << "\n\t" << "@cd .";
+ t << endl << endl;
+ }
}
}
}
@@ -3046,13 +3065,14 @@ QStringList
}
QString
-MakefileGenerator::specdir(const QString &outdir)
+MakefileGenerator::specdir(const QString &outdir, int host_build)
{
#if 0
if(!spec.isEmpty())
return spec;
#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;
}
@@ -3142,7 +3162,7 @@ MakefileGenerator::pkgConfigPrefix() const
{
if(!project->isEmpty("QMAKE_PKGCONFIG_PREFIX"))
return project->first("QMAKE_PKGCONFIG_PREFIX");
- return QLibraryInfo::rawLocation(QLibraryInfo::PrefixPath);
+ return QLibraryInfo::rawLocation(QLibraryInfo::PrefixPath, QLibraryInfo::FinalPaths);
}
QString
diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h
index 5b64ea68fb..33602dcf80 100644
--- a/qmake/generators/makefile.h
+++ b/qmake/generators/makefile.h
@@ -81,6 +81,7 @@ class MakefileGenerator : protected QMakeSourceFileInfo
QString spec;
bool init_opath_already, init_already, no_io;
QHash<QString, bool> init_compiler_already;
+ QString chkdir, chkfile, chkglue;
QString build_args(const QString &outdir=QString());
void checkMultipleDefinition(const QString &, const QString &);
@@ -97,7 +98,7 @@ protected:
void writeInstalls(QTextStream &t, const QString &installs, bool noBuild=false);
void writeHeader(QTextStream &t);
void writeSubDirs(QTextStream &t);
- void writeMakeQmake(QTextStream &t);
+ void writeMakeQmake(QTextStream &t, bool noDummyQmakeAll = false);
void writeExtraVariables(QTextStream &t);
void writeExtraTargets(QTextStream &t);
void writeExtraCompilerTargets(QTextStream &t);
@@ -127,6 +128,9 @@ protected:
SubTargetsNoFlags=0x00
};
QList<MakefileGenerator::SubTarget*> findSubDirsSubTargets() const;
+ void writeSubTargetCall(QTextStream &t,
+ const QString &in_directory, const QString &in, const QString &out_directory, const QString &out,
+ const QString &out_directory_cdin, const QString &makefilein, const QString &out_directory_cdout);
virtual void writeSubMakeCall(QTextStream &t, const QString &outDirectory_cdin,
const QString &makeFileIn, const QString &outDirectory_cdout);
void writeSubTargets(QTextStream &t, QList<SubTarget*> subtargets, int flags);
@@ -187,7 +191,7 @@ protected:
//subclasses can use these to query information about how the generator was "run"
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 bool doDepends() const { return Option::mkfile::do_deps; }
diff --git a/qmake/generators/metamakefile.cpp b/qmake/generators/metamakefile.cpp
index c69d5a5812..a1ab4ada75 100644
--- a/qmake/generators/metamakefile.cpp
+++ b/qmake/generators/metamakefile.cpp
@@ -300,6 +300,8 @@ SubdirsMetaMakefileGenerator::init()
bool recurse = Option::recursive == Option::QMAKE_RECURSIVE_YES
|| (Option::recursive == Option::QMAKE_RECURSIVE_DEFAULT
&& project->isRecursive());
+ if (recurse && project->isActiveConfig("dont_recurse"))
+ recurse = false;
if(recurse) {
QString old_output_dir = Option::output_dir;
QString old_output = Option::output.fileName();
@@ -336,7 +338,7 @@ SubdirsMetaMakefileGenerator::init()
printf(" ");
sub->input_dir = subdir.absolutePath();
if(subdir.isRelative() && old_output_dir != oldpwd) {
- sub->output_dir = old_output_dir + "/" + subdir.path();
+ sub->output_dir = old_output_dir + (subdir.path() != "." ? "/" + subdir.path() : QString());
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;
diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp
index 856bf371a7..b8b4f1bbc5 100644
--- a/qmake/generators/unix/unixmake.cpp
+++ b/qmake/generators/unix/unixmake.cpp
@@ -103,8 +103,6 @@ UnixMakefileGenerator::init()
MakefileGenerator::init();
if(project->isEmpty("MAKEFILE"))
project->values("MAKEFILE").append("Makefile");
- if(project->values("QMAKE_INTERNAL_QMAKE_DEPS").indexOf("qmake_all") == -1)
- project->values("QMAKE_INTERNAL_QMAKE_DEPS").append("qmake_all");
return; /* subdirs is done */
}
diff --git a/qmake/generators/win32/cesdkhandler.cpp b/qmake/generators/win32/cesdkhandler.cpp
new file mode 100644
index 0000000000..de6a55112b
--- /dev/null
+++ b/qmake/generators/win32/cesdkhandler.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "cesdkhandler.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QDebug>
+#include <QtCore/QXmlStreamReader>
+
+QT_BEGIN_NAMESPACE
+
+CeSdkInfo::CeSdkInfo() : m_major(0) , m_minor(0)
+{
+}
+
+CeSdkHandler::CeSdkHandler()
+{
+}
+
+bool CeSdkHandler::parse()
+{
+ // look at the file at %VCInstallDir%/vcpackages/WCE.VCPlatform.config
+ // and scan through all installed sdks...
+ m_list.clear();
+ m_vcInstallDir = QString::fromLatin1(qgetenv("VCInstallDir"));
+ if (m_vcInstallDir.isEmpty())
+ return false;
+
+ QDir vStudioDir(m_vcInstallDir);
+ if (!vStudioDir.cd(QLatin1String("vcpackages")))
+ return false;
+
+ QFile configFile(vStudioDir.absoluteFilePath(QLatin1String("WCE.VCPlatform.config")));
+ if (!configFile.open(QIODevice::ReadOnly))
+ return false;
+
+ QString currentElement;
+ CeSdkInfo currentItem;
+ QXmlStreamReader xml(&configFile);
+ while (!xml.atEnd()) {
+ xml.readNext();
+ if (xml.isStartElement()) {
+ currentElement = xml.name().toString();
+ if (currentElement == QLatin1String("Platform")) {
+ currentItem = CeSdkInfo();
+ } else if (currentElement == QLatin1String("Directories")) {
+ QXmlStreamAttributes attr = xml.attributes();
+ currentItem.m_include = fixPaths(attr.value(QLatin1String("Include")).toString());
+ currentItem.m_lib = fixPaths(attr.value(QLatin1String("Library")).toString());
+ currentItem.m_bin = fixPaths(attr.value(QLatin1String("Path")).toString());
+ }
+ } else if (xml.isEndElement()) {
+ if (xml.name().toString() == QLatin1String("Platform"))
+ m_list.append(currentItem);
+ } else if (xml.isCharacters() && !xml.isWhitespace()) {
+ if (currentElement == QLatin1String("PlatformName"))
+ currentItem.m_name = xml.text().toString();
+ else if (currentElement == QLatin1String("OSMajorVersion"))
+ currentItem.m_major = xml.text().toString().toInt();
+ else if (currentElement == QLatin1String("OSMinorVersion"))
+ currentItem.m_minor = xml.text().toString().toInt();
+ }
+ }
+
+ if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
+ qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString();
+ return false;
+ }
+
+ return m_list.size() > 0 ? true : false;
+}
+
+QString CeSdkHandler::fixPaths(QString path) const
+{
+ QRegExp searchStr(QLatin1String("(\\$\\(\\w+\\))"));
+ QString fixedString = path;
+ for (int index = fixedString.indexOf(searchStr, 0);
+ index >= 0;
+ index = fixedString.indexOf(searchStr, index)) {
+ const QString capture = searchStr.cap(0);
+ fixedString.replace(index, capture.length(), capture.toUpper());
+ index += capture.length(); // don't count the zero terminator
+ fixedString.insert(index, '\\'); // the configuration file lacks a directory separator for env vars
+ ++index;
+ }
+ return fixedString;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/cesdkhandler.h b/qmake/generators/win32/cesdkhandler.h
new file mode 100644
index 0000000000..8d35694e5d
--- /dev/null
+++ b/qmake/generators/win32/cesdkhandler.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CE_SDK_HANDLER_INCL
+#define CE_SDK_HANDLER_INCL
+
+#include <QStringList>
+#include <QDir>
+
+QT_BEGIN_NAMESPACE
+
+class CeSdkInfo
+{
+public:
+ CeSdkInfo();
+ inline QString name() const { return m_name; }
+ inline QString binPath() const { return m_bin; }
+ inline QString includePath() const { return m_include; }
+ inline QString libPath() const { return m_lib; }
+ inline bool isValid() const;
+ inline int majorVersion() const { return m_major; }
+ inline int minorVersion() const { return m_minor; }
+ inline bool isSupported() const { return m_major >= 5; }
+private:
+ friend class CeSdkHandler;
+ QString m_name;
+ QString m_bin;
+ QString m_include;
+ QString m_lib;
+ int m_major;
+ int m_minor;
+};
+
+bool CeSdkInfo::isValid() const
+{
+ return !m_name.isEmpty() &&
+ !m_bin.isEmpty() &&
+ !m_include.isEmpty() &&
+ !m_lib.isEmpty();
+}
+
+class CeSdkHandler
+{
+public:
+ CeSdkHandler();
+ bool parse();
+ inline QList<CeSdkInfo> listAll() const { return m_list; }
+private:
+ inline QString fixPaths(QString path) const;
+ QList<CeSdkInfo> m_list;
+ QString m_vcInstallDir;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp
index db6651cb88..adf8883b01 100644
--- a/qmake/generators/win32/msvc_nmake.cpp
+++ b/qmake/generators/win32/msvc_nmake.cpp
@@ -41,6 +41,7 @@
#include "msvc_nmake.h"
#include "option.h"
+#include "cesdkhandler.h"
#include <qregexp.h>
#include <qhash.h>
#include <qdir.h>
@@ -76,6 +77,30 @@ NmakeMakefileGenerator::writeMakefile(QTextStream &t)
if(Option::mkfile::do_stub_makefile)
return MakefileGenerator::writeStubMakefile(t);
#endif
+ if (!project->isHostBuild()) {
+ const QHash<QString, QStringList> &variables = project->variables();
+ if (variables.contains("XQMAKESPEC")
+ && !variables["XQMAKESPEC"].isEmpty()
+ && variables["XQMAKESPEC"].first().contains("wince", Qt::CaseInsensitive)) {
+ CeSdkHandler sdkhandler;
+ sdkhandler.parse();
+ const QString sdkName = variables["CE_SDK"].join(" ")
+ + " (" + variables["CE_ARCH"].join(" ") + ")";
+ const QList<CeSdkInfo> sdkList = sdkhandler.listAll();
+ CeSdkInfo sdk;
+ foreach (const CeSdkInfo &info, sdkList) {
+ if (info.name().compare(sdkName, Qt::CaseInsensitive ) == 0) {
+ sdk = info;
+ break;
+ }
+ }
+ if (sdk.isValid()) {
+ t << "\nINCLUDE = " << sdk.includePath();
+ t << "\nLIB = " << sdk.libPath();
+ t << "\nPATH = " << sdk.binPath() << "\n";
+ }
+ }
+ }
writeNmakeParts(t);
return MakefileGenerator::writeMakefile(t);
}
diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp
index 951784ec28..b228917692 100644
--- a/qmake/generators/win32/msvc_vcproj.cpp
+++ b/qmake/generators/win32/msvc_vcproj.cpp
@@ -649,12 +649,15 @@ nextfile:
t << _slnProjConfBeg;
for(QList<VcsolutionDepend*>::Iterator it = solution_cleanup.begin(); it != solution_cleanup.end(); ++it) {
QString platform = is64Bit ? "x64" : "Win32";
+ QString xplatform = platform;
if (!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH"))
- platform = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
- t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag1).arg(platform) << platform;
- t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag2).arg(platform) << platform;
- t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag1).arg(platform) << platform;
- t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag2).arg(platform) << platform;
+ xplatform = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
+ if (!project->isHostBuild())
+ platform = xplatform;
+ t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag1).arg(xplatform) << 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 << _slnExtSections;
@@ -858,7 +861,7 @@ void VcprojGenerator::initProject()
}
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");
} else {
vcProject.PlatformName = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
@@ -922,7 +925,7 @@ void VcprojGenerator::initConfiguration()
if (conf.Name.isEmpty())
conf.Name = isDebug ? "Debug" : "Release";
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");
} else {
conf.Name += "|" + project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
@@ -948,7 +951,7 @@ void VcprojGenerator::initConfiguration()
initPreBuildEventTools();
initPostBuildEventTools();
// 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();
initPreLinkEventTools();
@@ -1084,7 +1087,7 @@ void VcprojGenerator::initPostBuildEventTools()
QString signature = !project->isEmpty("SIGNATURE_FILE") ? var("SIGNATURE_FILE") : var("DEFAULT_SIGNATURE");
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) {
conf.postBuild.CommandLine.prepend(
QLatin1String("signtool sign /F ") + signature + QLatin1String(" \"$(TargetPath)\""));
@@ -1574,21 +1577,6 @@ QString VcprojGenerator::fixFilename(QString ofile) const
return ofile;
}
-QString VcprojGenerator::findTemplate(QString file)
-{
- QString ret;
- if(!exists((ret = file)) &&
- !exists((ret = QString(Option::mkfile::qmakespec + "/" + 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-msvc2003/" + file))) &&
- !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::HostDataPath) + "/win32-msvc2005/" + file))) &&
- !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::HostDataPath) + "/win32-msvc2008/" + file))))
- return "";
- debug_msg(1, "Generator: MSVC.NET: Found template \'%s\'", ret.toLatin1().constData());
- return ret;
-}
-
void VcprojGenerator::outputVariables()
{
#if 0
diff --git a/qmake/generators/win32/msvc_vcproj.h b/qmake/generators/win32/msvc_vcproj.h
index 30b149f8f5..416e233614 100644
--- a/qmake/generators/win32/msvc_vcproj.h
+++ b/qmake/generators/win32/msvc_vcproj.h
@@ -63,7 +63,6 @@ class VcprojGenerator : public Win32MakefileGenerator
bool writeMakefile(QTextStream &);
bool writeProjectMakefile();
- QString findTemplate(QString file);
void init();
public:
diff --git a/qmake/main.cpp b/qmake/main.cpp
index 985afaa8e8..45672c67ee 100644
--- a/qmake/main.cpp
+++ b/qmake/main.cpp
@@ -163,10 +163,7 @@ int runQMake(int argc, char **argv)
fn = fn.right(fn.length() - di - 1);
}
- if (!Option::prepareProject(fn)) {
- exit_val = 3;
- break;
- }
+ Option::prepareProject(fn);
// read project..
if(!project.read(fn)) {
diff --git a/qmake/option.cpp b/qmake/option.cpp
index b2a1e6982f..6eeddfd154 100644
--- a/qmake/option.cpp
+++ b/qmake/option.cpp
@@ -54,7 +54,6 @@ QT_BEGIN_NAMESPACE
//convenience
const char *Option::application_argv0 = 0;
QString Option::prf_ext;
-QString Option::js_ext;
QString Option::prl_ext;
QString Option::libtool_ext;
QString Option::pkgcfg_ext;
@@ -68,7 +67,6 @@ QString Option::obj_ext;
QString Option::lex_ext;
QString Option::yacc_ext;
QString Option::pro_ext;
-QString Option::mmp_ext;
QString Option::dir_sep;
QString Option::dirlist_sep;
QString Option::h_moc_mod;
@@ -107,6 +105,7 @@ QStringList Option::projfile::project_dirs;
//QMAKE_GENERATE_MAKEFILE stuff
QString Option::mkfile::qmakespec;
+QString Option::mkfile::xqmakespec;
int Option::mkfile::cachefile_depth = -1;
bool Option::mkfile::do_deps = true;
bool Option::mkfile::do_mocs = true;
@@ -114,11 +113,12 @@ bool Option::mkfile::do_dep_heuristics = true;
bool Option::mkfile::do_preprocess = false;
bool Option::mkfile::do_stub_makefile = false;
bool Option::mkfile::do_cache = true;
-QString Option::mkfile::project_root;
-QString Option::mkfile::project_build_root;
+QString Option::mkfile::source_root;
+QString Option::mkfile::build_root;
QString Option::mkfile::cachefile;
QStringList Option::mkfile::project_files;
QString Option::mkfile::qmakespec_commandline;
+QString Option::mkfile::xqmakespec_commandline;
static Option::QMAKE_MODE default_mode(QString progname)
{
@@ -329,6 +329,9 @@ Option::parseCommandLine(int argc, char **argv, int skip)
} else if(opt == "platform" || opt == "spec") {
Option::mkfile::qmakespec = cleanSpec(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 {
fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
@@ -383,6 +386,9 @@ Option::parseCommandLine(int argc, char **argv, int skip)
if (!user_configs.isEmpty())
Option::before_user_vars += "CONFIG += " + user_configs.join(" ");
+ if (Option::mkfile::xqmakespec.isEmpty())
+ Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
+
return Option::QMAKE_CMDLINE_SUCCESS;
}
@@ -414,7 +420,6 @@ Option::init(int argc, char **argv)
Option::libtool_ext = ".la";
Option::pkgcfg_ext = ".pc";
Option::prf_ext = ".prf";
- Option::js_ext = ".js";
Option::ui_ext = ".ui";
Option::h_ext << ".h" << ".hpp" << ".hh" << ".hxx";
Option::c_ext << ".c";
@@ -430,7 +435,6 @@ Option::init(int argc, char **argv)
Option::lex_ext = ".l";
Option::yacc_ext = ".y";
Option::pro_ext = ".pro";
- Option::mmp_ext = ".mmp";
#ifdef Q_OS_WIN
Option::dirlist_sep = ";";
Option::shellPath = detectShellPath();
@@ -538,8 +542,13 @@ Option::init(int argc, char **argv)
//last chance for defaults
if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
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());
+ if (Option::mkfile::xqmakespec.isEmpty())
+ Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
+ }
//try REALLY hard to do it for them, lazy..
if(Option::mkfile::project_files.isEmpty()) {
@@ -583,106 +592,27 @@ void Option::applyHostMode()
}
}
-QStringList Option::mkspecPaths()
-{
- QStringList ret;
- const QString concat = QLatin1String("/mkspecs");
-
- QByteArray qmakepath = qgetenv("QMAKEPATH");
- if (!qmakepath.isEmpty()) {
- const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath));
- for (QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it)
- ret << ((*it) + concat);
- }
- if (!Option::mkfile::project_build_root.isEmpty())
- ret << Option::mkfile::project_build_root + concat;
- if (!Option::mkfile::project_root.isEmpty())
- ret << Option::mkfile::project_root + concat;
- ret << QLibraryInfo::location(QLibraryInfo::HostDataPath) + concat;
- ret.removeDuplicates();
- return ret;
-}
-
-bool Option::resolveSpec(QString *spec)
+void Option::prepareProject(const QString &pfile)
{
- QString qmakespec = fixEnvVariables(*spec);
- if (qmakespec.isEmpty())
- qmakespec = "default";
- if (QDir::isRelativePath(qmakespec)) {
- QStringList mkspec_roots = mkspecPaths();
- debug_msg(2, "Looking for mkspec %s in (%s)", qmakespec.toLatin1().constData(),
- mkspec_roots.join("::").toLatin1().constData());
- for (QStringList::ConstIterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) {
- QString mkspec = (*it) + QLatin1Char('/') + qmakespec;
- if (QFile::exists(mkspec)) {
- *spec = mkspec;
- return true;
- }
- }
- fprintf(stderr, "Could not find mkspecs for your QMAKESPEC(%s) after trying:\n\t%s\n",
- qmakespec.toLatin1().constData(), mkspec_roots.join("\n\t").toLatin1().constData());
- return false;
- }
- return true;
-}
-
-bool Option::prepareProject(const QString &pfile)
-{
- mkfile::project_build_root.clear();
- if (mkfile::do_cache) {
- if (mkfile::cachefile.isEmpty()) { //find it as it has not been specified
- QDir dir(output_dir);
- while (!dir.exists(QLatin1String(".qmake.cache")))
- if (dir.isRoot() || !dir.cdUp())
- goto no_cache;
- mkfile::cachefile = dir.filePath(QLatin1String(".qmake.cache"));
- mkfile::project_build_root = dir.path();
- } else {
- QFileInfo fi(mkfile::cachefile);
- mkfile::cachefile = QDir::cleanPath(fi.absoluteFilePath());
- mkfile::project_build_root = QDir::cleanPath(fi.absolutePath());
- }
-
- if (mkfile::qmakespec.isEmpty()) {
- QMakeProject cproj;
- if (!cproj.read(mkfile::cachefile, QMakeProject::ReadProFile))
- return false;
- mkfile::qmakespec = cproj.first(QLatin1String("QMAKESPEC"));
- }
- }
- no_cache:
-
QString srcpath = (pfile != "-")
? QDir::cleanPath(QFileInfo(pfile).absolutePath()) : qmake_getpwd();
- if (srcpath != output_dir || mkfile::project_build_root.isEmpty()) {
- QDir srcdir(srcpath);
- QDir dstdir(output_dir);
- do {
- if (!mkfile::project_build_root.isEmpty()) {
- // If we already know the build root, just match up the source root with it.
- if (dstdir.path() == mkfile::project_build_root) {
- mkfile::project_root = srcdir.path();
- break;
- }
- } else {
- // Look for mkspecs/ in source and build. First to win determines the root.
- if (dstdir.exists("mkspecs") || srcdir.exists("mkspecs")) {
- mkfile::project_build_root = dstdir.path();
- mkfile::project_root = srcdir.path();
- if (mkfile::project_root == mkfile::project_build_root)
- mkfile::project_root.clear();
- break;
- }
- }
- } while (!srcdir.isRoot() && srcdir.cdUp() && !dstdir.isRoot() && dstdir.cdUp());
+ if (srcpath != output_dir) {
+ if (!srcpath.endsWith(QLatin1Char('/')))
+ srcpath += QLatin1Char('/');
+ QString dstpath = output_dir;
+ if (!dstpath.endsWith(QLatin1Char('/')))
+ dstpath += QLatin1Char('/');
+ int srcLen = srcpath.length();
+ int dstLen = dstpath.length();
+ int lastSl = 0;
+ while (++lastSl, srcpath.at(--srcLen) == dstpath.at(--dstLen))
+ if (srcpath.at(srcLen) == QLatin1Char('/'))
+ lastSl = 1;
+ mkfile::source_root = srcpath.left(srcLen + lastSl);
+ mkfile::build_root = dstpath.left(dstLen + lastSl);
} else {
- mkfile::project_root.clear();
+ mkfile::source_root.clear();
}
-
- if (!resolveSpec(&Option::mkfile::qmakespec))
- return false;
-
- return true;
}
bool Option::postProcessProject(QMakeProject *project)
diff --git a/qmake/option.h b/qmake/option.h
index 23384877fd..7b86d56e89 100644
--- a/qmake/option.h
+++ b/qmake/option.h
@@ -72,7 +72,6 @@ void warn_msg(QMakeWarn t, const char *fmt, ...);
struct Option
{
//simply global convenience
- static QString js_ext;
static QString libtool_ext;
static QString pkgcfg_ext;
static QString prf_ext;
@@ -94,7 +93,6 @@ struct Option
static QString dirlist_sep;
static QString sysenv_mod;
static QString pro_ext;
- static QString mmp_ext;
static QString res_ext;
static char field_sep;
static const char *application_argv0;
@@ -109,8 +107,7 @@ struct Option
//both of these must be called..
static int init(int argc=0, char **argv=0); //parse cmdline
static void applyHostMode();
- static QStringList mkspecPaths();
- static bool prepareProject(const QString &pfile);
+ static void prepareProject(const QString &pfile);
static bool postProcessProject(QMakeProject *);
enum StringFixFlags {
@@ -198,27 +195,28 @@ struct Option
//QMAKE_GENERATE_MAKEFILE options
struct mkfile {
static QString qmakespec;
+ static QString xqmakespec;
static bool do_cache;
static bool do_deps;
static bool do_mocs;
static bool do_dep_heuristics;
static bool do_preprocess;
static bool do_stub_makefile;
- static QString project_root;
- static QString project_build_root;
+ static QString source_root;
+ static QString build_root;
static QString cachefile;
static int cachefile_depth;
static QStringList project_files;
static QString qmakespec_commandline;
+ static QString xqmakespec_commandline;
};
private:
static int parseCommandLine(int, char **, int=0);
- static bool resolveSpec(QString *spec);
};
inline QString fixEnvVariables(const QString &x) { return Option::fixString(x, Option::FixEnvVars); }
-inline QStringList splitPathList(const QString &paths) { return paths.split(Option::dirlist_sep); }
+inline QStringList splitPathList(const QString &paths) { return paths.isEmpty() ? QStringList() : paths.split(Option::dirlist_sep); }
QT_END_NAMESPACE
diff --git a/qmake/project.cpp b/qmake/project.cpp
index 3df80bc00d..3a34aef1a9 100644
--- a/qmake/project.cpp
+++ b/qmake/project.cpp
@@ -54,7 +54,11 @@
#include <qstack.h>
#include <qdebug.h>
#ifdef Q_OS_UNIX
+#include <time.h>
+#include <utime.h>
+#include <errno.h>
#include <unistd.h>
+#include <sys/stat.h>
#include <sys/utsname.h>
#elif defined(Q_OS_WIN32)
#include <windows.h>
@@ -74,10 +78,12 @@ QT_BEGIN_NAMESPACE
//expand functions
enum ExpandFunc { E_MEMBER=1, E_FIRST, E_LAST, E_CAT, E_FROMFILE, E_EVAL, E_LIST,
- E_SPRINTF, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
- E_FIND, E_SYSTEM, E_UNIQUE, E_QUOTE, E_ESCAPE_EXPAND,
- E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE, E_REPLACE,
- E_SIZE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS };
+ E_SPRINTF, E_FORMAT_NUMBER, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
+ E_FIND, E_SYSTEM, E_UNIQUE, E_REVERSE, E_QUOTE, E_ESCAPE_EXPAND,
+ E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE, E_VAL_ESCAPE, E_REPLACE,
+ E_SIZE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS, E_ENUMERATE_VARS,
+ E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH, E_NATIVE_PATH,
+ E_SHELL_QUOTE };
QHash<QString, ExpandFunc> qmake_expandFunctions()
{
static QHash<QString, ExpandFunc> *qmake_expand_functions = 0;
@@ -92,6 +98,7 @@ QHash<QString, ExpandFunc> qmake_expandFunctions()
qmake_expand_functions->insert("eval", E_EVAL);
qmake_expand_functions->insert("list", E_LIST);
qmake_expand_functions->insert("sprintf", E_SPRINTF);
+ qmake_expand_functions->insert("format_number", E_FORMAT_NUMBER);
qmake_expand_functions->insert("join", E_JOIN);
qmake_expand_functions->insert("split", E_SPLIT);
qmake_expand_functions->insert("basename", E_BASENAME);
@@ -100,17 +107,26 @@ QHash<QString, ExpandFunc> qmake_expandFunctions()
qmake_expand_functions->insert("find", E_FIND);
qmake_expand_functions->insert("system", E_SYSTEM);
qmake_expand_functions->insert("unique", E_UNIQUE);
+ qmake_expand_functions->insert("reverse", E_REVERSE);
qmake_expand_functions->insert("quote", E_QUOTE);
qmake_expand_functions->insert("escape_expand", E_ESCAPE_EXPAND);
qmake_expand_functions->insert("upper", E_UPPER);
qmake_expand_functions->insert("lower", E_LOWER);
qmake_expand_functions->insert("re_escape", E_RE_ESCAPE);
+ qmake_expand_functions->insert("val_escape", E_VAL_ESCAPE);
qmake_expand_functions->insert("files", E_FILES);
qmake_expand_functions->insert("prompt", E_PROMPT);
qmake_expand_functions->insert("replace", E_REPLACE);
qmake_expand_functions->insert("size", E_SIZE);
qmake_expand_functions->insert("sort_depends", E_SORT_DEPENDS);
qmake_expand_functions->insert("resolve_depends", E_RESOLVE_DEPENDS);
+ qmake_expand_functions->insert("enumerate_vars", E_ENUMERATE_VARS);
+ qmake_expand_functions->insert("shadowed", E_SHADOWED);
+ qmake_expand_functions->insert("absolute_path", E_ABSOLUTE_PATH);
+ qmake_expand_functions->insert("relative_path", E_RELATIVE_PATH);
+ qmake_expand_functions->insert("clean_path", E_CLEAN_PATH);
+ qmake_expand_functions->insert("native_path", E_NATIVE_PATH);
+ qmake_expand_functions->insert("shell_quote", E_SHELL_QUOTE);
}
return *qmake_expand_functions;
}
@@ -118,8 +134,9 @@ QHash<QString, ExpandFunc> qmake_expandFunctions()
enum TestFunc { T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS,
T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM,
T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE,
- T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_ERROR,
- T_MESSAGE, T_WARNING, T_IF, T_OPTION };
+ T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD,
+ T_DEBUG, T_ERROR, T_MESSAGE, T_WARNING, T_LOG,
+ T_IF, T_OPTION, T_CACHE, T_MKPATH, T_WRITE_FILE, T_TOUCH };
QHash<QString, TestFunc> qmake_testFunctions()
{
static QHash<QString, TestFunc> *qmake_test_functions = 0;
@@ -153,7 +170,12 @@ QHash<QString, TestFunc> qmake_testFunctions()
qmake_test_functions->insert("error", T_ERROR);
qmake_test_functions->insert("message", T_MESSAGE);
qmake_test_functions->insert("warning", T_WARNING);
+ qmake_test_functions->insert("log", T_LOG);
qmake_test_functions->insert("option", T_OPTION);
+ qmake_test_functions->insert("cache", T_CACHE);
+ qmake_test_functions->insert("mkpath", T_MKPATH);
+ qmake_test_functions->insert("write_file", T_WRITE_FILE);
+ qmake_test_functions->insert("touch", T_TOUCH);
}
return *qmake_test_functions;
}
@@ -164,6 +186,21 @@ struct parser_info {
bool from_file;
} parser;
+static QString cached_source_root;
+static QString cached_build_root;
+static QStringList cached_qmakepath;
+static QStringList cached_qmakefeatures;
+
+static QStringList *all_feature_roots[2] = { 0, 0 };
+
+static void
+invalidateFeatureRoots()
+{
+ for (int i = 0; i < 2; i++)
+ if (all_feature_roots[i])
+ all_feature_roots[i]->clear();
+}
+
static QString remove_quotes(const QString &arg)
{
const ushort SINGLEQUOTE = '\'';
@@ -528,7 +565,7 @@ static void qmake_error_msg(const QString &msg)
1) features/(unix|win32|macx)/
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 base_concat = QLatin1String("/features");
@@ -551,36 +588,26 @@ QStringList qmake_feature_paths(QMakeProperty *prop=0)
concat << base_concat;
}
- QStringList feature_roots;
- QByteArray mkspec_path = qgetenv("QMAKEFEATURES");
- if(!mkspec_path.isNull())
- feature_roots += splitPathList(QString::fromLocal8Bit(mkspec_path));
+ QStringList feature_roots = splitPathList(QString::fromLocal8Bit(qgetenv("QMAKEFEATURES")));
+ feature_roots += cached_qmakefeatures;
if(prop)
feature_roots += splitPathList(prop->value("QMAKEFEATURES"));
- if(!Option::mkfile::cachefile.isEmpty()) {
- QString path;
- int last_slash = Option::mkfile::cachefile.lastIndexOf(QLatin1Char('/'));
- if(last_slash != -1)
- path = Option::normalizePath(Option::mkfile::cachefile.left(last_slash), false);
+ if (!cached_build_root.isEmpty())
for(QStringList::Iterator concat_it = concat.begin();
concat_it != concat.end(); ++concat_it)
- feature_roots << (path + (*concat_it));
- }
- QByteArray qmakepath = qgetenv("QMAKEPATH");
- if (!qmakepath.isNull()) {
- const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath));
- for(QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) {
- for(QStringList::Iterator concat_it = concat.begin();
- concat_it != concat.end(); ++concat_it)
- feature_roots << ((*it) + mkspecs_concat + (*concat_it));
- }
- }
- if(!Option::mkfile::qmakespec.isEmpty()) {
+ feature_roots << (cached_build_root + (*concat_it));
+ QStringList qmakepath = splitPathList(QString::fromLocal8Bit(qgetenv("QMAKEPATH")));
+ qmakepath += cached_qmakepath;
+ foreach (const QString &path, qmakepath)
+ foreach (const QString &cat, concat)
+ feature_roots << (path + mkspecs_concat + cat);
+ QString *specp = host_build ? &Option::mkfile::qmakespec : &Option::mkfile::xqmakespec;
+ if (!specp->isEmpty()) {
// 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
- QFileInfo specfi(Option::mkfile::qmakespec);
+ QFileInfo specfi(*specp);
QDir specrootdir(specfi.absolutePath());
while (!specrootdir.isRoot()) {
const QString specrootpath = specrootdir.path();
@@ -596,26 +623,37 @@ QStringList qmake_feature_paths(QMakeProperty *prop=0)
}
for(QStringList::Iterator concat_it = concat.begin();
concat_it != concat.end(); ++concat_it)
- feature_roots << (QLibraryInfo::location(QLibraryInfo::HostDataPath) +
+ feature_roots << (QLibraryInfo::rawLocation(QLibraryInfo::HostDataPath,
+ QLibraryInfo::EffectivePaths) +
mkspecs_concat + (*concat_it));
feature_roots.removeDuplicates();
return feature_roots;
}
+QStringList qmake_mkspec_paths()
+{
+ QStringList ret;
+ const QString concat = QLatin1String("/mkspecs");
+
+ QStringList qmakepath = splitPathList(QString::fromLocal8Bit(qgetenv("QMAKEPATH")));
+ qmakepath += cached_qmakepath;
+ foreach (const QString &path, qmakepath)
+ ret << (path + concat);
+ if (!cached_build_root.isEmpty())
+ ret << cached_build_root + concat;
+ if (!cached_source_root.isEmpty())
+ ret << cached_source_root + concat;
+ ret << QLibraryInfo::rawLocation(QLibraryInfo::HostDataPath, QLibraryInfo::EffectivePaths) + concat;
+ ret.removeDuplicates();
+
+ return ret;
+}
+
QMakeProject::~QMakeProject()
{
if(own_prop)
delete prop;
- 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();
+ cleanup();
}
@@ -630,14 +668,29 @@ QMakeProject::init(QMakeProperty *p)
own_prop = false;
}
recursive = false;
+ host_build = false;
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.
QMakeProject::QMakeProject(QMakeProject *p, const QHash<QString, QStringList> *_vars)
{
init(p->properties());
vars = _vars ? *_vars : p->variables();
+ host_build = p->host_build;
for(QHash<QString, FunctionBlock*>::iterator it = p->replaceFunctions.begin(); it != p->replaceFunctions.end(); ++it) {
it.value()->ref();
replaceFunctions.insert(it.key(), it.value());
@@ -657,6 +710,7 @@ QMakeProject::reset()
iterator = 0;
function = 0;
backslashWarned = false;
+ need_restart = false;
}
bool
@@ -1164,8 +1218,6 @@ QMakeProject::parse(const QString &t, QHash<QString, QStringList> &place, int nu
}
if(var == "REQUIRES") // special case to get communicated to backends!
doProjectCheckReqs(vallist, place);
- else if (var == "_QMAKE_CACHE_")
- Option::mkfile::cachefile = varlist.isEmpty() ? QString() : varlist.at(0);
}
return true;
}
@@ -1205,6 +1257,8 @@ QMakeProject::read(QTextStream &file, QHash<QString, QStringList> &place)
}
s = "";
numLines = 0;
+ if (need_restart)
+ break;
}
}
}
@@ -1250,7 +1304,7 @@ QMakeProject::read(const QString &file, QHash<QString, QStringList> &place)
if(!using_stdin)
qfile.close();
}
- if(scope_blocks.count() != 1) {
+ if (!need_restart && scope_blocks.count() != 1) {
qmake_error_msg("Unterminated conditional block at end of file");
ret = false;
}
@@ -1269,6 +1323,7 @@ QMakeProject::read(const QString &project, uchar cmd)
bool
QMakeProject::read(uchar cmd)
{
+ again:
if ((cmd & ReadSetup) && base_vars.isEmpty()) {
// hack to get the Option stuff in there
base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext;
@@ -1278,13 +1333,147 @@ QMakeProject::read(uchar cmd)
if(!Option::user_template_prefix.isEmpty())
base_vars["TEMPLATE_PREFIX"] = QStringList(Option::user_template_prefix);
+ QString superdir;
+ QString project_root;
+ QString project_build_root;
+ QStringList qmakepath;
+ QStringList qmakefeatures;
if (Option::mkfile::do_cache) { // parse the cache
- if (Option::output_dir.startsWith(Option::mkfile::project_build_root))
+ QHash<QString, QStringList> cache;
+ QString rdir = Option::output_dir;
+ forever {
+ QFileInfo qfi(rdir, QLatin1String(".qmake.super"));
+ if (qfi.exists()) {
+ superfile = qfi.filePath();
+ if (!read(superfile, cache))
+ return false;
+ superdir = rdir;
+ break;
+ }
+ QFileInfo qdfi(rdir);
+ if (qdfi.isRoot())
+ break;
+ rdir = qdfi.path();
+ }
+ if (Option::mkfile::cachefile.isEmpty()) { //find it as it has not been specified
+ QString sdir = qmake_getpwd();
+ QString dir = Option::output_dir;
+ forever {
+ QFileInfo qsfi(sdir, QLatin1String(".qmake.conf"));
+ if (qsfi.exists()) {
+ conffile = qsfi.filePath();
+ if (!read(conffile, cache))
+ return false;
+ }
+ QFileInfo qfi(dir, QLatin1String(".qmake.cache"));
+ if (qfi.exists()) {
+ cachefile = qfi.filePath();
+ if (!read(cachefile, cache))
+ return false;
+ }
+ if (!conffile.isEmpty() || !cachefile.isEmpty()) {
+ project_root = sdir;
+ project_build_root = dir;
+ break;
+ }
+ if (dir == superdir)
+ goto no_cache;
+ QFileInfo qsdfi(sdir);
+ QFileInfo qdfi(dir);
+ if (qsdfi.isRoot() || qdfi.isRoot())
+ goto no_cache;
+ sdir = qsdfi.path();
+ dir = qdfi.path();
+ }
+ } else {
+ QFileInfo fi(Option::mkfile::cachefile);
+ cachefile = QDir::cleanPath(fi.absoluteFilePath());
+ if (!read(cachefile, cache))
+ return false;
+ project_build_root = QDir::cleanPath(fi.absolutePath());
+ // This intentionally bypasses finding a source root,
+ // as the result would be more or less arbitrary.
+ }
+
+ 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();
+ if (Option::mkfile::xqmakespec.isEmpty())
+ Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
+ }
+ qmakepath = cache.value(QLatin1String("QMAKEPATH"));
+ qmakefeatures = cache.value(QLatin1String("QMAKEFEATURES"));
+
+ if (Option::output_dir.startsWith(project_build_root))
Option::mkfile::cachefile_depth =
- Option::output_dir.mid(Option::mkfile::project_build_root.length()).count('/');
+ Option::output_dir.mid(project_build_root.length()).count('/');
+ }
+ no_cache:
+
+ // Look for mkspecs/ in source and build. First to win determines the root.
+ QString sdir = qmake_getpwd();
+ QString dir = Option::output_dir;
+ while (dir != project_build_root) {
+ if ((dir != sdir && QFileInfo(sdir, QLatin1String("mkspecs")).isDir())
+ || QFileInfo(dir, QLatin1String("mkspecs")).isDir()) {
+ if (dir != sdir)
+ project_root = sdir;
+ project_build_root = dir;
+ break;
+ }
+ if (dir == superdir)
+ break;
+ QFileInfo qsdfi(sdir);
+ QFileInfo qdfi(dir);
+ if (qsdfi.isRoot() || qdfi.isRoot())
+ break;
+ sdir = qsdfi.path();
+ dir = qdfi.path();
+ }
+
+ if (qmakepath != cached_qmakepath || qmakefeatures != cached_qmakefeatures
+ || project_build_root != cached_build_root) { // No need to check source dir, as it goes in sync
+ cached_source_root = project_root;
+ cached_build_root = project_build_root;
+ cached_qmakepath = qmakepath;
+ cached_qmakefeatures = qmakefeatures;
+ invalidateFeatureRoots();
}
+
{ // parse mkspec
- QString qmakespec = Option::mkfile::qmakespec;
+ QString *specp = host_build ? &Option::mkfile::qmakespec : &Option::mkfile::xqmakespec;
+ QString qmakespec = *specp;
+ if (qmakespec.isEmpty())
+ qmakespec = host_build ? "default-host" : "default";
+ if (QDir::isRelativePath(qmakespec)) {
+ QStringList mkspec_roots = qmake_mkspec_paths();
+ debug_msg(2, "Looking for mkspec %s in (%s)", qmakespec.toLatin1().constData(),
+ mkspec_roots.join("::").toLatin1().constData());
+ bool found_mkspec = false;
+ for (QStringList::ConstIterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) {
+ QString mkspec = (*it) + QLatin1Char('/') + qmakespec;
+ if (QFile::exists(mkspec)) {
+ found_mkspec = true;
+ *specp = qmakespec = mkspec;
+ break;
+ }
+ }
+ if (!found_mkspec) {
+ fprintf(stderr, "Could not find mkspecs for your QMAKESPEC(%s) after trying:\n\t%s\n",
+ qmakespec.toLatin1().constData(), mkspec_roots.join("\n\t").toLatin1().constData());
+ return false;
+ }
+ }
+
+ // We do this before reading the spec, so it can use module and feature paths from
+ // here without resorting to tricks. This is the only planned use case anyway.
+ if (!superfile.isEmpty()) {
+ debug_msg(1, "Project super cache file: reading %s", superfile.toLatin1().constData());
+ read(superfile, base_vars);
+ }
+
+ // parse qmake configuration
while(qmakespec.endsWith(QLatin1Char('/')))
qmakespec.truncate(qmakespec.length()-1);
QString spec = qmakespec + QLatin1String("/qmake.conf");
@@ -1295,9 +1484,13 @@ QMakeProject::read(uchar cmd)
}
validateModes();
- if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty()) {
- debug_msg(1, "QMAKECACHE file: reading %s", Option::mkfile::cachefile.toLatin1().constData());
- read(Option::mkfile::cachefile, base_vars);
+ if (!conffile.isEmpty()) {
+ debug_msg(1, "Project config file: reading %s", conffile.toLatin1().constData());
+ read(conffile, base_vars);
+ }
+ if (!cachefile.isEmpty()) {
+ debug_msg(1, "QMAKECACHE file: reading %s", cachefile.toLatin1().constData());
+ read(cachefile, base_vars);
}
}
}
@@ -1347,6 +1540,11 @@ QMakeProject::read(uchar cmd)
pfile += Option::pro_ext;
if(!read(pfile, vars))
return false;
+ if (need_restart) {
+ base_vars.clear();
+ cleanup();
+ goto again;
+ }
}
if (cmd & ReadSetup) {
@@ -1443,7 +1641,7 @@ QMakeProject::resolveSpec(QString *spec, const QString &qmakespec)
{
if (spec->isEmpty()) {
*spec = QFileInfo(qmakespec).fileName();
- if (*spec == "default") {
+ if (*spec == "default" || *spec == "default-host") {
#ifdef Q_OS_UNIX
char buffer[1024];
int l = readlink(qmakespec.toLatin1().constData(), buffer, 1023);
@@ -1492,9 +1690,14 @@ QMakeProject::isActiveConfig(const QString &x, bool regex, QHash<QString, QStrin
return Option::target_mode == Option::TARG_WIN_MODE;
}
+ if (x == "host_build")
+ return host_build ? "true" : "false";
+
//mkspecs
- static QString spec;
- resolveSpec(&spec, Option::mkfile::qmakespec);
+ static QString hspec, xspec;
+ resolveSpec(&hspec, Option::mkfile::qmakespec);
+ resolveSpec(&xspec, Option::mkfile::xqmakespec);
+ const QString &spec = host_build ? hspec : xspec;
QRegExp re(x, Qt::CaseSensitive, QRegExp::Wildcard);
if((regex && re.exactMatch(spec)) || (!regex && spec == x))
return true;
@@ -1546,17 +1749,18 @@ QMakeProject::doProjectTest(QString func, const QString &params,
QMakeProject::IncludeStatus
QMakeProject::doProjectInclude(QString file, uchar flags, QHash<QString, QStringList> &place)
{
- enum { UnknownFormat, ProFormat, JSFormat } format = UnknownFormat;
if(flags & IncludeFlagFeature) {
if(!file.endsWith(Option::prf_ext))
file += Option::prf_ext;
validateModes(); // init dir_sep
if(file.indexOf(QLatin1Char('/')) == -1 || !QFile::exists(file)) {
- static QStringList *feature_roots = 0;
+ QStringList *&feature_roots = all_feature_roots[host_build];
if(!feature_roots) {
- feature_roots = new QStringList(qmake_feature_paths(prop));
+ feature_roots = new QStringList;
qmakeAddCacheClear(qmakeDeleteCacheClear<QStringList>, (void**)&feature_roots);
}
+ if (feature_roots->isEmpty())
+ *feature_roots = qmake_feature_paths(prop, host_build);
debug_msg(2, "Looking for feature '%s' in (%s)", file.toLatin1().constData(),
feature_roots->join("::").toLatin1().constData());
int start_root = 0;
@@ -1576,18 +1780,13 @@ QMakeProject::doProjectInclude(QString file, uchar flags, QHash<QString, QString
}
for(int root = start_root; root < feature_roots->size(); ++root) {
QString prf(feature_roots->at(root) + QLatin1Char('/') + file);
- if(QFile::exists(prf + Option::js_ext)) {
- format = JSFormat;
- file = prf + Option::js_ext;
- break;
- } else if(QFile::exists(prf)) {
- format = ProFormat;
+ if (QFile::exists(prf)) {
file = prf;
- break;
+ goto foundf;
}
}
- if(format == UnknownFormat)
- return IncludeNoExist;
+ return IncludeNoExist;
+ foundf: ;
}
if(place["QMAKE_INTERNAL_INCLUDED_FEATURES"].indexOf(file) != -1)
return IncludeFeatureAlreadyLoaded;
@@ -1605,19 +1804,13 @@ QMakeProject::doProjectInclude(QString file, uchar flags, QHash<QString, QString
testName += file;
if(QFile::exists(testName)) {
file = testName;
- break;
+ goto foundi;
}
}
- }
- if(format == UnknownFormat) {
- if(QFile::exists(file)) {
- if(file.endsWith(Option::js_ext))
- format = JSFormat;
- else
- format = ProFormat;
- } else {
- return IncludeNoExist;
- }
+ return IncludeNoExist;
+ foundi: ;
+ } else if (!QFile::exists(file)) {
+ return IncludeNoExist;
}
if(Option::mkfile::do_preprocess) //nice to see this first..
fprintf(stderr, "#switching file %s(%s) - %s:%d\n", (flags & IncludeFlagFeature) ? "load" : "include",
@@ -1637,10 +1830,7 @@ QMakeProject::doProjectInclude(QString file, uchar flags, QHash<QString, QString
}
bool parsed = false;
parser_info pi = parser;
- if(format == JSFormat) {
- warn_msg(WarnParser, "%s:%d: QtScript support disabled for %s.",
- pi.file.toLatin1().constData(), pi.line_no, orig_file.toLatin1().constData());
- } else {
+ {
if(flags & (IncludeFlagNewProject|IncludeFlagNewParser)) {
// The "project's variables" are used in other places (eg. export()) so it's not
// possible to use "place" everywhere. Instead just set variables and grab them later
@@ -1675,6 +1865,199 @@ QMakeProject::doProjectInclude(QString file, uchar flags, QHash<QString, QString
return IncludeSuccess;
}
+static void
+subAll(QStringList *val, const QStringList &diffval)
+{
+ foreach (const QString &dv, diffval)
+ val->removeAll(dv);
+}
+
+inline static
+bool isSpecialChar(ushort c)
+{
+ // Chars that should be quoted (TM). This includes:
+#ifdef Q_OS_WIN
+ // - control chars & space
+ // - the shell meta chars "&()<>^|
+ // - the potential separators ,;=
+ static const uchar iqm[] = {
+ 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
+ };
+#else
+ static const uchar iqm[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
+ 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
+ }; // 0-32 \'"$`<>|;&(){}*?#!~[]
+#endif
+
+ return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
+}
+
+inline static
+bool hasSpecialChars(const QString &arg)
+{
+ for (int x = arg.length() - 1; x >= 0; --x)
+ if (isSpecialChar(arg.unicode()[x].unicode()))
+ return true;
+ return false;
+}
+
+static QString
+shellQuote(const QString &arg)
+{
+ if (!arg.length())
+ return QString::fromLatin1("\"\"");
+
+ QString ret(arg);
+ if (hasSpecialChars(ret)) {
+#ifdef Q_OS_WIN
+ // Quotes are escaped and their preceding backslashes are doubled.
+ // It's impossible to escape anything inside a quoted string on cmd
+ // level, so the outer quoting must be "suspended".
+ ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\""));
+ // The argument must not end with a \ since this would be interpreted
+ // as escaping the quote -- rather put the \ behind the quote: e.g.
+ // rather use "foo"\ than "foo\"
+ int i = ret.length();
+ while (i > 0 && ret.at(i - 1) == QLatin1Char('\\'))
+ --i;
+ ret.insert(i, QLatin1Char('"'));
+ ret.prepend(QLatin1Char('"'));
+#else // Q_OS_WIN
+ ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
+ ret.prepend(QLatin1Char('\''));
+ ret.append(QLatin1Char('\''));
+#endif // Q_OS_WIN
+ }
+ return ret;
+}
+
+static QString
+quoteValue(const QString &val)
+{
+ QString ret;
+ ret.reserve(val.length());
+ bool quote = val.isEmpty();
+ bool escaping = false;
+ for (int i = 0, l = val.length(); i < l; i++) {
+ QChar c = val.unicode()[i];
+ ushort uc = c.unicode();
+ if (uc < 32) {
+ if (!escaping) {
+ escaping = true;
+ ret += QLatin1String("$$escape_expand(");
+ }
+ switch (uc) {
+ case '\r':
+ ret += QLatin1String("\\\\r");
+ break;
+ case '\n':
+ ret += QLatin1String("\\\\n");
+ break;
+ case '\t':
+ ret += QLatin1String("\\\\t");
+ break;
+ default:
+ ret += QString::fromLatin1("\\\\x%1").arg(uc, 2, 16, QLatin1Char('0'));
+ break;
+ }
+ } else {
+ if (escaping) {
+ escaping = false;
+ ret += QLatin1Char(')');
+ }
+ switch (uc) {
+ case '\\':
+ ret += QLatin1String("\\\\");
+ break;
+ case '"':
+ ret += QLatin1String("\\\"");
+ break;
+ case '\'':
+ ret += QLatin1String("\\'");
+ break;
+ case '$':
+ ret += QLatin1String("\\$");
+ break;
+ case '#':
+ ret += QLatin1String("$${LITERAL_HASH}");
+ break;
+ case 32:
+ quote = true;
+ // fallthrough
+ default:
+ ret += c;
+ break;
+ }
+ }
+ }
+ if (escaping)
+ ret += QLatin1Char(')');
+ if (quote) {
+ ret.prepend(QLatin1Char('"'));
+ ret.append(QLatin1Char('"'));
+ }
+ return ret;
+}
+
+static bool
+writeFile(const QString &name, QIODevice::OpenMode mode, const QString &contents, QString *errStr)
+{
+ QByteArray bytes = contents.toLocal8Bit();
+ QFile cfile(name);
+ if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ if (cfile.readAll() == bytes)
+ return true;
+ cfile.close();
+ }
+ if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) {
+ *errStr = cfile.errorString();
+ return false;
+ }
+ cfile.write(bytes);
+ cfile.close();
+ if (cfile.error() != QFile::NoError) {
+ *errStr = cfile.errorString();
+ return false;
+ }
+ return true;
+}
+
+static QByteArray
+getCommandOutput(const QString &args)
+{
+ QByteArray out;
+ if (FILE *proc = QT_POPEN(args.toLatin1().constData(), "r")) {
+ while (!feof(proc)) {
+ char buff[10 * 1024];
+ int read_in = int(fread(buff, 1, sizeof(buff), proc));
+ if (!read_in)
+ break;
+ out += QByteArray(buff, read_in);
+ }
+ QT_PCLOSE(proc);
+ }
+ return out;
+}
+
+#ifdef Q_OS_WIN
+static QString windowsErrorCode()
+{
+ wchar_t *string = 0;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPWSTR)&string,
+ 0,
+ NULL);
+ QString ret = QString::fromWCharArray(string);
+ LocalFree((HLOCAL)string);
+ return ret;
+}
+#endif
+
QStringList
QMakeProject::doProjectExpand(QString func, const QString &params,
QHash<QString, QStringList> &place)
@@ -1818,19 +2201,33 @@ QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list,
} else {
QString file = Option::normalizePath(args[0]);
+ bool blob = false;
+ bool lines = false;
bool singleLine = true;
- if(args.count() > 1)
- singleLine = (args[1].toLower() == "true");
-
+ if (args.count() > 1) {
+ if (!args.at(1).compare(QLatin1String("false"), Qt::CaseInsensitive))
+ singleLine = false;
+ else if (!args.at(1).compare(QLatin1String("blob"), Qt::CaseInsensitive))
+ blob = true;
+ else if (!args.at(1).compare(QLatin1String("lines"), Qt::CaseInsensitive))
+ lines = true;
+ }
QFile qfile(file);
if(qfile.open(QIODevice::ReadOnly)) {
QTextStream stream(&qfile);
- while(!stream.atEnd()) {
- ret += split_value_list(stream.readLine().trimmed());
- if(!singleLine)
- ret += "\n";
+ if (blob) {
+ ret += stream.readAll();
+ } else {
+ while (!stream.atEnd()) {
+ if (lines) {
+ ret += stream.readLine();
+ } else {
+ ret += split_value_list(stream.readLine().trimmed());
+ if (!singleLine)
+ ret += "\n";
+ }
+ }
}
- qfile.close();
}
}
break; }
@@ -1897,6 +2294,79 @@ QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list,
ret = split_value_list(tmp);
}
break; }
+ case E_FORMAT_NUMBER:
+ if (args.count() > 2) {
+ fprintf(stderr, "%s:%d: format_number(number[, options...]) requires one or two arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ int ibase = 10;
+ int obase = 10;
+ int width = 0;
+ bool zeropad = false;
+ bool leftalign = false;
+ enum { DefaultSign, PadSign, AlwaysSign } sign = DefaultSign;
+ if (args.count() >= 2) {
+ foreach (const QString &opt, split_value_list(args.at(1))) {
+ if (opt.startsWith(QLatin1String("ibase="))) {
+ ibase = opt.mid(6).toInt();
+ } else if (opt.startsWith(QLatin1String("obase="))) {
+ obase = opt.mid(6).toInt();
+ } else if (opt.startsWith(QLatin1String("width="))) {
+ width = opt.mid(6).toInt();
+ } else if (opt == QLatin1String("zeropad")) {
+ zeropad = true;
+ } else if (opt == QLatin1String("padsign")) {
+ sign = PadSign;
+ } else if (opt == QLatin1String("alwayssign")) {
+ sign = AlwaysSign;
+ } else if (opt == QLatin1String("leftalign")) {
+ leftalign = true;
+ } else {
+ fprintf(stderr, "%s:%d: format_number(): invalid format option %s.\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ opt.toLatin1().constData());
+ goto formfail;
+ }
+ }
+ }
+ if (args.at(0).contains(QLatin1Char('.'))) {
+ fprintf(stderr, "%s:%d: format_number(): floats are currently not supported.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ break;
+ }
+ bool ok;
+ qlonglong num = args.at(0).toLongLong(&ok, ibase);
+ if (!ok) {
+ fprintf(stderr, "%s:%d: format_number(): malformed number %s for base %d.\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ args.at(0).toLatin1().constData(), ibase);
+ break;
+ }
+ QString outstr;
+ if (num < 0) {
+ num = -num;
+ outstr = QLatin1Char('-');
+ } else if (sign == AlwaysSign) {
+ outstr = QLatin1Char('+');
+ } else if (sign == PadSign) {
+ outstr = QLatin1Char(' ');
+ }
+ QString numstr = QString::number(num, obase);
+ int space = width - outstr.length() - numstr.length();
+ if (space <= 0) {
+ outstr += numstr;
+ } else if (leftalign) {
+ outstr += numstr + QString(space, QLatin1Char(' '));
+ } else if (zeropad) {
+ outstr += QString(space, QLatin1Char('0')) + numstr;
+ } else {
+ outstr.prepend(QString(space, QLatin1Char(' ')));
+ outstr += numstr;
+ }
+ ret += outstr;
+ }
+ formfail:
+ break;
case E_JOIN: {
if(args.count() < 1 || args.count() > 4) {
fprintf(stderr, "%s:%d: join(var, glue, before, after) requires four"
@@ -1991,26 +2461,33 @@ QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list,
fprintf(stderr, "%s:%d system(execut) requires one argument.\n",
parser.file.toLatin1().constData(), parser.line_no);
} else {
- char buff[256];
+ bool blob = false;
+ bool lines = false;
bool singleLine = true;
- if(args.count() > 1)
- singleLine = (args[1].toLower() == "true");
- QString output;
- FILE *proc = QT_POPEN(args[0].toLatin1().constData(), "r");
- while(proc && !feof(proc)) {
- int read_in = int(fread(buff, 1, 255, proc));
- if(!read_in)
- break;
- for(int i = 0; i < read_in; i++) {
- if((singleLine && buff[i] == '\n') || buff[i] == '\t')
- buff[i] = ' ';
+ if (args.count() > 1) {
+ if (!args.at(1).compare(QLatin1String("false"), Qt::CaseInsensitive))
+ singleLine = false;
+ else if (!args.at(1).compare(QLatin1String("blob"), Qt::CaseInsensitive))
+ blob = true;
+ else if (!args.at(1).compare(QLatin1String("lines"), Qt::CaseInsensitive))
+ lines = true;
+ }
+ QByteArray bytes = getCommandOutput(args.at(0));
+ if (lines) {
+ QTextStream stream(bytes);
+ while (!stream.atEnd())
+ ret += stream.readLine();
+ } else {
+ QString output = QString::fromLocal8Bit(bytes);
+ if (blob) {
+ ret += output;
+ } else {
+ output.replace(QLatin1Char('\t'), QLatin1Char(' '));
+ if (singleLine)
+ output.replace(QLatin1Char('\n'), QLatin1Char(' '));
+ ret += split_value_list(output);
}
- buff[read_in] = '\0';
- output += buff;
}
- ret += split_value_list(output);
- if(proc)
- QT_PCLOSE(proc);
}
break; }
case E_UNIQUE: {
@@ -2025,6 +2502,17 @@ QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list,
}
}
break; }
+ case E_REVERSE:
+ if (args.count() != 1) {
+ fprintf(stderr, "%s:%d reverse(var) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ QStringList var = values(args.first(), place);
+ for (int i = 0; i < var.size() / 2; i++)
+ var.swap(i, var.size() - i - 1);
+ ret += var;
+ }
+ break;
case E_QUOTE:
ret = args;
break;
@@ -2064,6 +2552,17 @@ QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list,
for(int i = 0; i < args.size(); ++i)
ret += QRegExp::escape(args[i]);
break; }
+ case E_VAL_ESCAPE:
+ if (args.count() != 1) {
+ fprintf(stderr, "%s:%d val_escape(var) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ QStringList vals = values(args.at(0), place);
+ ret.reserve(vals.length());
+ foreach (const QString &str, vals)
+ ret += quoteValue(str);
+ }
+ break;
case E_UPPER:
case E_LOWER: {
for(int i = 0; i < args.size(); ++i) {
@@ -2181,6 +2680,53 @@ QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list,
}
}
break; }
+ case E_ENUMERATE_VARS:
+ ret += place.keys();
+ break;
+ case E_SHADOWED: {
+ QString val = QDir::cleanPath(QFileInfo(args.at(0)).absoluteFilePath());
+ if (Option::mkfile::source_root.isEmpty())
+ ret += val;
+ else if (val.startsWith(Option::mkfile::source_root))
+ ret += Option::mkfile::build_root + val.mid(Option::mkfile::source_root.length());
+ break; }
+ case E_ABSOLUTE_PATH:
+ if (args.count() > 2)
+ fprintf(stderr, "%s:%d absolute_path(path[, base]) requires one or two arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ else
+ ret += QDir::cleanPath(QDir(args.count() > 1 ? args.at(1) : QString())
+ .absoluteFilePath(args.at(0)));
+ break;
+ case E_RELATIVE_PATH:
+ if (args.count() > 2)
+ fprintf(stderr, "%s:%d relative_path(path[, base]) requires one or two arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ else
+ ret += QDir::cleanPath(QDir(args.count() > 1 ? args.at(1) : QString())
+ .relativeFilePath(args.at(0)));
+ break;
+ case E_CLEAN_PATH:
+ if (args.count() != 1)
+ fprintf(stderr, "%s:%d clean_path(path) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ else
+ ret += QDir::cleanPath(args.at(0));
+ break;
+ case E_NATIVE_PATH:
+ if (args.count() != 1)
+ fprintf(stderr, "%s:%d native_path(path) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ else
+ ret += Option::fixPathToTargetOS(args.at(0), false);
+ break;
+ case E_SHELL_QUOTE:
+ if (args.count() != 1)
+ fprintf(stderr, "%s:%d shell_quote(args) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ else
+ ret += shellQuote(args.at(0));
+ break;
default: {
fprintf(stderr, "%s:%d: Unknown replace function: %s\n",
parser.file.toLatin1().constData(), parser.line_no,
@@ -2448,6 +2994,8 @@ QMakeProject::doProjectTest(QString func, QList<QStringList> args_list, QHash<QS
return testFunctions.contains(args[0]);
else if(args[1] == "replace")
return replaceFunctions.contains(args[0]);
+ else if(args[1] == "var")
+ return place.contains(args[0]);
fprintf(stderr, "%s:%d: defined(function, type): unexpected type [%s].\n",
parser.file.toLatin1().constData(), parser.line_no,
args[1].toLatin1().constData());
@@ -2623,6 +3171,7 @@ QMakeProject::doProjectTest(QString func, QList<QStringList> args_list, QHash<QS
QString msg = fixEnvVariables(args[1]);
debug_msg(args[0].toInt(), "Project DEBUG: %s", msg.toLatin1().constData());
return true; }
+ case T_LOG:
case T_ERROR:
case T_MESSAGE:
case T_WARNING: {
@@ -2632,13 +3181,17 @@ QMakeProject::doProjectTest(QString func, QList<QStringList> args_list, QHash<QS
return false;
}
QString msg = fixEnvVariables(args.first());
- fprintf(stderr, "Project %s: %s\n", func.toUpper().toLatin1().constData(), msg.toLatin1().constData());
- if(func == "error")
+ if (func_t == T_LOG) {
+ fputs(msg.toLatin1().constData(), stderr);
+ } else {
+ fprintf(stderr, "Project %s: %s\n", func.toUpper().toLatin1().constData(), msg.toLatin1().constData());
+ if (func == "error")
#if defined(QT_BUILD_QMAKE_LIBRARY)
- return false;
+ return false;
#else
- exit(2);
+ exit(2);
#endif
+ }
return true; }
case T_OPTION:
if (args.count() != 1) {
@@ -2648,6 +3201,11 @@ QMakeProject::doProjectTest(QString func, QList<QStringList> args_list, QHash<QS
}
if (args.first() == "recursive") {
recursive = true;
+ } else if (args.first() == "host_build") {
+ if (!host_build && isActiveConfig("cross_compile")) {
+ host_build = true;
+ need_restart = true;
+ }
} else {
fprintf(stderr, "%s:%d: unrecognized option() argument '%s'.\n",
parser.file.toLatin1().constData(), parser.line_no,
@@ -2655,6 +3213,238 @@ QMakeProject::doProjectTest(QString func, QList<QStringList> args_list, QHash<QS
return false;
}
return true;
+ case T_CACHE: {
+ if (args.count() > 3) {
+ fprintf(stderr, "%s:%d: cache(var, [set|add|sub] [transient] [super], [srcvar]) requires one to three arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+ bool persist = true;
+ bool super = false;
+ enum { CacheSet, CacheAdd, CacheSub } mode = CacheSet;
+ QString srcvar;
+ if (args.count() >= 2) {
+ foreach (const QString &opt, split_value_list(args.at(1))) {
+ if (opt == QLatin1String("transient")) {
+ persist = false;
+ } else if (opt == QLatin1String("super")) {
+ super = true;
+ } else if (opt == QLatin1String("set")) {
+ mode = CacheSet;
+ } else if (opt == QLatin1String("add")) {
+ mode = CacheAdd;
+ } else if (opt == QLatin1String("sub")) {
+ mode = CacheSub;
+ } else {
+ fprintf(stderr, "%s:%d: cache(): invalid flag %s.\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ opt.toLatin1().constData());
+ return false;
+ }
+ }
+ if (args.count() >= 3) {
+ srcvar = args.at(2);
+ } else if (mode != CacheSet) {
+ fprintf(stderr, "%s:%d: cache(): modes other than 'set' require a source variable.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+ }
+ QString varstr;
+ QString dstvar = args.at(0);
+ if (!dstvar.isEmpty()) {
+ if (srcvar.isEmpty())
+ srcvar = dstvar;
+ if (!place.contains(srcvar)) {
+ fprintf(stderr, "%s:%d: variable %s is not defined.\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ srcvar.toLatin1().constData());
+ return false;
+ }
+ // The current ("native") value can differ from the cached value, e.g., the current
+ // CONFIG will typically have more values than the cached one. Therefore we deal with
+ // them separately.
+ const QStringList diffval = values(srcvar, place);
+ const QStringList oldval = base_vars.value(dstvar);
+ QStringList newval;
+ if (mode == CacheSet) {
+ newval = diffval;
+ } else {
+ newval = oldval;
+ if (mode == CacheAdd)
+ newval += diffval;
+ else
+ subAll(&newval, diffval);
+ }
+ // We assume that whatever got the cached value to be what it is now will do so
+ // the next time as well, so it is OK that the early exit here will skip the
+ // persisting as well.
+ if (oldval == newval)
+ return true;
+ base_vars[dstvar] = newval;
+ do {
+ if (dstvar == "QMAKEPATH")
+ cached_qmakepath = newval;
+ else if (dstvar == "QMAKEFEATURES")
+ cached_qmakefeatures = newval;
+ else
+ break;
+ invalidateFeatureRoots();
+ } while (false);
+ if (!persist)
+ return true;
+ varstr = dstvar;
+ if (mode == CacheAdd)
+ varstr += QLatin1String(" +=");
+ else if (mode == CacheSub)
+ varstr += QLatin1String(" -=");
+ else
+ varstr += QLatin1String(" =");
+ if (diffval.count() == 1) {
+ varstr += QLatin1Char(' ');
+ varstr += quoteValue(diffval.at(0));
+ } else if (!diffval.isEmpty()) {
+ foreach (const QString &vval, diffval) {
+ varstr += QLatin1String(" \\\n ");
+ varstr += quoteValue(vval);
+ }
+ }
+ varstr += QLatin1Char('\n');
+ }
+ QString fn;
+ if (super) {
+ if (superfile.isEmpty()) {
+ superfile = Option::output_dir + QLatin1String("/.qmake.super");
+ printf("Info: creating super cache file %s\n", superfile.toLatin1().constData());
+ }
+ fn = superfile;
+ } else {
+ if (cachefile.isEmpty()) {
+ cachefile = Option::output_dir + QLatin1String("/.qmake.cache");
+ printf("Info: creating cache file %s\n", cachefile.toLatin1().constData());
+ if (cached_build_root.isEmpty()) {
+ cached_build_root = Option::output_dir;
+ cached_source_root = values("_PRO_FILE_PWD_", place).first();
+ if (cached_source_root == cached_build_root)
+ cached_source_root.clear();
+ invalidateFeatureRoots();
+ }
+ }
+ fn = cachefile;
+ }
+ QFileInfo qfi(fn);
+ if (!QDir::current().mkpath(qfi.path())) {
+ fprintf(stderr, "%s:%d: ERROR creating cache directory %s\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ qfi.path().toLatin1().constData());
+ return false;
+ }
+ QString errStr;
+ if (!writeFile(fn, QIODevice::Append, varstr, &errStr)) {
+ fprintf(stderr, "ERROR writing cache file %s: %s\n",
+ fn.toLatin1().constData(), errStr.toLatin1().constData());
+#if defined(QT_BUILD_QMAKE_LIBRARY)
+ return false;
+#else
+ exit(2);
+#endif
+ }
+ return true; }
+ case T_MKPATH:
+ if (args.count() != 1) {
+ fprintf(stderr, "%s:%d: mkpath(name) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+ if (!QDir::current().mkpath(args.at(0))) {
+ fprintf(stderr, "%s:%d: ERROR creating directory %s\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ QDir::toNativeSeparators(args.at(0)).toLatin1().constData());
+ return false;
+ }
+ return true;
+ case T_WRITE_FILE: {
+ if (args.count() > 3) {
+ fprintf(stderr, "%s:%d: write_file(name, [content var, [append]]) requires one to three arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+ QIODevice::OpenMode mode = QIODevice::Truncate;
+ QString contents;
+ if (args.count() >= 2) {
+ QStringList vals = values(args.at(1), place);
+ if (!vals.isEmpty())
+ contents = vals.join(QLatin1String("\n")) + QLatin1Char('\n');
+ if (args.count() >= 3)
+ if (!args.at(2).compare(QLatin1String("append"), Qt::CaseInsensitive))
+ mode = QIODevice::Append;
+ }
+ QFileInfo qfi(args.at(0));
+ if (!QDir::current().mkpath(qfi.path())) {
+ fprintf(stderr, "%s:%d: ERROR creating directory %s\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ qfi.path().toLatin1().constData());
+ return false;
+ }
+ QString errStr;
+ if (!writeFile(args.at(0), mode, contents, &errStr)) {
+ fprintf(stderr, "%s:%d ERROR writing %s: %s\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ args.at(0).toLatin1().constData(), errStr.toLatin1().constData());
+ return false;
+ }
+ return true; }
+ case T_TOUCH: {
+ if (args.count() != 2) {
+ fprintf(stderr, "%s:%d: touch(file, reffile) requires two arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+#ifdef Q_OS_UNIX
+ struct stat st;
+ if (stat(args.at(1).toLocal8Bit().constData(), &st)) {
+ fprintf(stderr, "%s:%d: ERROR: cannot stat() reference file %s: %s.\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ args.at(1).toLatin1().constData(), strerror(errno));
+ return false;
+ }
+ struct utimbuf utb;
+ utb.actime = time(0);
+ utb.modtime = st.st_mtime;
+ if (utime(args.at(0).toLocal8Bit().constData(), &utb)) {
+ fprintf(stderr, "%s:%d: ERROR: cannot touch %s: %s.\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ args.at(0).toLatin1().constData(), strerror(errno));
+ return false;
+ }
+#else
+ HANDLE rHand = CreateFile((wchar_t*)args.at(1).utf16(),
+ GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (rHand == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "%s:%d: ERROR: cannot open() reference file %s: %s.\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ args.at(1).toLatin1().constData(),
+ windowsErrorCode().toLatin1().constData());
+ return false;
+ }
+ FILETIME ft;
+ GetFileTime(rHand, 0, 0, &ft);
+ CloseHandle(rHand);
+ HANDLE wHand = CreateFile((wchar_t*)args.at(0).utf16(),
+ GENERIC_WRITE, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (wHand == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "%s:%d: ERROR: cannot open %s: %s.\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ args.at(0).toLatin1().constData(),
+ windowsErrorCode().toLatin1().constData());
+ return false;
+ }
+ SetFileTime(wHand, 0, 0, &ft);
+ CloseHandle(wHand);
+#endif
+ break; }
default:
fprintf(stderr, "%s:%d: Unknown test function: %s\n", parser.file.toLatin1().constData(), parser.line_no,
func.toLatin1().constData());
@@ -2968,7 +3758,11 @@ QStringList &QMakeProject::values(const QString &_var, QHash<QString, QStringLis
} else if(var == QLatin1String("_QMAKE_CACHE_")) {
var = ".BUILTIN." + var;
if(Option::mkfile::do_cache)
- place[var] = QStringList(Option::mkfile::cachefile);
+ place[var] = QStringList(cachefile);
+ } else if(var == QLatin1String("_QMAKE_SUPER_CACHE_")) {
+ var = ".BUILTIN." + var;
+ if(Option::mkfile::do_cache && !superfile.isEmpty())
+ place[var] = QStringList(superfile);
} else if(var == QLatin1String("TEMPLATE")) {
if(!Option::user_template.isEmpty()) {
var = ".BUILTIN.USER." + var;
@@ -3067,11 +3861,11 @@ QStringList &QMakeProject::values(const QString &_var, QHash<QString, QStringLis
}
} else if (var == QLatin1String("QMAKE_QMAKE")) {
if (place[var].isEmpty())
- place[var] = QStringList(Option::fixPathToTargetOS(
+ place[var] = QStringList(
!Option::qmake_abslocation.isEmpty()
? Option::qmake_abslocation
- : QLibraryInfo::location(QLibraryInfo::HostBinariesPath) + "/qmake",
- false));
+ : QLibraryInfo::rawLocation(QLibraryInfo::HostBinariesPath,
+ QLibraryInfo::EffectivePaths) + "/qmake");
}
#if defined(Q_OS_WIN32) && defined(Q_CC_MSVC)
else if(var.startsWith(QLatin1String("QMAKE_TARGET."))) {
diff --git a/qmake/project.h b/qmake/project.h
index ccdc1b63f1..e733f6097c 100644
--- a/qmake/project.h
+++ b/qmake/project.h
@@ -79,8 +79,13 @@ class QMakeProject
QHash<QString, FunctionBlock*> testFunctions, replaceFunctions;
bool recursive;
+ bool host_build;
+ bool need_restart;
bool own_prop;
bool backslashWarned;
+ QString conffile;
+ QString superfile;
+ QString cachefile;
QString pfile;
QMakeProperty *prop;
void reset();
@@ -107,6 +112,7 @@ class QMakeProject
bool doVariableReplace(QString &str, QHash<QString, QStringList> &place);
QStringList doVariableReplaceExpand(const QString &str, QHash<QString, QStringList> &place, bool *ok=0);
void init(QMakeProperty *);
+ void cleanup();
QStringList &values(const QString &v, QHash<QString, QStringList> &place);
void validateModes();
void resolveSpec(QString *spec, const QString &qmakespec);
@@ -128,6 +134,8 @@ public:
QStringList userTestFunctions() { return testFunctions.keys(); }
QString projectFile();
+ QString confFile() const { return conffile; }
+ QString cacheFile() const { return cachefile; }
inline QMakeProperty *properties() { return prop; }
bool doProjectTest(QString str, QHash<QString, QStringList> &place);
@@ -160,6 +168,7 @@ public:
QHash<QString, QStringList> &variables(); // No compat mapping and magic, obviously
bool isRecursive() const { return recursive; }
+ bool isHostBuild() const { return host_build; }
protected:
friend class MakefileGenerator;
diff --git a/qmake/property.cpp b/qmake/property.cpp
index 1952b5069b..8d2e14ca11 100644
--- a/qmake/property.cpp
+++ b/qmake/property.cpp
@@ -49,6 +49,8 @@
QT_BEGIN_NAMESPACE
+QStringList qmake_mkspec_paths(); //project.cpp
+
static const struct {
const char *name;
QLibraryInfo::LibraryLocation loc;
@@ -77,7 +79,8 @@ QMakeProperty::QMakeProperty() : settings(0)
{
for (int i = 0; i < sizeof(propList)/sizeof(propList[0]); i++) {
QString name = QString::fromLatin1(propList[i].name);
- QString val = QLibraryInfo::rawLocation(propList[i].loc);
+ m_values[name + "/get"] = QLibraryInfo::rawLocation(propList[i].loc, QLibraryInfo::EffectivePaths);
+ QString val = QLibraryInfo::rawLocation(propList[i].loc, QLibraryInfo::FinalPaths);
if (!propList[i].raw) {
m_values[name] = QLibraryInfo::location(propList[i].loc);
name += "/raw";
@@ -115,7 +118,7 @@ QMakeProperty::value(QString v, bool just_check)
if (!val.isNull())
return val;
else if(v == "QMAKE_MKSPECS")
- return Option::mkspecPaths().join(Option::dirlist_sep);
+ return qmake_mkspec_paths().join(Option::dirlist_sep);
else if(v == "QMAKE_VERSION")
return qmake_version();
#ifdef QT_VERSION_STR
@@ -212,9 +215,12 @@ QMakeProperty::exec()
foreach (QString prop, specialProps) {
QString val = value(prop);
QString pval = value(prop + "/raw");
+ QString gval = value(prop + "/get");
fprintf(stdout, "%s:%s\n", prop.toLatin1().constData(), val.toLatin1().constData());
if (!pval.isEmpty() && pval != val)
fprintf(stdout, "%s/raw:%s\n", prop.toLatin1().constData(), pval.toLatin1().constData());
+ if (!gval.isEmpty() && gval != (pval.isEmpty() ? val : pval))
+ fprintf(stdout, "%s/get:%s\n", prop.toLatin1().constData(), gval.toLatin1().constData());
}
return true;
}
diff --git a/qmake/qmake.pri b/qmake/qmake.pri
index cfa0c1359d..68b78f8d21 100644
--- a/qmake/qmake.pri
+++ b/qmake/qmake.pri
@@ -14,7 +14,8 @@ SOURCES += project.cpp property.cpp main.cpp generators/makefile.cpp \
generators/win32/msvc_vcproj.cpp \
generators/win32/msvc_vcxproj.cpp \
generators/win32/msvc_objectmodel.cpp generators/win32/msbuild_objectmodel.cpp \
- generators/integrity/gbuild.cpp
+ generators/integrity/gbuild.cpp \
+ generators/win32/cesdkhandler.cpp
HEADERS += project.h property.h generators/makefile.h \
generators/unix/unixmake.h meta.h option.h cachekeys.h \
@@ -24,7 +25,8 @@ HEADERS += project.h property.h generators/makefile.h \
generators/win32/msvc_vcproj.h \
generators/win32/msvc_vcxproj.h \
generators/win32/msvc_objectmodel.h generators/win32/msbuild_objectmodel.h \
- generators/integrity/gbuild.h
+ generators/integrity/gbuild.h \
+ generators/win32/cesdkhandler.h
contains(QT_EDITION, OpenSource) {
DEFINES += QMAKE_OPENSOURCE_EDITION
diff --git a/qmake/qmake.pro b/qmake/qmake.pro
index 5a5010ff6a..0693d9a4ac 100644
--- a/qmake/qmake.pro
+++ b/qmake/qmake.pro
@@ -3,6 +3,7 @@
#once you are boot strapped though, the qmake.pro will offer better coverage of a
#platform than either of the generic makefiles
+option(host_build)
CONFIG += console bootstrap
CONFIG -= qt shared app_bundle uic
DEFINES += QT_BUILD_QMAKE QT_BOOTSTRAPPED