Commit d1bdfcc3 authored by Tobias Hunger's avatar Tobias Hunger

Integrate target support

 * Ease cross device development by introducing 'targets' which
   group build- and runsettings that are valid for this one target

 Most of the kudos for the code review go to dt. Con, thorbjorn,
 ckandler and others did also review parts of this patch.

Reviewed-by: dt
parent 8ee2521f
......@@ -31,6 +31,7 @@
#include "cmakeopenprojectwizard.h"
#include "cmakeproject.h"
#include "cmaketarget.h"
#include <projectexplorer/projectexplorerconstants.h>
#include <utils/qtcassert.h>
......@@ -46,25 +47,17 @@ const char * const CMAKE_BC_ID("CMakeProjectManager.CMakeBuildConfiguration");
const char * const USER_ENVIRONMENT_CHANGES_KEY("CMakeProjectManager.CMakeBuildConfiguration.UserEnvironmentChanges");
const char * const MSVC_VERSION_KEY("CMakeProjectManager.CMakeBuildConfiguration.MsvcVersion");
const char * const BUILD_DIRECTORY_KEY("CMakeProjectManager.CMakeBuildConfiguration.BuildDirectory");
} // namespace
}
CMakeBuildConfiguration::CMakeBuildConfiguration(CMakeProject *project) :
BuildConfiguration(project, QLatin1String(CMAKE_BC_ID)),
m_toolChain(0),
m_clearSystemEnvironment(false)
{
}
CMakeBuildConfiguration::CMakeBuildConfiguration(CMakeProject *project, const QString &id) :
BuildConfiguration(project, id),
CMakeBuildConfiguration::CMakeBuildConfiguration(CMakeTarget *parent) :
BuildConfiguration(parent, QLatin1String(CMAKE_BC_ID)),
m_toolChain(0),
m_clearSystemEnvironment(false)
{
}
CMakeBuildConfiguration::CMakeBuildConfiguration(CMakeProject *pro, CMakeBuildConfiguration *source) :
BuildConfiguration(pro, source),
CMakeBuildConfiguration::CMakeBuildConfiguration(CMakeTarget *parent, CMakeBuildConfiguration *source) :
BuildConfiguration(parent, source),
m_toolChain(0),
m_clearSystemEnvironment(source->m_clearSystemEnvironment),
m_userEnvironmentChanges(source->m_userEnvironmentChanges),
......@@ -97,9 +90,9 @@ CMakeBuildConfiguration::~CMakeBuildConfiguration()
delete m_toolChain;
}
CMakeProject *CMakeBuildConfiguration::cmakeProject() const
CMakeTarget *CMakeBuildConfiguration::cmakeTarget() const
{
return static_cast<CMakeProject *>(project());
return static_cast<CMakeTarget *>(target());
}
ProjectExplorer::Environment CMakeBuildConfiguration::baseEnvironment() const
......@@ -155,7 +148,7 @@ QString CMakeBuildConfiguration::buildDirectory() const
{
QString buildDirectory = m_buildDirectory;
if (buildDirectory.isEmpty())
buildDirectory = cmakeProject()->sourceDirectory() + "/qtcreator-build";
buildDirectory = cmakeTarget()->cmakeProject()->sourceDirectory() + "/qtcreator-build";
return buildDirectory;
}
......@@ -230,9 +223,9 @@ CMakeBuildConfigurationFactory::~CMakeBuildConfigurationFactory()
{
}
QStringList CMakeBuildConfigurationFactory::availableCreationIds(ProjectExplorer::Project *parent) const
QStringList CMakeBuildConfigurationFactory::availableCreationIds(ProjectExplorer::Target *parent) const
{
if (!qobject_cast<CMakeProject *>(parent))
if (!qobject_cast<CMakeTarget *>(parent))
return QStringList();
return QStringList() << QLatin1String(CMAKE_BC_ID);
}
......@@ -244,22 +237,22 @@ QString CMakeBuildConfigurationFactory::displayNameForId(const QString &id) cons
return QString();
}
bool CMakeBuildConfigurationFactory::canCreate(ProjectExplorer::Project *parent, const QString &id) const
bool CMakeBuildConfigurationFactory::canCreate(ProjectExplorer::Target *parent, const QString &id) const
{
if (!qobject_cast<CMakeProject *>(parent))
if (!qobject_cast<CMakeTarget *>(parent))
return false;
if (id == QLatin1String(CMAKE_BC_ID))
return true;
return false;
}
ProjectExplorer::BuildConfiguration *CMakeBuildConfigurationFactory::create(ProjectExplorer::Project *parent, const QString &id)
CMakeBuildConfiguration *CMakeBuildConfigurationFactory::create(ProjectExplorer::Target *parent, const QString &id)
{
if (!canCreate(parent, id))
return 0;
CMakeProject *cmProject = static_cast<CMakeProject *>(parent);
Q_ASSERT(cmProject);
CMakeTarget *cmtarget = static_cast<CMakeTarget *>(parent);
Q_ASSERT(cmtarget);
//TODO configuration name should be part of the cmakeopenprojectwizard
bool ok;
......@@ -271,7 +264,7 @@ ProjectExplorer::BuildConfiguration *CMakeBuildConfigurationFactory::create(Proj
&ok);
if (!ok || buildConfigurationName.isEmpty())
return false;
CMakeBuildConfiguration *bc = new CMakeBuildConfiguration(cmProject);
CMakeBuildConfiguration *bc = new CMakeBuildConfiguration(cmtarget);
bc->setDisplayName(buildConfigurationName);
MakeStep *makeStep = new MakeStep(bc);
......@@ -282,53 +275,53 @@ ProjectExplorer::BuildConfiguration *CMakeBuildConfigurationFactory::create(Proj
cleanMakeStep->setAdditionalArguments(QStringList() << "clean");
cleanMakeStep->setClean(true);
CMakeOpenProjectWizard copw(cmProject->projectManager(),
cmProject->sourceDirectory(),
CMakeOpenProjectWizard copw(cmtarget->cmakeProject()->projectManager(),
cmtarget->cmakeProject()->sourceDirectory(),
bc->buildDirectory(),
bc->environment());
if (copw.exec() != QDialog::Accepted) {
delete bc;
return false;
}
cmProject->addBuildConfiguration(bc); // this also makes the name unique
cmtarget->addBuildConfiguration(bc); // this also makes the name unique
bc->setBuildDirectory(copw.buildDirectory());
bc->setMsvcVersion(copw.msvcVersion());
cmProject->parseCMakeLists();
cmtarget->cmakeProject()->parseCMakeLists();
// Default to all
if (cmProject->hasBuildTarget("all"))
if (cmtarget->cmakeProject()->hasBuildTarget("all"))
makeStep->setBuildTarget("all", true);
return bc;
}
bool CMakeBuildConfigurationFactory::canClone(ProjectExplorer::Project *parent, ProjectExplorer::BuildConfiguration *source) const
bool CMakeBuildConfigurationFactory::canClone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source) const
{
return canCreate(parent, source->id());
}
ProjectExplorer::BuildConfiguration *CMakeBuildConfigurationFactory::clone(ProjectExplorer::Project *parent, ProjectExplorer::BuildConfiguration *source)
CMakeBuildConfiguration *CMakeBuildConfigurationFactory::clone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source)
{
if (!canClone(parent, source))
return 0;
CMakeBuildConfiguration *old = static_cast<CMakeBuildConfiguration *>(source);
CMakeProject *cmProject(static_cast<CMakeProject *>(parent));
return new CMakeBuildConfiguration(cmProject, old);
CMakeTarget *cmtarget(static_cast<CMakeTarget *>(parent));
return new CMakeBuildConfiguration(cmtarget, old);
}
bool CMakeBuildConfigurationFactory::canRestore(ProjectExplorer::Project *parent, const QVariantMap &map) const
bool CMakeBuildConfigurationFactory::canRestore(ProjectExplorer::Target *parent, const QVariantMap &map) const
{
QString id(ProjectExplorer::idFromMap(map));
return canCreate(parent, id);
}
ProjectExplorer::BuildConfiguration *CMakeBuildConfigurationFactory::restore(ProjectExplorer::Project *parent, const QVariantMap &map)
CMakeBuildConfiguration *CMakeBuildConfigurationFactory::restore(ProjectExplorer::Target *parent, const QVariantMap &map)
{
if (!canRestore(parent, map))
return 0;
CMakeProject *cmProject(static_cast<CMakeProject *>(parent));
CMakeBuildConfiguration *bc = new CMakeBuildConfiguration(cmProject);
CMakeTarget *cmtarget(static_cast<CMakeTarget *>(parent));
CMakeBuildConfiguration *bc = new CMakeBuildConfiguration(cmtarget);
if (bc->fromMap(map))
return bc;
delete bc;
......
......@@ -36,7 +36,7 @@
namespace CMakeProjectManager {
namespace Internal {
class CMakeProject;
class CMakeTarget;
class CMakeBuildConfigurationFactory;
class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
......@@ -45,10 +45,10 @@ class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
friend class CMakeBuildConfigurationFactory;
public:
CMakeBuildConfiguration(CMakeProject *pro);
CMakeBuildConfiguration(CMakeTarget *parent);
~CMakeBuildConfiguration();
CMakeProject *cmakeProject() const;
CMakeTarget *cmakeTarget() const;
ProjectExplorer::Environment environment() const;
ProjectExplorer::Environment baseEnvironment() const;
......@@ -74,8 +74,7 @@ signals:
void msvcVersionChanged();
protected:
CMakeBuildConfiguration(CMakeProject *pro, const QString &id);
CMakeBuildConfiguration(CMakeProject *pro, CMakeBuildConfiguration *source);
CMakeBuildConfiguration(CMakeTarget *parent, CMakeBuildConfiguration *source);
virtual bool fromMap(const QVariantMap &map);
private:
......@@ -95,15 +94,15 @@ public:
CMakeBuildConfigurationFactory(QObject *parent = 0);
~CMakeBuildConfigurationFactory();
QStringList availableCreationIds(ProjectExplorer::Project *project) const;
QStringList availableCreationIds(ProjectExplorer::Target *parent) const;
QString displayNameForId(const QString &id) const;
bool canCreate(ProjectExplorer::Project *parent, const QString &id) const;
ProjectExplorer::BuildConfiguration *create(ProjectExplorer::Project *parent, const QString &id);
bool canClone(ProjectExplorer::Project *parent, ProjectExplorer::BuildConfiguration *source) const;
ProjectExplorer::BuildConfiguration *clone(ProjectExplorer::Project *parent, ProjectExplorer::BuildConfiguration *source);
bool canRestore(ProjectExplorer::Project *parent, const QVariantMap &map) const;
ProjectExplorer::BuildConfiguration *restore(ProjectExplorer::Project *parent, const QVariantMap &map);
bool canCreate(ProjectExplorer::Target *parent, const QString &id) const;
CMakeBuildConfiguration *create(ProjectExplorer::Target *parent, const QString &id);
bool canClone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source) const;
CMakeBuildConfiguration *clone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source);
bool canRestore(ProjectExplorer::Target *parent, const QVariantMap &map) const;
CMakeBuildConfiguration *restore(ProjectExplorer::Target *parent, const QVariantMap &map);
};
} // namespace Internal
......
......@@ -31,6 +31,7 @@
#include "cmakeprojectconstants.h"
#include "cmakeprojectnodes.h"
#include "cmakerunconfiguration.h"
#include "cmaketarget.h"
#include "makestep.h"
#include "cmakeopenprojectwizard.h"
#include "cmakebuildenvironmentwidget.h"
......@@ -72,12 +73,14 @@ using ProjectExplorer::EnvironmentItem;
CMakeProject::CMakeProject(CMakeManager *manager, const QString &fileName)
: m_manager(manager),
m_fileName(fileName),
m_buildConfigurationFactory(new CMakeBuildConfigurationFactory(this)),
m_rootNode(new CMakeProjectNode(m_fileName)),
m_insideFileChanged(false),
m_lastActiveBuildConfiguration(0)
m_targetFactory(new CMakeTargetFactory(this))
{
m_file = new CMakeFile(this, fileName);
connect(this, SIGNAL(addedTarget(ProjectExplorer::Target*)),
SLOT(targetAdded(ProjectExplorer::Target*)));
}
CMakeProject::~CMakeProject()
......@@ -85,29 +88,34 @@ CMakeProject::~CMakeProject()
delete m_rootNode;
}
CMakeBuildConfiguration *CMakeProject::activeCMakeBuildConfiguration() const
void CMakeProject::fileChanged(const QString &fileName)
{
return static_cast<CMakeBuildConfiguration *>(activeBuildConfiguration());
}
Q_UNUSED(fileName)
if (!activeTarget() ||
!activeTarget()->activeBuildConfiguration())
return;
IBuildConfigurationFactory *CMakeProject::buildConfigurationFactory() const
{
return m_buildConfigurationFactory;
if (m_insideFileChanged)
return;
m_insideFileChanged = true;
changeActiveBuildConfiguration(activeTarget()->activeBuildConfiguration());
m_insideFileChanged = false;
}
void CMakeProject::slotActiveBuildConfiguration()
void CMakeProject::changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *bc)
{
if (m_lastActiveBuildConfiguration)
disconnect(m_lastActiveBuildConfiguration, SIGNAL(environmentChanged()),
this, SIGNAL(environmentChanged()));
CMakeTarget *target(qobject_cast<CMakeTarget *>(sender()));
if (!bc || !target || target != activeTarget())
return;
CMakeBuildConfiguration * cmakebc(qobject_cast<CMakeBuildConfiguration *>(bc));
if (!cmakebc)
return;
CMakeBuildConfiguration *activeBC = activeCMakeBuildConfiguration();
connect(activeBC, SIGNAL(environmentChanged()),
this, SIGNAL(environmentChanged()));
// Pop up a dialog asking the user to rerun cmake
QFileInfo sourceFileInfo(m_fileName);
QString cbpFile = CMakeManager::findCbpFile(QDir(activeBC->buildDirectory()));
QString cbpFile = CMakeManager::findCbpFile(QDir(bc->buildDirectory()));
QFileInfo cbpFileFi(cbpFile);
CMakeOpenProjectWizard::Mode mode = CMakeOpenProjectWizard::Nothing;
if (!cbpFileFi.exists()) {
......@@ -124,25 +132,23 @@ void CMakeProject::slotActiveBuildConfiguration()
if (mode != CMakeOpenProjectWizard::Nothing) {
CMakeOpenProjectWizard copw(m_manager,
sourceFileInfo.absolutePath(),
activeBC->buildDirectory(),
cmakebc->buildDirectory(),
mode,
activeBC->environment());
cmakebc->environment());
copw.exec();
activeBC->setMsvcVersion(copw.msvcVersion());
cmakebc->setMsvcVersion(copw.msvcVersion());
}
// reparse
parseCMakeLists();
emit environmentChanged();
}
void CMakeProject::fileChanged(const QString &fileName)
void CMakeProject::targetAdded(ProjectExplorer::Target *t)
{
Q_UNUSED(fileName)
if (m_insideFileChanged)
if (!t)
return;
m_insideFileChanged = true;
slotActiveBuildConfiguration();
m_insideFileChanged = false;
connect(t, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
SLOT(changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
}
void CMakeProject::changeBuildDirectory(CMakeBuildConfiguration *bc, const QString &newBuildDirectory)
......@@ -158,8 +164,12 @@ QString CMakeProject::sourceDirectory() const
bool CMakeProject::parseCMakeLists()
{
if (!activeTarget() ||
!activeTarget()->activeBuildConfiguration())
return false;
// Find cbp file
CMakeBuildConfiguration *activeBC = activeCMakeBuildConfiguration();
CMakeBuildConfiguration *activeBC = activeTarget()->activeBuildConfiguration();
QString cbpFile = CMakeManager::findCbpFile(activeBC->buildDirectory());
// setFolderName
......@@ -181,7 +191,6 @@ bool CMakeProject::parseCMakeLists()
m_rootNode->setFolderName(cbpparser.projectName());
//qDebug()<<"Building Tree";
QList<ProjectExplorer::FileNode *> fileList = cbpparser.fileList();
QSet<QString> projectFiles;
if (cbpparser.hasCMakeFiles()) {
......@@ -253,59 +262,15 @@ bool CMakeProject::parseCMakeLists()
}
}
// Create run configurations for m_targets
//qDebug()<<"Create run configurations of m_targets";
QMultiMap<QString, CMakeRunConfiguration* > existingRunConfigurations;
foreach(ProjectExplorer::RunConfiguration* cmakeRunConfiguration, runConfigurations()) {
if (CMakeRunConfiguration* rc = qobject_cast<CMakeRunConfiguration *>(cmakeRunConfiguration)) {
existingRunConfigurations.insert(rc->title(), rc);
}
}
bool setActive = existingRunConfigurations.isEmpty();
foreach(const CMakeBuildTarget &ct, m_buildTargets) {
if (ct.executable.isEmpty())
continue;
if (ct.title.endsWith(QLatin1String("/fast")))
continue;
QList<CMakeRunConfiguration *> list = existingRunConfigurations.values(ct.title);
if (!list.isEmpty()) {
// Already exists, so override the settings...
foreach (CMakeRunConfiguration *rc, list) {
//qDebug()<<"Updating Run Configuration with title"<<ct.title;
//qDebug()<<" Executable new:"<<ct.executable<< "old:"<<rc->executable();
//qDebug()<<" WD new:"<<ct.workingDirectory<<"old:"<<rc->workingDirectory();
rc->setExecutable(ct.executable);
rc->setWorkingDirectory(ct.workingDirectory);
}
existingRunConfigurations.remove(ct.title);
} else {
// Does not exist yet
//qDebug()<<"Adding new run configuration with title"<<ct.title;
//qDebug()<<" Executable:"<<ct.executable<<"WD:"<<ct.workingDirectory;
ProjectExplorer::RunConfiguration *rc(new CMakeRunConfiguration(this, ct.executable, ct.workingDirectory, ct.title));
addRunConfiguration(rc);
// The first one gets the honour of being the active one
if (setActive) {
setActiveRunConfiguration(rc);
setActive = false;
}
}
}
QMultiMap<QString, CMakeRunConfiguration *>::const_iterator it =
existingRunConfigurations.constBegin();
for( ; it != existingRunConfigurations.constEnd(); ++it) {
CMakeRunConfiguration *rc = it.value();
//qDebug()<<"Removing old RunConfiguration with title:"<<rc->title();
//qDebug()<<" Executable:"<<rc->executable()<<rc->workingDirectory();
removeRunConfiguration(rc);
}
//qDebug()<<"\n";
emit buildTargetsChanged();
return true;
}
QList<CMakeBuildTarget> CMakeProject::buildTargets() const
{
return m_buildTargets;
}
QStringList CMakeProject::buildTargetTitles() const
{
QStringList results;
......@@ -452,11 +417,21 @@ Core::IFile *CMakeProject::file() const
return m_file;
}
CMakeTargetFactory *CMakeProject::targetFactory() const
{
return m_targetFactory;
}
CMakeManager *CMakeProject::projectManager() const
{
return m_manager;
}
CMakeTarget *CMakeProject::activeTarget() const
{
return static_cast<CMakeTarget *>(Project::activeTarget());
}
QList<ProjectExplorer::Project *> CMakeProject::dependsOn()
{
return QList<Project *>();
......@@ -496,9 +471,15 @@ bool CMakeProject::fromMap(const QVariantMap &map)
if (!Project::fromMap(map))
return false;
bool hasUserFile = !buildConfigurations().isEmpty();
MakeStep *makeStep = 0;
bool hasUserFile = activeTarget() &&
activeTarget()->activeBuildConfiguration();
if (!hasUserFile) {
CMakeTarget *t(0);
if (!activeTarget())
t = new CMakeTarget(this);
else
t = activeTarget();
// Ask the user for where he wants to build it
// and the cmake command line
......@@ -506,29 +487,18 @@ bool CMakeProject::fromMap(const QVariantMap &map)
if (copw.exec() != QDialog::Accepted)
return false;
CMakeBuildConfiguration *bc = new CMakeBuildConfiguration(this);
bc->setDisplayName("all");
CMakeBuildConfiguration *bc =
static_cast<CMakeBuildConfiguration *>(t->buildConfigurations().at(0));
bc->setMsvcVersion(copw.msvcVersion());
if (!copw.buildDirectory().isEmpty())
bc->setBuildDirectory(copw.buildDirectory());
// Now create a standard build configuration
makeStep = new MakeStep(bc);
bc->insertBuildStep(0, makeStep);
//TODO save arguments somewhere copw.arguments()
MakeStep *cleanMakeStep = new MakeStep(bc);
bc->insertCleanStep(0, cleanMakeStep);
cleanMakeStep->setAdditionalArguments(QStringList() << "clean");
cleanMakeStep->setClean(true);
addBuildConfiguration(bc);
setActiveBuildConfiguration(bc);
addTarget(t);
} else {
// We have a user file, but we could still be missing the cbp file
// or simply run createXml with the saved settings
QFileInfo sourceFileInfo(m_fileName);
CMakeBuildConfiguration *activeBC = activeCMakeBuildConfiguration();
CMakeBuildConfiguration *activeBC = activeTarget()->activeBuildConfiguration();
QString cbpFile = CMakeManager::findCbpFile(QDir(activeBC->buildDirectory()));
QFileInfo cbpFileFi(cbpFile);
......@@ -552,20 +522,22 @@ bool CMakeProject::fromMap(const QVariantMap &map)
m_watcher = new ProjectExplorer::FileWatcher(this);
connect(m_watcher, SIGNAL(fileChanged(QString)), this, SLOT(fileChanged(QString)));
bool result = parseCMakeLists(); // Gets the directory from the active buildconfiguration
if (!result)
if (!parseCMakeLists()) // Gets the directory from the active buildconfiguration
return false;
if (!hasUserFile && hasBuildTarget("all"))
if (!hasUserFile && hasBuildTarget("all")) {
MakeStep *makeStep(qobject_cast<MakeStep *>(activeTarget()->activeBuildConfiguration()->buildSteps().at(0)));
Q_ASSERT(makeStep);
makeStep->setBuildTarget("all", true);
}
m_lastActiveBuildConfiguration = activeCMakeBuildConfiguration();
if (m_lastActiveBuildConfiguration)
connect(m_lastActiveBuildConfiguration, SIGNAL(environmentChanged()),
this, SIGNAL(environmentChanged()));
connect(this, SIGNAL(activeBuildConfigurationChanged()),
this, SLOT(slotActiveBuildConfiguration()));
foreach (Target *t, targets()) {
connect(t, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
this, SLOT(changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
connect(t, SIGNAL(environmentChanged()),
this, SLOT(changeEnvironment()));
}
return true;
}
......
......@@ -33,6 +33,7 @@
#include "cmakeprojectmanager.h"
#include "cmakeprojectnodes.h"
#include "cmakebuildconfiguration.h"
#include "cmaketarget.h"
#include "makestep.h"
#include <projectexplorer/project.h>
......@@ -72,14 +73,14 @@ public:
CMakeProject(CMakeManager *manager, const QString &filename);
~CMakeProject();
CMakeBuildConfiguration *activeCMakeBuildConfiguration() const;
QString displayName() const;
QString id() const;
Core::IFile *file() const;
ProjectExplorer::IBuildConfigurationFactory *buildConfigurationFactory() const;
CMakeTargetFactory *targetFactory() const;
CMakeManager *projectManager() const;