diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp
index 68d3479050ec3be3a9edf90f6e4de93974e996d6..35769432c98e8ff97c2004719b3319406ba5c16f 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp
+++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp
@@ -193,6 +193,16 @@ QStringList QbsBuildConfiguration::changedFiles() const
     return m_changedFiles;
 }
 
+void QbsBuildConfiguration::setProducts(const QStringList &products)
+{
+    m_products = products;
+}
+
+QStringList QbsBuildConfiguration::products() const
+{
+    return m_products;
+}
+
 QbsBuildConfiguration *QbsBuildConfiguration::setup(ProjectExplorer::Target *t,
                                                     const QString &defaultDisplayName,
                                                     const QString &displayName,
diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h
index 8a0749c2259bdc2281bff7974346269ea0addd86..6304bf7adcc69267fb9b4c14b1be0d213b2c2320 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h
+++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h
@@ -73,6 +73,9 @@ public:
     void setChangedFiles(const QStringList &files);
     QStringList changedFiles() const;
 
+    void setProducts(const QStringList &products);
+    QStringList products() const;
+
 signals:
     void qbsConfigurationChanged();
 
@@ -96,6 +99,7 @@ private:
     bool m_parsingError;
     Utils::FileName m_buildDirectory;
     QStringList m_changedFiles;
+    QStringList m_products;
 
     friend class QbsBuildConfigurationFactory;
     friend class QbsBuildConfigurationWidget;
diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
index 93a5d304f7e7851b72801622416030063eb0e445..68d23c1c261b2a1428b957d95ae280f63257e941 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
+++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp
@@ -102,6 +102,7 @@ bool QbsBuildStep::init()
         m_parser->appendOutputParser(parser);
 
     m_changedFiles = bc->changedFiles();
+    m_products = bc->products();
 
     connect(m_parser, SIGNAL(addOutput(QString,ProjectExplorer::BuildStep::OutputFormat)),
             this, SIGNAL(addOutput(QString,ProjectExplorer::BuildStep::OutputFormat)));
@@ -119,7 +120,7 @@ void QbsBuildStep::run(QFutureInterface<bool> &fi)
     qbs::BuildOptions options(m_qbsBuildOptions);
     options.setChangedFiles(m_changedFiles);
 
-    m_job = pro->build(options);
+    m_job = pro->build(options, m_products);
 
     if (!m_job) {
         m_fi->reportResult(false);
diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.h b/src/plugins/qbsprojectmanager/qbsbuildstep.h
index a916b9d91cb685270e105b3e9d2787216b4f4517..433d2478b19cb20899a331b0b1201bd83d4a54e1 100644
--- a/src/plugins/qbsprojectmanager/qbsbuildstep.h
+++ b/src/plugins/qbsprojectmanager/qbsbuildstep.h
@@ -96,6 +96,7 @@ private:
     QVariantMap m_qbsConfiguration;
     qbs::BuildOptions m_qbsBuildOptions;
     QStringList m_changedFiles;
+    QStringList m_products;
 
     QFutureInterface<bool> *m_fi;
     qbs::BuildJob *m_job;
diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp
index 6fc2f8519071fc9e2f76d3422d7620696c5c4034..2ff1460bb22cd59b88f88bb600989204dcb5b157 100644
--- a/src/plugins/qbsprojectmanager/qbsproject.cpp
+++ b/src/plugins/qbsprojectmanager/qbsproject.cpp
@@ -179,11 +179,29 @@ void QbsProject::invalidate()
     prepareForParsing();
 }
 
-qbs::BuildJob *QbsProject::build(const qbs::BuildOptions &opts)
+qbs::BuildJob *QbsProject::build(const qbs::BuildOptions &opts, QStringList productNames)
 {
     if (!qbsProject() || isParsing())
         return 0;
-    return qbsProject()->buildAllProducts(opts);
+    if (productNames.isEmpty()) {
+        return qbsProject()->buildAllProducts(opts);
+    } else {
+        QList<qbs::ProductData> products;
+        foreach (const QString &productName, productNames) {
+            bool found = false;
+            foreach (const qbs::ProductData &data, qbsProjectData()->products()) {
+                if (data.name() == productName) {
+                    found = true;
+                    products.append(data);
+                    break;
+                }
+            }
+            if (!found)
+                return 0;
+        }
+
+        return qbsProject()->buildSomeProducts(products, opts);
+    }
 }
 
 qbs::CleanJob *QbsProject::clean(const qbs::CleanOptions &opts)
diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h
index 823f5fbb355c05a8233e3c4d13a98504a22b48ea..49419e004c57a7cbc52e6022ad5dcb11e2054c81 100644
--- a/src/plugins/qbsprojectmanager/qbsproject.h
+++ b/src/plugins/qbsprojectmanager/qbsproject.h
@@ -79,7 +79,7 @@ public:
 
     QStringList files(FilesMode fileMode) const;
 
-    qbs::BuildJob *build(const qbs::BuildOptions &opts);
+    qbs::BuildJob *build(const qbs::BuildOptions &opts, QStringList products = QStringList());
     qbs::CleanJob *clean(const qbs::CleanOptions &opts);
     qbs::InstallJob *install(const qbs::InstallOptions &opts);
 
diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h b/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h
index 6d7428f1ab58d39d949867591670175d621dec2b..32e8f7962a7d78d8f75c73ea93e60951c5665998 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h
+++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h
@@ -49,6 +49,8 @@ const char ACTION_REPARSE_QBS[] = "Qbs.Reparse";
 const char ACTION_REPARSE_QBS_CONTEXT[] = "Qbs.ReparseCtx";
 const char ACTION_BUILD_FILE_CONTEXT[] = "Qbs.BuildFileCtx";
 const char ACTION_BUILD_FILE[] = "Qbs.BuildFile";
+const char ACTION_BUILD_PRODUCT_CONTEXT[] = "Qbs.BuildProductCtx";
+const char ACTION_BUILD_PRODUCT[] = "Qbs.BuildProduct";
 
 // Ids:
 const char QBS_BUILDSTEP_ID[] = "Qbs.BuildStep";
diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
index 1453d18a0026b2c074a4ade55c274e520eedde01..d6ea41010012cfba3523076ac1da2f7ae322a3db 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
+++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
@@ -77,6 +77,7 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString *
     m_manager = new QbsManager(this);
     m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
     const Core::Context projectContext(::QbsProjectManager::Constants::PROJECT_ID);
+    const Core::Context globalcontext(Core::Constants::C_GLOBAL);
 
     Q_UNUSED(arguments);
 
@@ -100,10 +101,8 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString *
     // PE Context menu for projects
     Core::ActionContainer *mproject =
             Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_PROJECTCONTEXT);
