OSDN Git Service

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