OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qt4projectmanager / qt4buildconfiguration.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "qt4buildconfiguration.h"
34
35 #include "qt4project.h"
36 #include "qt4target.h"
37 #include "qt4projectmanagerconstants.h"
38 #include "qt4nodes.h"
39 #include "qmakestep.h"
40 #include "makestep.h"
41
42 #include <utils/qtcassert.h>
43 #include <utils/qtcprocess.h>
44 #include <limits>
45 #include <projectexplorer/buildsteplist.h>
46 #include <projectexplorer/projectexplorerconstants.h>
47 #include <projectexplorer/toolchainmanager.h>
48
49 #include <QtCore/QDebug>
50
51 #include <QtGui/QInputDialog>
52
53 using namespace Qt4ProjectManager;
54 using namespace Qt4ProjectManager::Internal;
55 using namespace ProjectExplorer;
56
57 namespace {
58 const char * const QT4_BC_ID_PREFIX("Qt4ProjectManager.Qt4BuildConfiguration.");
59 const char * const QT4_BC_ID("Qt4ProjectManager.Qt4BuildConfiguration");
60
61 const char * const USE_SHADOW_BUILD_KEY("Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild");
62 const char * const BUILD_DIRECTORY_KEY("Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory");
63 const char * const TOOLCHAIN_KEY("Qt4ProjectManager.Qt4BuildConfiguration.ToolChain");
64 const char * const BUILD_CONFIGURATION_KEY("Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration");
65 const char * const QT_VERSION_ID_KEY("Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId");
66
67 enum { debug = 0 };
68 }
69
70 Qt4BuildConfiguration::Qt4BuildConfiguration(Qt4BaseTarget *target) :
71     BuildConfiguration(target, QLatin1String(QT4_BC_ID)),
72     m_shadowBuild(true),
73     m_isEnabled(false),
74     m_qtVersionId(-1),
75     m_qmakeBuildConfiguration(0),
76     m_subNodeBuild(0)
77 {
78     ctor();
79 }
80
81 Qt4BuildConfiguration::Qt4BuildConfiguration(Qt4BaseTarget *target, const QString &id) :
82     BuildConfiguration(target, id),
83     m_shadowBuild(true),
84     m_isEnabled(false),
85     m_qtVersionId(-1),
86     m_qmakeBuildConfiguration(0),
87     m_subNodeBuild(0)
88 {
89     ctor();
90 }
91
92 Qt4BuildConfiguration::Qt4BuildConfiguration(Qt4BaseTarget *target, Qt4BuildConfiguration *source) :
93     BuildConfiguration(target, source),
94     m_shadowBuild(source->m_shadowBuild),
95     m_isEnabled(false),
96     m_buildDirectory(source->m_buildDirectory),
97     m_qtVersionId(source->m_qtVersionId),
98     m_qmakeBuildConfiguration(source->m_qmakeBuildConfiguration),
99     m_subNodeBuild(0) // temporary value, so not copied
100 {
101     cloneSteps(source);
102     ctor();
103 }
104
105 Qt4BuildConfiguration::~Qt4BuildConfiguration()
106 {
107 }
108
109 QVariantMap Qt4BuildConfiguration::toMap() const
110 {
111     QVariantMap map(BuildConfiguration::toMap());
112     map.insert(QLatin1String(USE_SHADOW_BUILD_KEY), m_shadowBuild);
113     map.insert(QLatin1String(BUILD_DIRECTORY_KEY), m_buildDirectory);
114     map.insert(QLatin1String(QT_VERSION_ID_KEY), m_qtVersionId);
115     map.insert(QLatin1String(TOOLCHAIN_KEY), toolChain() ? toolChain()->id() : QLatin1String("<UNSET>"));
116     map.insert(QLatin1String(BUILD_CONFIGURATION_KEY), int(m_qmakeBuildConfiguration));
117     return map;
118 }
119
120 static inline QString msgBuildConfigNotApplicable(const QString &d, const QtVersion *qtVersion,
121                                                   const Target *target)
122 {
123     return QString::fromLatin1("Warning: Buildconfiguration '%1' : Qt '%2' from %3 not supported by target '%4'").
124             arg(d, qtVersion->displayName(), qtVersion->qmakeCommand(), target->id());
125 }
126
127 bool Qt4BuildConfiguration::fromMap(const QVariantMap &map)
128 {
129     if (!BuildConfiguration::fromMap(map))
130         return false;
131
132     m_shadowBuild = map.value(QLatin1String(USE_SHADOW_BUILD_KEY), true).toBool();
133     m_buildDirectory = map.value(QLatin1String(BUILD_DIRECTORY_KEY), qt4Target()->defaultBuildDirectory()).toString();
134     m_qtVersionId = map.value(QLatin1String(QT_VERSION_ID_KEY)).toInt();
135     ProjectExplorer::ToolChain *tc = 0;
136     tc = ProjectExplorer::ToolChainManager::instance()->findToolChain(map.value(QLatin1String(TOOLCHAIN_KEY)).toString());
137     m_qmakeBuildConfiguration = QtVersion::QmakeBuildConfigs(map.value(QLatin1String(BUILD_CONFIGURATION_KEY)).toInt());
138
139     // Pick a Qt version if the default version is used:
140     // We assume that the default Qt version was used in earlier versions of Qt creator.
141     // Pick a Qt version that is supporting a desktop.
142     if (m_qtVersionId == 0) {
143         QList<QtVersion *> versions = QtVersionManager::instance()->versions();
144         foreach (QtVersion *v, versions) {
145             if (v->isValid() && v->supportsTargetId(QLatin1String(Constants::DESKTOP_TARGET_ID))) {
146                 m_qtVersionId = v->uniqueId();
147                 break;
148             }
149         }
150         if (m_qtVersionId == 0)
151             m_qtVersionId = versions.at(0)->uniqueId();
152     }
153
154     QtVersion *version = qtVersion();
155     if (!map.contains(QLatin1String("Qt4ProjectManager.Qt4BuildConfiguration.NeedsV0Update"))) { // we are not upgrading from pre-targets!
156         if (version->isValid() && !version->supportedTargetIds().contains(target()->id())) {
157             qWarning("%s", qPrintable(msgBuildConfigNotApplicable(displayName(), version, target())));
158             return false;
159         }
160     } else {
161         if (!version->isValid() || !version->supportedTargetIds().contains(target()->id())) {
162             qWarning("%s", qPrintable(msgBuildConfigNotApplicable(displayName(), version, target())));
163             return false;
164         }
165     }
166
167     if (version->isValid()) {
168         if (!tc)
169             tc = qt4Target()->preferredToolChain(this);
170         if (tc && qt4Target()->possibleToolChains(this).contains(tc))
171             setToolChain(tc);
172         m_shadowBuild = (m_shadowBuild && version->supportsShadowBuilds());
173     }
174
175     if (!toolChain()) {
176         if (version->isValid()) {
177             qWarning("Warning: No tool chain available for '%s' from %s used in '%s'.",
178                     qPrintable(version->displayName()), qPrintable(version->qmakeCommand()),
179                     qPrintable(target()->id()));
180         } else {
181             qWarning("Warning: No tool chain available for invalid Qt version used in '%s'.",
182                      qPrintable(target()->id()));
183         }
184         return false;
185     }
186
187     return true;
188 }
189
190 void Qt4BuildConfiguration::ctor()
191 {
192     m_buildDirectory = qt4Target()->defaultBuildDirectory();
193     if (m_buildDirectory == target()->project()->projectDirectory())
194         m_shadowBuild = false;
195
196     m_lastEmmitedBuildDirectory = buildDirectory();
197
198     connect(this, SIGNAL(environmentChanged()),
199             this, SLOT(emitBuildDirectoryChanged()));
200
201     QtVersionManager *vm = QtVersionManager::instance();
202     connect(vm, SIGNAL(qtVersionsChanged(QList<int>)),
203             this, SLOT(qtVersionsChanged(QList<int>)));
204 }
205
206 void Qt4BuildConfiguration::emitBuildDirectoryChanged()
207 {
208     if (buildDirectory() != m_lastEmmitedBuildDirectory) {
209         m_lastEmmitedBuildDirectory = buildDirectory();
210         emit buildDirectoryChanged();
211     }
212 }
213
214 void Qt4BuildConfiguration::pickValidQtVersion()
215 {
216     QList<QtVersion *> versions = QtVersionManager::instance()->versionsForTargetId(qt4Target()->id());
217     if (!versions.isEmpty())
218         setQtVersion(versions.at(0));
219     else
220         setQtVersion(QtVersionManager::instance()->emptyVersion());
221 }
222
223 Qt4BaseTarget *Qt4BuildConfiguration::qt4Target() const
224 {
225     return static_cast<Qt4BaseTarget *>(target());
226 }
227
228 Utils::Environment Qt4BuildConfiguration::baseEnvironment() const
229 {
230     Utils::Environment env = BuildConfiguration::baseEnvironment();
231     qtVersion()->addToEnvironment(env);
232
233     ToolChain *tc = toolChain();
234     if (tc)
235         tc->addToEnvironment(env);
236     return env;
237 }
238
239 /// returns the unexpanded build directory
240 QString Qt4BuildConfiguration::rawBuildDirectory() const
241 {
242     QString workingDirectory;
243     if (m_shadowBuild) {
244         if (!m_buildDirectory.isEmpty())
245             workingDirectory = m_buildDirectory;
246         else
247             workingDirectory = qt4Target()->defaultBuildDirectory();
248     }
249     if (workingDirectory.isEmpty())
250         workingDirectory = target()->project()->projectDirectory();
251     return workingDirectory;
252 }
253
254 /// returns the build directory
255 QString Qt4BuildConfiguration::buildDirectory() const
256 {
257     return QDir::cleanPath(environment().expandVariables(rawBuildDirectory()));
258 }
259
260 /// If only a sub tree should be build this function returns which sub node
261 /// should be build
262 /// \see Qt4BuildConfiguration::setSubNodeBuild
263 Qt4ProjectManager::Internal::Qt4ProFileNode *Qt4BuildConfiguration::subNodeBuild() const
264 {
265     return m_subNodeBuild;
266 }
267
268 /// A sub node build on builds a sub node of the project
269 /// That is triggered by a right click in the project explorer tree
270 /// The sub node to be build is set via this function immediately before
271 /// calling BuildManager::buildProject( BuildConfiguration * )
272 /// and reset immediately afterwards
273 /// That is m_subNodesBuild is set only temporarly
274 void Qt4BuildConfiguration::setSubNodeBuild(Qt4ProjectManager::Internal::Qt4ProFileNode *node)
275 {
276     m_subNodeBuild = node;
277 }
278
279 /// returns whether this is a shadow build configuration or not
280 /// note, even if shadowBuild() returns true, it might be using the
281 /// source directory as the shadow build directory, thus it
282 /// still is a in-source build
283 bool Qt4BuildConfiguration::shadowBuild() const
284 {
285     return m_shadowBuild;
286 }
287
288 /// returns the shadow build directory if set
289 /// \note buildDirectory() is probably the function you want to call
290 QString Qt4BuildConfiguration::shadowBuildDirectory() const
291 {
292     if (m_buildDirectory.isEmpty())
293         return qt4Target()->defaultBuildDirectory();
294     return m_buildDirectory;
295 }
296
297 void Qt4BuildConfiguration::setShadowBuildAndDirectory(bool shadowBuild, const QString &buildDirectory)
298 {
299     QtVersion *version = qtVersion();
300     QString directoryToSet = buildDirectory;
301     bool toSet = (shadowBuild && version->isValid() && version->supportsShadowBuilds());
302     if (m_shadowBuild == toSet && m_buildDirectory == directoryToSet)
303         return;
304
305     m_shadowBuild = toSet;
306     m_buildDirectory = directoryToSet;
307
308     emit environmentChanged();
309     emitBuildDirectoryChanged();
310     emit proFileEvaluateNeeded(this);
311 }
312
313 QString Qt4BuildConfiguration::makeCommand() const
314 {
315     ToolChain *tc = toolChain();
316     return tc ? tc->makeCommand() : "make";
317 }
318
319 static inline QString symbianMakeTarget(QtVersion::QmakeBuildConfigs buildConfig,
320                                         const QString &type)
321 {
322     QString rc = (buildConfig & QtVersion::DebugBuild) ?
323                  QLatin1String("debug-") : QLatin1String("release-");
324     rc += type;
325     return rc;
326 }
327
328 QString Qt4BuildConfiguration::defaultMakeTarget() const
329 {
330     ToolChain *tc = toolChain();
331     if (!tc || target()->id() != Constants::S60_DEVICE_TARGET_ID)
332         return QString();
333     const QtVersion::QmakeBuildConfigs buildConfig = qmakeBuildConfiguration();
334
335     return symbianMakeTarget(buildConfig, tc->defaultMakeTarget());
336 }
337
338 QString Qt4BuildConfiguration::makefile() const
339 {
340     return qt4Target()->qt4Project()->rootProjectNode()->makefile();
341 }
342
343 QtVersion *Qt4BuildConfiguration::qtVersion() const
344 {
345     QtVersionManager *vm = QtVersionManager::instance();
346     return vm->version(m_qtVersionId);
347 }
348
349 void Qt4BuildConfiguration::setQtVersion(QtVersion *version)
350 {
351     Q_ASSERT(version);
352
353     if (m_qtVersionId == version->uniqueId())
354         return;
355
356     m_qtVersionId = version->uniqueId();
357
358     if (!qt4Target()->possibleToolChains(this).contains(toolChain()))
359         setToolChain(qt4Target()->preferredToolChain(this));
360     m_shadowBuild = m_shadowBuild && qtVersion()->supportsShadowBuilds();
361
362     emit proFileEvaluateNeeded(this);
363     emit qtVersionChanged();
364     emit environmentChanged();
365     emitBuildDirectoryChanged();
366 }
367
368 void Qt4BuildConfiguration::setToolChain(ProjectExplorer::ToolChain *tc)
369 {
370     Q_ASSERT(qtVersion());
371     if (tc != 0 && !qt4Target()->possibleToolChains(this).contains(tc))
372         return;
373
374     BuildConfiguration::setToolChain(tc);
375
376     emit proFileEvaluateNeeded(this);
377     emit environmentChanged();
378     emitBuildDirectoryChanged();
379 }
380
381 QtVersion::QmakeBuildConfigs Qt4BuildConfiguration::qmakeBuildConfiguration() const
382 {
383     return m_qmakeBuildConfiguration;
384 }
385
386 void Qt4BuildConfiguration::setQMakeBuildConfiguration(QtVersion::QmakeBuildConfigs config)
387 {
388     if (m_qmakeBuildConfiguration == config)
389         return;
390     m_qmakeBuildConfiguration = config;
391
392     emit proFileEvaluateNeeded(this);
393     emit qmakeBuildConfigurationChanged();
394 }
395
396 void Qt4BuildConfiguration::emitProFileEvaluteNeeded()
397 {
398     emit proFileEvaluateNeeded(this);
399 }
400
401 void Qt4BuildConfiguration::emitQMakeBuildConfigurationChanged()
402 {
403     emit qmakeBuildConfigurationChanged();
404 }
405
406 void Qt4BuildConfiguration::emitBuildDirectoryInitialized()
407 {
408     emit buildDirectoryInitialized();
409 }
410
411 void Qt4BuildConfiguration::emitS60CreatesSmartInstallerChanged()
412 {
413     emit s60CreatesSmartInstallerChanged();
414 }
415
416
417 QStringList Qt4BuildConfiguration::configCommandLineArguments() const
418 {
419     QStringList result;
420     QtVersion::QmakeBuildConfigs defaultBuildConfiguration = qtVersion()->defaultBuildConfig();
421     QtVersion::QmakeBuildConfigs userBuildConfiguration = m_qmakeBuildConfiguration;
422     if ((defaultBuildConfiguration & QtVersion::BuildAll) && !(userBuildConfiguration & QtVersion::BuildAll))
423         result << "CONFIG-=debug_and_release";
424
425     if (!(defaultBuildConfiguration & QtVersion::BuildAll) && (userBuildConfiguration & QtVersion::BuildAll))
426         result << "CONFIG+=debug_and_release";
427     if ((defaultBuildConfiguration & QtVersion::DebugBuild)
428             && !(userBuildConfiguration & QtVersion::DebugBuild)
429             && !(userBuildConfiguration & QtVersion::BuildAll))
430         result << "CONFIG+=release";
431     if (!(defaultBuildConfiguration & QtVersion::DebugBuild)
432             && (userBuildConfiguration & QtVersion::DebugBuild)
433             && !(userBuildConfiguration & QtVersion::BuildAll))
434         result << "CONFIG+=debug";
435     return result;
436 }
437
438 QMakeStep *Qt4BuildConfiguration::qmakeStep() const
439 {
440     QMakeStep *qs = 0;
441     BuildStepList *bsl = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
442     Q_ASSERT(bsl);
443     for (int i = 0; i < bsl->count(); ++i)
444         if ((qs = qobject_cast<QMakeStep *>(bsl->at(i))) != 0)
445             return qs;
446     return 0;
447 }
448
449 MakeStep *Qt4BuildConfiguration::makeStep() const
450 {
451     MakeStep *ms = 0;
452     BuildStepList *bsl = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
453     Q_ASSERT(bsl);
454     for (int i = 0; i < bsl->count(); ++i)
455         if ((ms = qobject_cast<MakeStep *>(bsl->at(i))) != 0)
456             return ms;
457     return 0;
458 }
459
460 void Qt4BuildConfiguration::qtVersionsChanged(const QList<int> &changedVersions)
461 {
462     if (!changedVersions.contains(m_qtVersionId) ||
463         qtVersion()->isValid())
464         return;
465
466     pickValidQtVersion();
467 }
468
469 // returns true if both are equal
470 bool Qt4BuildConfiguration::compareToImportFrom(const QString &makefile)
471 {
472     QMakeStep *qs = qmakeStep();
473     if (QFileInfo(makefile).exists() && qs) {
474         QString qmakePath = QtVersionManager::findQMakeBinaryFromMakefile(makefile);
475         QtVersion *version = qtVersion();
476         if (version->qmakeCommand() == qmakePath) {
477             // same qtversion
478             QPair<QtVersion::QmakeBuildConfigs, QString> result =
479                     QtVersionManager::scanMakeFile(makefile, version->defaultBuildConfig());
480             if (qmakeBuildConfiguration() == result.first) {
481                 // The qmake Build Configuration are the same,
482                 // now compare arguments lists
483                 // we have to compare without the spec/platform cmd argument
484                 // and compare that on its own
485                 QString workingDirectory = QFileInfo(makefile).absolutePath();
486                 QString userArgs = qs->userArguments();
487                 QStringList actualArgs;
488                 QString actualSpec = extractSpecFromArguments(&userArgs, workingDirectory, version, &actualArgs);
489                 if (actualSpec.isEmpty()) {
490                     // Easy one: the user has chosen not to override the settings
491                     actualSpec = version->mkspec();
492                 }
493                 actualArgs += qs->moreArguments();
494
495                 QString qmakeArgs = result.second;
496                 QStringList parsedArgs;
497                 QString parsedSpec = extractSpecFromArguments(&qmakeArgs, workingDirectory, version, &parsedArgs);
498
499                 if (debug) {
500                     qDebug()<<"Actual args:"<<actualArgs;
501                     qDebug()<<"Parsed args:"<<parsedArgs;
502                     qDebug()<<"Actual spec:"<<actualSpec;
503                     qDebug()<<"Parsed spec:"<<parsedSpec;
504                 }
505
506                 // Comparing the sorted list is obviously wrong
507                 // Though haven written a more complete version
508                 // that managed had around 200 lines and yet faild
509                 // to be actually foolproof at all, I think it's
510                 // not feasible without actually taking the qmake
511                 // command line parsing code
512
513                 // Things, sorting gets wrong:
514                 // parameters to positional parameters matter
515                 //  e.g. -o -spec is different from -spec -o
516                 //       -o 1 -spec 2 is diffrent from -spec 1 -o 2
517                 // variable assignment order matters
518                 // variable assignment vs -after
519                 // -norecursive vs. recursive
520                 actualArgs.sort();
521                 parsedArgs.sort();
522                 if (actualArgs == parsedArgs) {
523                     // Specs match exactly
524                     if (actualSpec == parsedSpec)
525                         return true;
526                     // Actual spec is the default one
527 //                    qDebug()<<"AS vs VS"<<actualSpec<<version->mkspec();
528                     if ((actualSpec == version->mkspec() || actualSpec == "default")
529                         && (parsedSpec == version->mkspec() || parsedSpec == "default" || parsedSpec.isEmpty()))
530                         return true;
531                 }
532             } else if (debug) {
533                 qDebug()<<"different qmake buildconfigurations buildconfiguration:"<<qmakeBuildConfiguration()<<" Makefile:"<<result.first;
534             }
535         } else if (debug) {
536             qDebug()<<"diffrent qt versions, buildconfiguration:"<<version->qmakeCommand()<<" Makefile:"<<qmakePath;
537         }
538     }
539     return false;
540 }
541
542 void Qt4BuildConfiguration::removeQMLInspectorFromArguments(QString *args)
543 {
544     for (Utils::QtcProcess::ArgIterator ait(args); ait.next(); )
545         if (ait.value().contains(QLatin1String(Constants::QMAKEVAR_QMLJSDEBUGGER_PATH)))
546             ait.deleteArg();
547 }
548
549 QString Qt4BuildConfiguration::extractSpecFromArguments(QString *args,
550                                                         const QString &directory, const QtVersion *version,
551                                                         QStringList *outArgs)
552 {
553     QString parsedSpec;
554
555     bool ignoreNext = false;
556     bool nextIsSpec = false;
557     for (Utils::QtcProcess::ArgIterator ait(args); ait.next(); ) {
558         if (ignoreNext) {
559             ignoreNext = false;
560             ait.deleteArg();
561         } else if (nextIsSpec) {
562             nextIsSpec = false;
563             parsedSpec = QDir::cleanPath(ait.value());
564             ait.deleteArg();
565         } else if (ait.value() == QLatin1String("-spec") || ait.value() == QLatin1String("-platform")) {
566             nextIsSpec = true;
567             ait.deleteArg();
568         } else if (ait.value() == QLatin1String("-cache")) {
569             // We ignore -cache, because qmake contained a bug that it didn't
570             // mention the -cache in the Makefile.
571             // That means changing the -cache option in the additional arguments
572             // does not automatically rerun qmake. Alas, we could try more
573             // intelligent matching for -cache, but i guess people rarely
574             // do use that.
575             ignoreNext = true;
576             ait.deleteArg();
577         } else if (outArgs && ait.isSimple()) {
578             outArgs->append(ait.value());
579         }
580     }
581
582     if (parsedSpec.isEmpty())
583         return QString();
584
585     QString baseMkspecDir = version->versionInfo().value("QMAKE_MKSPECS");
586     if (baseMkspecDir.isEmpty())
587         baseMkspecDir = version->versionInfo().value("QT_INSTALL_DATA") + "/mkspecs";
588
589 #ifdef Q_OS_WIN
590     baseMkspecDir = baseMkspecDir.toLower();
591     parsedSpec = parsedSpec.toLower();
592 #endif
593     // if the path is relative it can be
594     // relative to the working directory (as found in the Makefiles)
595     // or relatively to the mkspec directory
596     // if it is the former we need to get the canonical form
597     // for the other one we don't need to do anything
598     if (QFileInfo(parsedSpec).isRelative()) {
599         if(QFileInfo(directory + QLatin1Char('/') + parsedSpec).exists()) {
600             parsedSpec = QDir::cleanPath(directory + QLatin1Char('/') + parsedSpec);
601 #ifdef Q_OS_WIN
602             parsedSpec = parsedSpec.toLower();
603 #endif
604         } else {
605             parsedSpec = baseMkspecDir + QLatin1Char('/') + parsedSpec;
606         }
607     }
608
609     QFileInfo f2(parsedSpec);
610     while (f2.isSymLink()) {
611         parsedSpec = f2.symLinkTarget();
612         f2.setFile(parsedSpec);
613     }
614
615     if (parsedSpec.startsWith(baseMkspecDir)) {
616         parsedSpec = parsedSpec.mid(baseMkspecDir.length() + 1);
617     } else {
618         QString sourceMkSpecPath = version->sourcePath() + "/mkspecs";
619         if (parsedSpec.startsWith(sourceMkSpecPath)) {
620             parsedSpec = parsedSpec.mid(sourceMkSpecPath.length() + 1);
621         }
622     }
623 #ifdef Q_OS_WIN
624     parsedSpec = parsedSpec.toLower();
625 #endif
626     return parsedSpec;
627 }
628
629 ProjectExplorer::IOutputParser *Qt4BuildConfiguration::createOutputParser() const
630 {
631     ToolChain *tc = toolChain();
632     if (tc)
633         return toolChain()->outputParser();
634     return 0;
635 }
636
637 bool Qt4BuildConfiguration::isEnabled() const
638 {
639     return m_isEnabled;
640 }
641
642 void Qt4BuildConfiguration::setEnabled(bool enabled)
643 {
644     if (m_isEnabled == enabled)
645         return;
646     m_isEnabled = enabled;
647     emit enabledChanged();
648 }
649
650 /*!
651   \class Qt4BuildConfigurationFactory
652 */
653
654 Qt4BuildConfigurationFactory::Qt4BuildConfigurationFactory(QObject *parent) :
655     ProjectExplorer::IBuildConfigurationFactory(parent)
656 {
657     update();
658
659     QtVersionManager *vm = QtVersionManager::instance();
660     connect(vm, SIGNAL(qtVersionsChanged(QList<int>)),
661             this, SLOT(update()));
662 }
663
664 Qt4BuildConfigurationFactory::~Qt4BuildConfigurationFactory()
665 {
666 }
667
668 void Qt4BuildConfigurationFactory::update()
669 {
670     m_versions.clear();
671     QtVersionManager *vm = QtVersionManager::instance();
672     foreach (const QtVersion *version, vm->versions()) {
673         if (version->isValid()) {
674             QString key = QString::fromLatin1(QT4_BC_ID_PREFIX)
675                     + QString::fromLatin1("Qt%1").arg(version->uniqueId());
676             VersionInfo info(tr("Using Qt Version \"%1\"").arg(version->displayName()), version->uniqueId());
677             m_versions.insert(key, info);
678         }
679     }
680     emit availableCreationIdsChanged();
681 }
682
683 QStringList Qt4BuildConfigurationFactory::availableCreationIds(ProjectExplorer::Target *parent) const
684 {
685     if (!qobject_cast<Qt4BaseTarget *>(parent))
686         return QStringList();
687
688     QStringList results;
689     QtVersionManager *vm = QtVersionManager::instance();
690     for (QMap<QString, VersionInfo>::const_iterator i = m_versions.constBegin();
691          i != m_versions.constEnd(); ++i) {
692         if (vm->version(i.value().versionId)->supportsTargetId(parent->id()))
693             results.append(i.key());
694     }
695     return results;
696 }
697
698 QString Qt4BuildConfigurationFactory::displayNameForId(const QString &id) const
699 {
700     if (!m_versions.contains(id))
701         return QString();
702     return m_versions.value(id).displayName;
703 }
704
705 bool Qt4BuildConfigurationFactory::canCreate(ProjectExplorer::Target *parent, const QString &id) const
706 {
707     if (!qobject_cast<Qt4BaseTarget *>(parent))
708         return false;
709     if (!m_versions.contains(id))
710         return false;
711     const VersionInfo &info = m_versions.value(id);
712     QtVersion *version = QtVersionManager::instance()->version(info.versionId);
713     if (!version ||
714         !version->supportsTargetId(parent->id()))
715         return false;
716     return true;
717 }
718
719 BuildConfiguration *Qt4BuildConfigurationFactory::create(ProjectExplorer::Target *parent, const QString &id)
720 {
721     if (!canCreate(parent, id))
722         return 0;
723
724     const VersionInfo &info = m_versions.value(id);
725     QtVersion *version = QtVersionManager::instance()->version(info.versionId);
726     Q_ASSERT(version);
727
728     Qt4BaseTarget *qt4Target = static_cast<Qt4BaseTarget *>(parent);
729
730     bool ok;
731     QString buildConfigurationName = QInputDialog::getText(0,
732                           tr("New Configuration"),
733                           tr("New configuration name:"),
734                           QLineEdit::Normal,
735                           version->displayName(),
736                           &ok);
737     buildConfigurationName = buildConfigurationName.trimmed();
738     if (!ok || buildConfigurationName.isEmpty())
739         return 0;
740
741     //: Debug build configuration. We recommend not translating it.
742     qt4Target->addQt4BuildConfiguration(tr("%1 Debug").arg(buildConfigurationName),
743                                         version,
744                                         (version->defaultBuildConfig() | QtVersion::DebugBuild),
745                                         QString(), QString());
746     BuildConfiguration *bc =
747     //: Release build configuration. We recommend not translating it.
748     qt4Target->addQt4BuildConfiguration(tr("%1 Release").arg(buildConfigurationName),
749                                         version,
750                                         (version->defaultBuildConfig() & ~QtVersion::DebugBuild),
751                                         QString(), QString());
752     return bc;
753 }
754
755 bool Qt4BuildConfigurationFactory::canClone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source) const
756 {
757     if (!qobject_cast<Qt4BaseTarget *>(parent))
758         return false;
759     Qt4BuildConfiguration *qt4bc(qobject_cast<Qt4BuildConfiguration *>(source));
760     if (!qt4bc)
761         return false;
762
763     QtVersion *version = qt4bc->qtVersion();
764     if (!version ||
765         !version->supportsTargetId(parent->id()))
766         return false;
767     return true;
768 }
769
770 BuildConfiguration *Qt4BuildConfigurationFactory::clone(Target *parent, BuildConfiguration *source)
771 {
772     if (!canClone(parent, source))
773         return 0;
774     Qt4BaseTarget *target = static_cast<Qt4BaseTarget *>(parent);
775     Qt4BuildConfiguration *oldbc(static_cast<Qt4BuildConfiguration *>(source));
776     return new Qt4BuildConfiguration(target, oldbc);
777 }
778
779 bool Qt4BuildConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const
780 {
781     QString id = ProjectExplorer::idFromMap(map);
782     if (!qobject_cast<Qt4BaseTarget *>(parent))
783         return false;
784     return id.startsWith(QLatin1String(QT4_BC_ID_PREFIX)) ||
785            id == QLatin1String(QT4_BC_ID);
786 }
787
788 BuildConfiguration *Qt4BuildConfigurationFactory::restore(Target *parent, const QVariantMap &map)
789 {
790     if (!canRestore(parent, map))
791         return 0;
792     Qt4BaseTarget *target = static_cast<Qt4BaseTarget *>(parent);
793     Qt4BuildConfiguration *bc = new Qt4BuildConfiguration(target);
794     if (bc->fromMap(map))
795         return bc;
796     delete bc;
797     return 0;
798 }
799
800 void Qt4BuildConfiguration::importFromBuildDirectory()
801 {
802     QString directory = buildDirectory();
803     if (!directory.isEmpty()) {
804         QString mkfile = directory;
805         if (makefile().isEmpty())
806             mkfile.append("/Makefile");
807         else
808             mkfile.append(makefile());
809
810         QString qmakePath = QtVersionManager::findQMakeBinaryFromMakefile(mkfile);
811         if (!qmakePath.isEmpty()) {
812             QtVersionManager *vm = QtVersionManager::instance();
813             QtVersion *version = vm->qtVersionForQMakeBinary(qmakePath);
814             if (!version) {
815                 version = new QtVersion(qmakePath);
816                 vm->addVersion(version);
817             }
818
819             QPair<QtVersion::QmakeBuildConfigs, QString> result =
820                     QtVersionManager::scanMakeFile(directory, version->defaultBuildConfig());
821             QtVersion::QmakeBuildConfigs qmakeBuildConfig = result.first;
822
823             QString aa = result.second;
824             QString parsedSpec = Qt4BuildConfiguration::extractSpecFromArguments(&aa, directory, version);
825             QString versionSpec = version->mkspec();
826             QString additionalArguments;
827             if (parsedSpec.isEmpty() || parsedSpec == versionSpec || parsedSpec == "default") {
828                 // using the default spec, don't modify additional arguments
829             } else {
830                 additionalArguments = "-spec " + Utils::QtcProcess::quoteArg(parsedSpec);
831             }
832             Utils::QtcProcess::addArgs(&additionalArguments, aa);
833
834             Qt4BuildConfiguration::removeQMLInspectorFromArguments(&additionalArguments);
835
836             // So we got all the information now apply it...
837             setQtVersion(version);
838
839             qmakeStep()->setUserArguments(additionalArguments);
840
841             setQMakeBuildConfiguration(qmakeBuildConfig);
842             // Adjust command line arguments, this is ugly as hell
843             // If we are switching to BuildAll we want "release" in there and no "debug"
844             // or "debug" in there and no "release"
845             // If we are switching to not BuildAl we want neither "release" nor "debug" in there
846             bool debug = qmakeBuildConfig & QtVersion::DebugBuild;
847             bool haveTag = !(qmakeBuildConfig & QtVersion::BuildAll);
848             QString makeCmdArguments = makeStep()->userArguments();
849             Utils::QtcProcess::ArgIterator ait(&makeCmdArguments);
850             while (ait.next()) {
851                 if (ait.value() == QLatin1String("debug")) {
852                     if (!haveTag && debug)
853                         haveTag = true;
854                     else
855                         ait.deleteArg();
856                 } else if (ait.value() == QLatin1String("release")) {
857                     if (!haveTag && !debug)
858                         haveTag = true;
859                     else
860                         ait.deleteArg();
861                 }
862             }
863             if (!haveTag)
864                 ait.appendArg(QLatin1String(debug ? "debug" : "release"));
865             makeStep()->setUserArguments(makeCmdArguments);
866         }
867     }
868 }
869
870 BuildConfiguration::BuildType Qt4BuildConfiguration::buildType() const
871 {
872     if (qmakeBuildConfiguration() & QtVersion::DebugBuild)
873         return Debug;
874     else
875         return Release;
876 }
877