-    // <debug>
-    // Core::ActionContainer *msubproject =
-    //         Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_SUBPROJECTCONTEXT);
-    // </debug>
+    Core::ActionContainer *msubproject =
+             Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_SUBPROJECTCONTEXT);
     Core::ActionContainer *mfile =
             Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_FILECONTEXT);
 
@@ -129,7 +128,6 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString *
     mfile->addAction(command, ProjectExplorer::Constants::G_FILE_OTHER);
     connect(m_buildFileContextMenu, SIGNAL(triggered()), this, SLOT(buildFileContextMenu()));
 
-    const Core::Context globalcontext(Core::Constants::C_GLOBAL);
     m_buildFile = new Utils::ParameterAction(tr("Build File"), tr("Build File \"%1\""),
                                                    Utils::ParameterAction::AlwaysEnabled, this);
     command = Core::ActionManager::registerAction(m_buildFile, Constants::ACTION_BUILD_FILE, globalcontext);
@@ -140,6 +138,22 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString *
     mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
     connect(m_buildFile, SIGNAL(triggered()), this, SLOT(buildFile()));
 
+    m_buildProductContextMenu = new QAction(tr("Build"), this);
+    command = Core::ActionManager::registerAction(m_buildProductContextMenu, Constants::ACTION_BUILD_PRODUCT_CONTEXT, projectContext);
+    command->setAttribute(Core::Command::CA_Hide);
+    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
+    connect(m_buildProductContextMenu, SIGNAL(triggered()), this, SLOT(buildProductContextMenu()));
+
+    m_buildProduct = new Utils::ParameterAction(tr("Build Product"), tr("Build Product \"%1\""),
+                                                Utils::ParameterAction::AlwaysEnabled, this);
+    command = Core::ActionManager::registerAction(m_buildProduct, Constants::ACTION_BUILD_PRODUCT, globalcontext);
+    command->setAttribute(Core::Command::CA_Hide);
+    command->setAttribute(Core::Command::CA_UpdateText);
+    command->setDescription(m_buildFile->text());
+    command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Shift+B")));
+    mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
+    connect(m_buildProduct, SIGNAL(triggered()), this, SLOT(buildProduct()));
+
     // Connect
     connect(m_projectExplorer, SIGNAL(currentNodeChanged(ProjectExplorer::Node*,ProjectExplorer::Project*)),
             this, SLOT(updateContextActions(ProjectExplorer::Node*,ProjectExplorer::Project*)));
