Commit cd27fdec authored by dt's avatar dt
Browse files

Parse the Makefile in the importing case a lot better

We add each command line argument to the Additional Arguments
parent ecfb6eaf
......@@ -62,8 +62,10 @@ ProjectLoadWizard::ProjectLoadWizard(Qt4Project *project, QWidget *parent, Qt::W
m_temporaryVersion = true;
}
m_importBuildConfig = m_importVersion->defaultBuildConfig();
m_importBuildConfig= QtVersionManager::scanMakefileForQmakeConfig(directory, m_importBuildConfig);
QPair<QtVersion::QmakeBuildConfig, QStringList> result =
QtVersionManager::scanMakeFile(directory, m_importVersion->defaultBuildConfig());
m_importBuildConfig = result.first;
m_additionalArguments = result.second;
}
// So now we have the version and the configuration for that version
......@@ -73,7 +75,7 @@ ProjectLoadWizard::ProjectLoadWizard(Qt4Project *project, QWidget *parent, Qt::W
// Also if the qt version is not yet in the Tools Options dialog we offer to add it there
if (m_importVersion)
setupImportPage(m_importVersion, m_importBuildConfig);
setupImportPage(m_importVersion, m_importBuildConfig, m_additionalArguments);
setOptions(options() | QWizard::NoCancelButton | QWizard::NoBackButtonOnLastPage);
}
......@@ -93,8 +95,9 @@ ProjectLoadWizard::~ProjectLoadWizard()
}
void ProjectLoadWizard::addBuildConfiguration(QString buildConfigurationName, QtVersion *qtversion, QtVersion::QmakeBuildConfig qmakeBuildConfiguration)
void ProjectLoadWizard::addBuildConfiguration(QString buildConfigurationName, QtVersion *qtversion, QtVersion::QmakeBuildConfig qmakeBuildConfiguration, QStringList additionalArguments)
{
QMakeStep *qmakeStep = m_project->qmakeStep();
MakeStep *makeStep = m_project->makeStep();
bool debug = qmakeBuildConfiguration & QtVersion::DebugBuild;
......@@ -109,6 +112,7 @@ void ProjectLoadWizard::addBuildConfiguration(QString buildConfigurationName, Qt
// Add the buildconfiguration
m_project->addBuildConfiguration(buildConfigurationName);
qmakeStep->setValue(buildConfigurationName, "qmakeArgs", additionalArguments);
// set some options for qmake and make
if (qmakeBuildConfiguration & QtVersion::BuildAll) // debug_and_release => explicit targets
makeStep->setValue(buildConfigurationName, "makeargs", QStringList() << (debug ? "debug" : "release"));
......@@ -139,7 +143,7 @@ void ProjectLoadWizard::done(int result)
// qDebug()<<"Creating m_buildconfiguration entry from imported stuff";
// qDebug()<<((m_importBuildConfig& QtVersion::BuildAll)? "debug_and_release" : "")<<((m_importBuildConfig & QtVersion::DebugBuild)? "debug" : "release");
bool debug = m_importBuildConfig & QtVersion::DebugBuild;
addBuildConfiguration(debug ? "Debug" : "Release", m_importVersion, m_importBuildConfig);
addBuildConfiguration(debug ? "Debug" : "Release", m_importVersion, m_importBuildConfig, m_additionalArguments);
if (m_importBuildConfig & QtVersion::BuildAll) {
// Also create the other configuration
......@@ -149,7 +153,7 @@ void ProjectLoadWizard::done(int result)
else
otherBuildConfiguration = QtVersion::QmakeBuildConfig(otherBuildConfiguration | QtVersion::DebugBuild);
addBuildConfiguration(debug ? "Release" : "Debug", m_importVersion, otherBuildConfiguration);
addBuildConfiguration(debug ? "Release" : "Debug", m_importVersion, otherBuildConfiguration, m_additionalArguments);
}
} else {
// Not importing
......@@ -161,11 +165,11 @@ void ProjectLoadWizard::done(int result)
if (defaultVersion && defaultVersion->isValid() && (defaultVersion->defaultBuildConfig() & QtVersion::BuildAll))
buildAll = true;
if (buildAll) {
addBuildConfiguration("Debug", 0, QtVersion::QmakeBuildConfig(QtVersion::BuildAll | QtVersion::DebugBuild));
addBuildConfiguration("Release", 0, QtVersion::BuildAll);
addBuildConfiguration("Debug", 0, QtVersion::QmakeBuildConfig(QtVersion::BuildAll | QtVersion::DebugBuild), m_additionalArguments);
addBuildConfiguration("Release", 0, QtVersion::BuildAll, m_additionalArguments);
} else {
addBuildConfiguration("Debug", 0, QtVersion::DebugBuild);
addBuildConfiguration("Release", 0, QtVersion::QmakeBuildConfig(0));
addBuildConfiguration("Debug", 0, QtVersion::DebugBuild, m_additionalArguments);
addBuildConfiguration("Release", 0, QtVersion::QmakeBuildConfig(0), m_additionalArguments);
}
}
......@@ -179,7 +183,7 @@ int ProjectLoadWizard::nextId() const
return -1;
}
void ProjectLoadWizard::setupImportPage(QtVersion *version, QtVersion::QmakeBuildConfig buildConfig)
void ProjectLoadWizard::setupImportPage(QtVersion *version, QtVersion::QmakeBuildConfig buildConfig, QStringList addtionalArguments)
{
resize(605, 490);
// Import Page
......@@ -194,9 +198,11 @@ void ProjectLoadWizard::setupImportPage(QtVersion *version, QtVersion::QmakeBuil
importLabel->setTextFormat(Qt::RichText);
importLabel->setText(tr("Qt Creator has found an already existing build in the source directory.<br><br>"
"<b>Qt Version:</b> %1<br>"
"<b>Build configuration:</b> %2<br>")
"<b>Build configuration:</b> %2<br>"
"<b>Additional QMake Arguments:</b>%3")
.arg(versionString)
.arg(buildConfigString));
.arg(buildConfigString)
.arg(ProjectExplorer::Environment::joinArgumentList(addtionalArguments)));
importLayout->addWidget(importLabel);
......
......@@ -57,14 +57,15 @@ public:
void execDialog();
private:
void addBuildConfiguration(QString name, QtVersion *qtversion, QtVersion::QmakeBuildConfig buildConfiguration);
void setupImportPage(QtVersion *version, QtVersion::QmakeBuildConfig buildConfig);
void addBuildConfiguration(QString name, QtVersion *qtversion, QtVersion::QmakeBuildConfig buildConfiguration, QStringList additionalArguments);
void setupImportPage(QtVersion *version, QtVersion::QmakeBuildConfig buildConfig, QStringList addtionalArguments);
Qt4Project *m_project;
// Only used for imported stuff
QtVersion *m_importVersion;
QtVersion::QmakeBuildConfig m_importBuildConfig;
QStringList m_additionalArguments;
// Those that we might add
bool m_temporaryVersion;
......
......@@ -722,11 +722,7 @@ void Qt4Project::addDefaultBuild()
wizard.execDialog();
} else {
// Migrate settings
QMakeStep *qs = 0;
foreach(BuildStep *bs, buildSteps())
if ( (qs = qobject_cast<QMakeStep *>(bs)) != 0)
break;
QMakeStep *qs = qmakeStep();
foreach (const QString &buildConfiguration, buildConfigurations()) {
QVariant v = qs->value(buildConfiguration, "buildConfiguration");
if (v.isValid()) {
......@@ -1044,6 +1040,15 @@ void Qt4Project::proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *nod
}
}
QMakeStep *Qt4Project::qmakeStep() const
{
QMakeStep *qs = 0;
foreach(BuildStep *bs, buildSteps())
if ((qs = qobject_cast<QMakeStep *>(bs)) != 0)
return qs;
return 0;
}
MakeStep *Qt4Project::makeStep() const
{
MakeStep *qs = 0;
......
......@@ -179,6 +179,7 @@ public:
// That is generally the stuff that is asked should normally be transfered to
// Qt4Project *
// So that we can later enable people to build qt4projects the way they would like
QMakeStep *qmakeStep() const;
MakeStep *makeStep() const;
void notifyChanged(const QString &name);
......
......@@ -227,14 +227,18 @@ void Qt4ProjectConfigWidget::importLabelClicked()
version = new QtVersion(QFileInfo(qtPath).baseName(), qtPath);
vm->addVersion(version);
}
QtVersion::QmakeBuildConfig qmakeBuildConfig = version->defaultBuildConfig();
qmakeBuildConfig = QtVersionManager::scanMakefileForQmakeConfig(directory, qmakeBuildConfig);
QPair<QtVersion::QmakeBuildConfig, QStringList> result =
QtVersionManager::scanMakeFile(directory, version->defaultBuildConfig());
QtVersion::QmakeBuildConfig qmakeBuildConfig = result.first;
QStringList additionalArguments = result.second;
// So we got all the information now apply it...
m_pro->setQtVersion(m_buildConfiguration, version->uniqueId());
// Combo box will be updated at the end
// Find qmakestep...
QMakeStep *qmakeStep = m_pro->qmakeStep();
qmakeStep->setValue(m_buildConfiguration, "qmakeArgs", additionalArguments);
MakeStep *makeStep = m_pro->makeStep();
m_pro->setValue(m_buildConfiguration, "buildConfiguration", int(qmakeBuildConfig));
......
......@@ -256,10 +256,7 @@ void Qt4Manager::runQMakeContextMenu()
void Qt4Manager::runQMake(ProjectExplorer::Project *p)
{
QMakeStep *qs = 0;
foreach(BuildStep *bs, p->buildSteps())
if ( (qs = qobject_cast<QMakeStep *>(bs)) != 0)
break;
QMakeStep *qs = qobject_cast<Qt4Project *>(p)->qmakeStep();
if (!qs)
return;
//found qmakeStep, now use it
......
......@@ -547,121 +547,194 @@ QtVersion *QtVersionManager::qtVersionForDirectory(const QString &directory)
return 0;
}
QtVersion::QmakeBuildConfig QtVersionManager::scanMakefileForQmakeConfig(const QString &directory, QtVersion::QmakeBuildConfig defaultBuildConfig)
void dumpQMakeAssignments(const QList<QMakeAssignment> &list)
{
bool debugScan = false;
foreach(QMakeAssignment qa, list) {
qDebug()<<qa.variable<<qa.op<<qa.value;
}
}
// New code
QPair<QtVersion::QmakeBuildConfig, QStringList> QtVersionManager::scanMakeFile(const QString &directory, QtVersion::QmakeBuildConfig defaultBuildConfig)
{
qDebug()<<"ScanMakeFile, the gory details:";
QtVersion::QmakeBuildConfig result = QtVersion::NoBuild;
QStringList result2;
QString line = findQMakeLine(directory);
if (!line.isEmpty()) {
qDebug()<<"Found line"<<line;
line = trimLine(line);
qDebug()<<"Trimmed to"<<line;
QStringList parts = splitLine(line);
qDebug()<<"Splitted into"<<parts;
QList<QMakeAssignment> assignments;
QList<QMakeAssignment> afterAssignments;
QStringList additionalArguments;
parseParts(parts, &assignments, &afterAssignments, &additionalArguments);
qDebug()<<"After parseParts";
dumpQMakeAssignments(assignments);
qDebug()<<"-after";
dumpQMakeAssignments(afterAssignments);
// Search in assignments for CONFIG(+=,-=,=)(debug,release,debug_and_release)
// Also remove them from the list
result = qmakeBuildConfigFromCmdArgs(&assignments, defaultBuildConfig);
qDebug()<<"After qmakeBuildConfigFromCmdArgs";
dumpQMakeAssignments(assignments);
result2.append(additionalArguments);
foreach(QMakeAssignment qa, assignments)
result2.append(qa.variable + qa.op + qa.value);
if (!afterAssignments.isEmpty()) {
result2.append("-after");
foreach(QMakeAssignment qa, afterAssignments)
result2.append(qa.variable + qa.op + qa.value);
}
}
// Dump the gathered information:
qDebug()<<"\n\nDumping information from scanMakeFile";
qDebug()<<"QMake CONFIG variable parsing";
qDebug()<<" "<< (result & QtVersion::NoBuild ? "No Build" : QString::number(int(result)));
qDebug()<<" "<< (result & QtVersion::DebugBuild ? "debug" : "release");
qDebug()<<" "<< (result & QtVersion::BuildAll ? "debug_and_release" : "no debug_and_release");
qDebug()<<"\nAddtional Arguments";
qDebug()<<result2;
qDebug()<<"\n\n";
return qMakePair(result, result2);
}
QString QtVersionManager::findQMakeLine(const QString &directory)
{
QFile makefile(directory + "/Makefile" );
if (makefile.exists() && makefile.open(QFile::ReadOnly)) {
QTextStream ts(&makefile);
while (!ts.atEnd()) {
QString line = ts.readLine();
if (line.startsWith("# Command:")) {
// if nothing is specified
result = defaultBuildConfig;
// Actually parsing that line is not trivial in the general case
// There might things like this
// # Command: /home/dteske/git/bqt-45/bin/qmake -unix CONFIG+=debug\ release CONFIG\ +=\ debug_and_release\ debug -o Makefile test.pro
// which sets debug_and_release and debug
// or something like this:
//[...] CONFIG+=debug\ release CONFIG\ +=\ debug_and_release\ debug CONFIG\ -=\ debug_and_release CONFIG\ -=\ debug -o Makefile test.pro
// which sets -build_all and release
// To parse that, we search for the first CONFIG, then look for " " which is not after a "\" or the end
// And then look at each config individually
// we then remove all "\ " with just " "
// += sets adding flags
// -= sets removing flags
// and then split the string after the =
// and go over each item separetly
// debug sets/removes the flag DebugBuild
// release removes/sets the flag DebugBuild
// debug_and_release sets/removes the flag BuildAll
int pos = line.indexOf("CONFIG");
if (pos != -1) {
// Chopped of anything that is not interesting
line = line.mid(pos);
line = line.trimmed();
if (debugScan)
qDebug()<<"chopping line :"<<line;
//Now chop into parts that are intresting
QStringList parts;
int lastpos = 0;
for (int i = 1; i < line.size(); ++i) {
if (line.at(i) == QLatin1Char(' ') && line.at(i-1) != QLatin1Char('\\')) {
// found a part
parts.append(line.mid(lastpos, i-lastpos));
if (debugScan)
qDebug()<<"part appended:"<<line.mid(lastpos, i-lastpos);
lastpos = i + 1; // Nex one starts after the space
}
}
parts.append(line.mid(lastpos));
if (debugScan)
qDebug()<<"part appended:"<<line.mid(lastpos);
foreach(const QString &part, parts) {
if (debugScan)
qDebug()<<"now interpreting part"<<part;
bool setFlags;
// Now try to understand each part for that we do a rather stupid approach, optimize it if you care
if (part.startsWith("CONFIG")) {
// Yep something interesting
if (part.indexOf("+=") != -1) {
setFlags = true;
} else if (part.indexOf("-=") != -1) {
setFlags = false;
} else {
setFlags = true;
if (debugScan)
qDebug()<<"This can never happen, except if we can't parse Makefiles...";
}
if (debugScan)
qDebug()<<"part has setFlags:"<<setFlags;
// now loop forward, looking for something that looks like debug, release or debug_and_release
for (int i = 0; i < part.size(); ++i) {
int left = part.size() - i;
if (left >= 17 && QStringRef(&part, i, 17) == "debug_and_release") {
if (setFlags)
result = QtVersion::QmakeBuildConfig(result | QtVersion::BuildAll);
else
result = QtVersion::QmakeBuildConfig(result & ~QtVersion::BuildAll);
if (debugScan)
qDebug()<<"found debug_and_release new value"<<result;
i += 17;
} else if (left >=7 && QStringRef(&part, i, 7) == "release") {
if (setFlags)
result = QtVersion::QmakeBuildConfig(result & ~QtVersion::DebugBuild);
else
result = QtVersion::QmakeBuildConfig(result | QtVersion::DebugBuild);
if (debugScan)
qDebug()<<"found release new value"<<result;
i += 7;
} else if (left >= 5 && QStringRef(&part, i, 5) == "debug") {
if (setFlags)
result = QtVersion::QmakeBuildConfig(result | QtVersion::DebugBuild);
else
result = QtVersion::QmakeBuildConfig(result & ~QtVersion::DebugBuild);
if (debugScan)
qDebug()<<"found debug new value"<<result;
i += 5;
}
}
}
}
if (line.startsWith("# Command:"))
return line;
}
}
return QString();
}
/// This function trims the "#Command /path/to/qmake" from the the line
QString QtVersionManager::trimLine(const QString line)
{
// Actually the first space after #Command: /path/to/qmake
int firstSpace = line.indexOf(" ", 11);
return line.mid(firstSpace).trimmed();
}
QStringList QtVersionManager::splitLine(const QString &line)
{
// Split on each " ", except on those which are escaped
// Also remove all escaping
bool escape = false;
QString currentWord;
QStringList results;
int length = line.length();
for (int i=0; i<length; ++i) {
if (escape) {
currentWord += line.at(i);
escape = false;
} else if (line.at(i) == ' ') {
results << currentWord;
currentWord.clear();
} else if (line.at(i) == '\\') {
escape = true;
} else {
currentWord += line.at(i);
}
}
return results;
}
void QtVersionManager::parseParts(const QStringList &parts, QList<QMakeAssignment> *assignments, QList<QMakeAssignment> *afterAssignments, QStringList *additionalArguments)
{
QRegExp regExp("([^\\s\\+-]*)\\s*(\\+=|=|-=|~=)(.*)");
bool after = false;
bool ignoreNext = false;
foreach (const QString &part, parts) {
if (ignoreNext) {
// Ignoring
ignoreNext = false;
} else if (part == "after") {
after = true;
} else if(part.contains('=')) {
if (regExp.exactMatch(part)) {
qDebug()<<regExp.cap(1)<<"|"<<regExp.cap(2)<<"|"<<regExp.cap(3);
QMakeAssignment qa;
qa.variable = regExp.cap(1);
qa.op = regExp.cap(2);
qa.value = regExp.cap(3).trimmed();
if (after)
afterAssignments->append(qa);
else
assignments->append(qa);
} else {
qDebug()<<"regexp did not match";
}
} else if (part == "-o") {
ignoreNext = true;
} else {
qDebug()<<"Not parsed"<<part;
additionalArguments->append(part);
}
}
#if defined(Q_OS_WIN32)
additionalArguments->removeAll("-win32");
#elif defined(Q_OS_MAC)
additionalArguments->removeAll("-macx");
#elif defined(Q_OS_QNX6)
additionalArguments->removeAll("-qnx6");
#else
additionalArguments->removeAll("-unix");
#endif
}
/// This function extracts all the CONFIG+=debug, CONFIG+=release
QtVersion::QmakeBuildConfig QtVersionManager::qmakeBuildConfigFromCmdArgs(QList<QMakeAssignment> *assignments, QtVersion::QmakeBuildConfig defaultBuildConfig)
{
QtVersion::QmakeBuildConfig result = defaultBuildConfig;
QList<QMakeAssignment> oldAssignments = *assignments;
assignments->clear();
foreach(QMakeAssignment qa, oldAssignments) {
if (qa.variable == "CONFIG") {
QStringList values = qa.value.split(' ');
QStringList newValues;
foreach(const QString &value, values) {
if (value == "debug") {
if (qa.op == "+=")
result = QtVersion::QmakeBuildConfig(result | QtVersion::DebugBuild);
else
result = QtVersion::QmakeBuildConfig(result & ~QtVersion::DebugBuild);
} else if (value == "release") {
if (qa.op == "+=")
result = QtVersion::QmakeBuildConfig(result & ~QtVersion::DebugBuild);
else
result = QtVersion::QmakeBuildConfig(result | QtVersion::DebugBuild);
} else if (value == "debug_and_release") {
if (qa.op == "+=")
result = QtVersion::QmakeBuildConfig(result | QtVersion::BuildAll);
else
result = QtVersion::QmakeBuildConfig(result & ~QtVersion::BuildAll);
} else {
newValues.append(value);
}
if (debugScan)
qDebug()<<"returning: "<<result;
if (debugScan)
qDebug()<<"buildall = "<<bool(result & QtVersion::BuildAll);
if (debugScan)
qDebug()<<"debug ="<<bool(result & QtVersion::DebugBuild);
QMakeAssignment newQA = qa;
newQA.value = newValues.join(" ");
if (!newValues.isEmpty())
assignments->append(newQA);
}
} else {
assignments->append(qa);
}
makefile.close();
}
return result;
}
......
......@@ -167,6 +167,13 @@ private:
mutable QString m_qmakeCXX;
};
struct QMakeAssignment
{
QString variable;
QString op;
QString value;
};
class QtVersionManager : public QObject
{
Q_OBJECT
......@@ -189,13 +196,18 @@ public:
void removeVersion(QtVersion *version);
// Static Methods
static QtVersion::QmakeBuildConfig scanMakefileForQmakeConfig(const QString &directory, QtVersion::QmakeBuildConfig defaultBuildConfig);
static QPair<QtVersion::QmakeBuildConfig, QStringList> scanMakeFile(const QString &directory, QtVersion::QmakeBuildConfig defaultBuildConfig);
static QString findQtVersionFromMakefile(const QString &directory);
signals:
void defaultQtVersionChanged();
void qtVersionsChanged();
void updatedExamples(const QString& examplesPath, const QString& demosPath);
private:
static QString findQMakeLine(const QString &directory);
static QString trimLine(const QString line);
static QStringList splitLine(const QString &line);
static void parseParts(const QStringList &parts, QList<QMakeAssignment> *assignments, QList<QMakeAssignment> *afterAssignments, QStringList *additionalArguments);
static QtVersion::QmakeBuildConfig qmakeBuildConfigFromCmdArgs(QList<QMakeAssignment> *assignments, QtVersion::QmakeBuildConfig defaultBuildConfig);
// Used by QtOptionsPage
void setNewQtVersions(QList<QtVersion *> newVersions, int newDefaultVersion);
// Used by QtVersion
......
......@@ -59,6 +59,9 @@ public:
void setVerbose(bool on); // Default is false
void setCumulative(bool on); // Default is true!
void setOutputDir(const QString &dir); // Default is empty
// -nocache, -cache, -spec, QMAKESPEC
// -set persistent value
void setUserConfigCmdArgs(const QStringList &addUserConfigCmdArgs, const QStringList &removeUserConfigCmdArgs);
void setParsePreAndPostFiles(bool on); // Default is true
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment