qmake: Harden logic for handling the -o option
We now treat -o foo/bar/baz as a request to generate the output in the foo/bar directory with baz as the output name, or if foo/bar/baz is already a directory, in the foo/bar/baz directory with the default output name. We take care to handle generator specific directory structures, so that the project directory does not get merged into OUT_PWD. This is done in runQmake(), before parsing the project file, so that OUT_PWD will be correct during project parsing. The individual generators are then passed the filename relative to the final output directory. Each generator now also makes sure to add the right project suffix to the output file, so -o foo will result in foo.pro or foo.vcproj, instead of just foo. Task-number: QTBUG-44408 Change-Id: I26990cec0c0458bee2b88dbb86322617a85f54b5 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
This commit is contained in:
parent
3ed22c5efe
commit
8cea3ec8ce
@ -1882,33 +1882,28 @@ ProjectBuilderMakefileGenerator::keyFor(const QString &block)
|
||||
bool
|
||||
ProjectBuilderMakefileGenerator::openOutput(QFile &file, const QString &build) const
|
||||
{
|
||||
if(QDir::isRelativePath(file.fileName()))
|
||||
file.setFileName(Option::output_dir + "/" + file.fileName()); //pwd when qmake was run
|
||||
Q_ASSERT_X(QDir::isRelativePath(file.fileName()), "ProjectBuilderMakefileGenerator",
|
||||
"runQMake() should have normalized the filename and made it relative");
|
||||
|
||||
QFileInfo fi(fileInfo(file.fileName()));
|
||||
if(fi.suffix() != "pbxproj" || file.fileName().isEmpty()) {
|
||||
if (fi.suffix() != "pbxproj") {
|
||||
QString output = file.fileName();
|
||||
if(fi.isDir())
|
||||
output += QDir::separator();
|
||||
if (!output.endsWith(projectSuffix())) {
|
||||
if(file.fileName().isEmpty() || fi.isDir()) {
|
||||
if (fi.fileName().isEmpty()) {
|
||||
if (project->first("TEMPLATE") == "subdirs" || project->isEmpty("QMAKE_ORIG_TARGET"))
|
||||
output += fileInfo(project->projectFile()).baseName();
|
||||
else
|
||||
output += project->first("QMAKE_ORIG_TARGET").toQString();
|
||||
}
|
||||
output += projectSuffix() + QDir::separator();
|
||||
} else if(output[(int)output.length() - 1] != QDir::separator()) {
|
||||
} else {
|
||||
output += QDir::separator();
|
||||
}
|
||||
output += QString("project.pbxproj");
|
||||
file.setFileName(output);
|
||||
bool ret = UnixMakefileGenerator::openOutput(file, build);
|
||||
((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir.section(Option::dir_sep, 0, -1);
|
||||
Option::output_dir = pbx_dir.section(Option::dir_sep, 0, -2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir;
|
||||
pbx_dir = Option::output_dir + Option::dir_sep + file.fileName().section(Option::dir_sep, 0, 0);
|
||||
return UnixMakefileGenerator::openOutput(file, build);
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ QT_BEGIN_NAMESPACE
|
||||
class ProjectBuilderMakefileGenerator : public UnixMakefileGenerator
|
||||
{
|
||||
bool writingUnixMakefileGenerator;
|
||||
QString pbx_dir;
|
||||
mutable QString pbx_dir;
|
||||
int pbuilderVersion() const;
|
||||
bool writeSubDirs(QTextStream &);
|
||||
bool writeMakeParts(QTextStream &);
|
||||
|
@ -3167,54 +3167,31 @@ MakefileGenerator::specdir()
|
||||
bool
|
||||
MakefileGenerator::openOutput(QFile &file, const QString &build) const
|
||||
{
|
||||
{
|
||||
QString outdir;
|
||||
if(!file.fileName().isEmpty()) {
|
||||
if(QDir::isRelativePath(file.fileName()))
|
||||
file.setFileName(Option::output_dir + "/" + file.fileName()); //pwd when qmake was run
|
||||
QFileInfo fi(fileInfo(file.fileName()));
|
||||
if(fi.isDir())
|
||||
outdir = file.fileName() + '/';
|
||||
}
|
||||
if(!outdir.isEmpty() || file.fileName().isEmpty()) {
|
||||
QString fname = "Makefile";
|
||||
if(!project->isEmpty("MAKEFILE"))
|
||||
fname = project->first("MAKEFILE").toQString();
|
||||
file.setFileName(outdir + fname);
|
||||
}
|
||||
}
|
||||
if(QDir::isRelativePath(file.fileName())) {
|
||||
QString fname = Option::output_dir; //pwd when qmake was run
|
||||
if(!fname.endsWith("/"))
|
||||
fname += "/";
|
||||
fname += file.fileName();
|
||||
file.setFileName(fname);
|
||||
debug_msg(3, "asked to open output file '%s' in %s",
|
||||
qPrintable(file.fileName()), qPrintable(Option::output_dir));
|
||||
|
||||
if (file.fileName().isEmpty()) {
|
||||
file.setFileName(!project->isEmpty("MAKEFILE")
|
||||
? project->first("MAKEFILE").toQString() : "Makefile");
|
||||
}
|
||||
|
||||
file.setFileName(QDir(Option::output_dir).absoluteFilePath(file.fileName()));
|
||||
|
||||
if (!build.isEmpty())
|
||||
file.setFileName(file.fileName() + "." + build);
|
||||
|
||||
if (project->isEmpty("QMAKE_MAKEFILE"))
|
||||
project->values("QMAKE_MAKEFILE").append(file.fileName());
|
||||
|
||||
// Make required directories. Note that we do this based on the
|
||||
// filename, not Option::output_dir, as the filename may include
|
||||
// generator specific directories not included in output_dir.
|
||||
int slsh = file.fileName().lastIndexOf('/');
|
||||
if (slsh != -1)
|
||||
mkdir(file.fileName().left(slsh));
|
||||
if(file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
QFileInfo fi(fileInfo(Option::output.fileName()));
|
||||
QString od;
|
||||
if(fi.isSymLink())
|
||||
od = fileInfo(fi.readLink()).absolutePath();
|
||||
else
|
||||
od = fi.path();
|
||||
od = QDir::fromNativeSeparators(od);
|
||||
if(QDir::isRelativePath(od)) {
|
||||
QString dir = Option::output_dir;
|
||||
if (!dir.endsWith('/') && !od.isEmpty())
|
||||
dir += '/';
|
||||
od.prepend(dir);
|
||||
}
|
||||
Option::output_dir = od;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
debug_msg(3, "opening output file %s", qPrintable(file.fileName()));
|
||||
return file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
|
||||
}
|
||||
|
||||
QString
|
||||
|
@ -473,18 +473,11 @@ ProjectGenerator::getWritableVar(const char *vk, bool)
|
||||
bool
|
||||
ProjectGenerator::openOutput(QFile &file, const QString &build) const
|
||||
{
|
||||
QString outdir;
|
||||
if(!file.fileName().isEmpty()) {
|
||||
QFileInfo fi(fileInfo(file.fileName()));
|
||||
if(fi.isDir())
|
||||
outdir = fi.path() + QDir::separator();
|
||||
}
|
||||
if(!outdir.isEmpty() || file.fileName().isEmpty()) {
|
||||
QString dir = qmake_getpwd();
|
||||
int s = dir.lastIndexOf('/');
|
||||
if(s != -1)
|
||||
dir = dir.right(dir.length() - (s + 1));
|
||||
file.setFileName(outdir + dir + Option::pro_ext);
|
||||
ProString fileName = file.fileName();
|
||||
if (!fileName.endsWith(Option::pro_ext)) {
|
||||
if (fileName.isEmpty())
|
||||
fileName = fileInfo(Option::output_dir).fileName();
|
||||
file.setFileName(fileName + Option::pro_ext);
|
||||
}
|
||||
return MakefileGenerator::openOutput(file, build);
|
||||
}
|
||||
|
@ -1617,20 +1617,15 @@ QString VcprojGenerator::replaceExtraCompilerVariables(
|
||||
|
||||
bool VcprojGenerator::openOutput(QFile &file, const QString &/*build*/) const
|
||||
{
|
||||
QString outdir;
|
||||
if(!file.fileName().isEmpty()) {
|
||||
QFileInfo fi(fileInfo(file.fileName()));
|
||||
if(fi.isDir())
|
||||
outdir = file.fileName() + QDir::separator();
|
||||
ProString fileName = file.fileName();
|
||||
ProString extension = project->first("TEMPLATE") == "vcsubdirs"
|
||||
? project->first("VCSOLUTION_EXTENSION") : project->first("VCPROJ_EXTENSION");
|
||||
if (!fileName.endsWith(extension)) {
|
||||
if (fileName.isEmpty()) {
|
||||
fileName = !project->first("MAKEFILE").isEmpty()
|
||||
? project->first("MAKEFILE") : project->first("TARGET");
|
||||
}
|
||||
if(!outdir.isEmpty() || file.fileName().isEmpty()) {
|
||||
ProString ext = project->first("VCPROJ_EXTENSION");
|
||||
if(project->first("TEMPLATE") == "vcsubdirs")
|
||||
ext = project->first("VCSOLUTION_EXTENSION");
|
||||
ProString outputName = project->first("TARGET");
|
||||
if (!project->first("MAKEFILE").isEmpty())
|
||||
outputName = project->first("MAKEFILE");
|
||||
file.setFileName(outdir + outputName + ext);
|
||||
file.setFileName(fileName + extension);
|
||||
}
|
||||
return Win32MakefileGenerator::openOutput(file, QString());
|
||||
}
|
||||
|
@ -455,28 +455,22 @@ int runQMake(int argc, char **argv)
|
||||
QString oldpwd = qmake_getpwd();
|
||||
|
||||
Option::output_dir = oldpwd; //for now this is the output dir
|
||||
if(Option::output.fileName() != "-") {
|
||||
if (!Option::output.fileName().isEmpty() && Option::output.fileName() != "-") {
|
||||
// The output 'filename', as given by the -o option, might include one
|
||||
// or more directories, so we may need to rebase the output directory.
|
||||
QFileInfo fi(Option::output);
|
||||
QString dir;
|
||||
if(fi.isDir()) {
|
||||
dir = fi.filePath();
|
||||
} else {
|
||||
QString tmp_dir = fi.path();
|
||||
if(!tmp_dir.isEmpty() && QFile::exists(tmp_dir))
|
||||
dir = tmp_dir;
|
||||
|
||||
QDir dir(QDir::cleanPath(fi.isDir() ? fi.absoluteFilePath() : fi.absolutePath()));
|
||||
|
||||
// Don't treat Xcode project directory as part of OUT_PWD
|
||||
if (dir.dirName().endsWith(QLatin1String(".xcodeproj"))) {
|
||||
// Note: we're intentionally not using cdUp(), as the dir may not exist
|
||||
dir.setPath(QDir::cleanPath(dir.filePath("..")));
|
||||
}
|
||||
#ifdef Q_OS_MAC
|
||||
if (fi.fileName().endsWith(QLatin1String(".pbxproj"))
|
||||
&& dir.endsWith(QLatin1String(".xcodeproj")))
|
||||
dir += QStringLiteral("/..");
|
||||
#endif
|
||||
if(!dir.isNull() && dir != ".")
|
||||
Option::output_dir = dir;
|
||||
if (QDir::isRelativePath(Option::output_dir)) {
|
||||
Option::output.setFileName(fi.fileName());
|
||||
Option::output_dir.prepend(oldpwd + QLatin1Char('/'));
|
||||
}
|
||||
Option::output_dir = QDir::cleanPath(Option::output_dir);
|
||||
|
||||
Option::output_dir = dir.path();
|
||||
QString absoluteFilePath = QDir::cleanPath(fi.absoluteFilePath());
|
||||
Option::output.setFileName(absoluteFilePath.mid(Option::output_dir.length() + 1));
|
||||
}
|
||||
|
||||
QMakeProperty prop;
|
||||
|
Loading…
x
Reference in New Issue
Block a user