@@ -148,12 +162,12 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString *
             this, SLOT(buildStateChanged(ProjectExplorer::Project*)));
 
     connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
-            this, SLOT(updateBuildFileAction()));
+            this, SLOT(updateBuildActions()));
 
     // Run initial setup routines
     updateContextActions(0, 0);
     updateReparseQbsAction();
-    updateBuildFileAction();
+    updateBuildActions();
 
     return true;
 }
@@ -187,10 +201,12 @@ void QbsProjectManagerPlugin::updateContextActions(ProjectExplorer::Node *node,
 
     bool isBuilding = m_projectExplorer->buildManager()->isBuilding(project);
     bool isFile = m_currentProject && node && (node->nodeType() == ProjectExplorer::FileNodeType);
+    bool isProduct = m_currentProject && node && qobject_cast<QbsProductNode *>(node->projectNode());
     bool isFileEnabled = isFile && node->isEnabled();
 
     m_reparseQbsCtx->setEnabled(!isBuilding && m_currentProject && !m_currentProject->isParsing());
     m_buildFileContextMenu->setEnabled(isFileEnabled);
+    m_buildProductContextMenu->setEnabled(isProduct);
 }
 
 void QbsProjectManagerPlugin::updateReparseQbsAction()
@@ -200,12 +216,15 @@ void QbsProjectManagerPlugin::updateReparseQbsAction()
                              && !m_currentProject->isParsing());
 }
 
-void QbsProjectManagerPlugin::updateBuildFileAction()
+void QbsProjectManagerPlugin::updateBuildActions()
 {
-    bool visible = false;
-    bool enabled = false;
+    bool fileVisible = false;
+    bool fileEnabled = false;
+    bool productVisible = false;
+    bool productEnabled = false;
 
     QString file;
+
     if (Core::IEditor *currentEditor = Core::EditorManager::currentEditor()) {
         file = currentEditor->document()->fileName();
         ProjectExplorer::SessionManager *session = m_projectExplorer->session();
@@ -214,14 +233,22 @@ void QbsProjectManagerPlugin::updateBuildFileAction()
                 = qobject_cast<QbsProject *>(session->projectForFile(file));
 
         m_buildFile->setParameter(QFileInfo(file).fileName());
-        visible = project && node && qobject_cast<QbsBaseProjectNode *>(node->projectNode());
-
-        enabled = !m_projectExplorer->buildManager()->isBuilding(project)
+        fileVisible = project && node && qobject_cast<QbsBaseProjectNode *>(node->projectNode());
+        fileEnabled = !m_projectExplorer->buildManager()->isBuilding(project)
                 && m_currentProject && !m_currentProject->isParsing();
+
+        if (QbsProductNode *productNode = qobject_cast<QbsProductNode *>(node->projectNode())) {
+            productEnabled = true;
+            productVisible = true;
+            m_buildProduct->setParameter(productNode->displayName());
+        }
     }
 
-    m_buildFile->setEnabled(enabled);
-    m_buildFile->setVisible(visible);
+    m_buildFile->setEnabled(fileEnabled);
+    m_buildFile->setVisible(fileVisible);
+
+    m_buildProduct->setEnabled(productEnabled);
+    m_buildProduct->setVisible(productVisible);
 }
 
 void QbsProjectManagerPlugin::activeTargetChanged()
@@ -244,7 +271,7 @@ void QbsProjectManagerPlugin::buildStateChanged(ProjectExplorer::Project *projec
     if (project == m_currentProject) {
         updateReparseQbsAction();
         updateContextActions(m_currentNode, m_currentProject);
-        updateBuildFileAction();
+        updateBuildActions();
     }
 }
 
@@ -279,6 +306,32 @@ void QbsProjectManagerPlugin::buildFile()
     buildFiles(project, QStringList(file));
 }
 
+void QbsProjectManagerPlugin::buildProductContextMenu()
+{
+    QTC_ASSERT(m_currentNode, return);
+    QTC_ASSERT(m_currentProject, return);
+
+    buildProducts(m_currentProject, QStringList(m_currentNode->displayName()));
+}
+
+void QbsProjectManagerPlugin::buildProduct()
+{
+    QbsProject *project = 0;
+    QbsProductNode *product = 0;
+    if (Core::IEditor *currentEditor = Core::EditorManager::currentEditor()) {
+        const QString file = currentEditor->document()->fileName();
+        ProjectExplorer::SessionManager *session = m_projectExplorer->session();
+
+        project = qobject_cast<QbsProject *>(session->projectForFile(file));
+        product = qobject_cast<QbsProductNode *>(session->nodeForFile(file)->projectNode());
+    }
+
+    if (!project || !product)
+        return;
+
+    buildProducts(project, QStringList(product->displayName()));
+}
+
 void QbsProjectManagerPlugin::buildFiles(QbsProject *project, const QStringList &files)
 {
     QTC_ASSERT(project, return);
@@ -296,6 +349,7 @@ void QbsProjectManagerPlugin::buildFiles(QbsProject *project, const QStringList
         return;
 
     bc->setChangedFiles(files);
+    bc->setProducts(QStringList());
 
     const Core::Id buildStep = Core::Id(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
 
@@ -305,6 +359,33 @@ void QbsProjectManagerPlugin::buildFiles(QbsProject *project, const QStringList
     bc->setChangedFiles(QStringList());
 }
 
+void QbsProjectManagerPlugin::buildProducts(QbsProject *project, const QStringList &products)
+{
+    QTC_ASSERT(project, return);
+    QTC_ASSERT(!products.isEmpty(), return);
+
+    ProjectExplorer::Target *t = project->activeTarget();
+    if (!t)
+        return;
+    QbsBuildConfiguration *bc = qobject_cast<QbsBuildConfiguration *>(t->activeBuildConfiguration());
+    if (!bc)
+        return;
+
+    ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance();
+    if (!pe->saveModifiedFiles())
+        return;
+
+    bc->setChangedFiles(QStringList());
+    bc->setProducts(products);
+
+    const Core::Id buildStep = Core::Id(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
+
+    const QString name = ProjectExplorer::ProjectExplorerPlugin::displayNameForStepId(buildStep);
+    pe->buildManager()->buildList(bc->stepList(buildStep), name);
+
+    bc->setProducts(QStringList());
+}
+
 void QbsProjectManagerPlugin::reparseCurrentProject()
 {
     if (m_currentProject)
diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h
index 27317940a3f396c666f26e2ef92a84c01e9fcb94..9e91e3da8db4dbe0544dbd3883abb8453a45d7c1 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h
+++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h
@@ -68,17 +68,20 @@ public:
 private slots:
     void updateContextActions(ProjectExplorer::Node *node, ProjectExplorer::Project *project);
     void updateReparseQbsAction();
-    void updateBuildFileAction();
+    void updateBuildActions();
     void activeTargetChanged();
     void buildStateChanged(ProjectExplorer::Project *project);
     void parsingStateChanged();
     void buildFileContextMenu();
     void buildFile();
+    void buildProductContextMenu();
+    void buildProduct();
 
     void reparseCurrentProject();
 
 private:
     void buildFiles(QbsProject *project, const QStringList &files);
+    void buildProducts(QbsProject *project, const QStringList &products);
 
     QbsManager *m_manager;
     ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
@@ -86,7 +89,9 @@ private:
     QAction *m_reparseQbs;
     QAction *m_reparseQbsCtx;
     QAction *m_buildFileContextMenu;
+    QAction *m_buildProductContextMenu;
     Utils::ParameterAction *m_buildFile;
+    Utils::ParameterAction *m_buildProduct;
 
     Internal::QbsProject *m_currentProject;
     ProjectExplorer::Target *m_currentTarget;