diff --git a/kdevplatform/shell/CMakeLists.txt b/kdevplatform/shell/CMakeLists.txt
index 3dee19523a..5a9c8c3ebe 100644
--- a/kdevplatform/shell/CMakeLists.txt
+++ b/kdevplatform/shell/CMakeLists.txt
@@ -1,192 +1,193 @@
add_definitions(-DTRANSLATION_DOMAIN=\"kdevplatform\")
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
set(KDevPlatformShell_LIB_SRCS
workingsetcontroller.cpp
workingsets/workingset.cpp
workingsets/workingsetfilelabel.cpp
workingsets/workingsettoolbutton.cpp
workingsets/workingsettooltipwidget.cpp
workingsets/workingsetwidget.cpp
workingsets/closedworkingsetswidget.cpp
workingsets/workingsethelpers.cpp
mainwindow.cpp
mainwindow_p.cpp
plugincontroller.cpp
ktexteditorpluginintegration.cpp
shellextension.cpp
core.cpp
uicontroller.cpp
colorschemechooser.cpp
projectcontroller.cpp
project.cpp
partcontroller.cpp
#document.cpp
partdocument.cpp
textdocument.cpp
documentcontroller.cpp
languagecontroller.cpp
statusbar.cpp
runcontroller.cpp
unitylauncher.cpp
sessioncontroller.cpp
session.cpp
sessionlock.cpp
sessionchooserdialog.cpp
savedialog.cpp
sourceformattercontroller.cpp
sourceformatterjob.cpp
completionsettings.cpp
openprojectpage.cpp
openprojectdialog.cpp
projectinfopage.cpp
selectioncontroller.cpp
documentationcontroller.cpp
debugcontroller.cpp
launchconfiguration.cpp
launchconfigurationdialog.cpp
loadedpluginsdialog.cpp
testcontroller.cpp
projectsourcepage.cpp
configdialog.cpp
editorconfigpage.cpp
environmentconfigurebutton.cpp
sourceformatterselectionedit.cpp
runtimecontroller.cpp
checkerstatus.cpp
problem.cpp
problemmodelset.cpp
problemmodel.cpp
problemstore.cpp
watcheddocumentset.cpp
filteredproblemstore.cpp
progresswidget/progressmanager.cpp
progresswidget/statusbarprogresswidget.cpp
progresswidget/overlaywidget.cpp
progresswidget/progressdialog.cpp
areadisplay.cpp
settings/uipreferences.cpp
settings/pluginpreferences.cpp
settings/sourceformattersettings.cpp
settings/editstyledialog.cpp
settings/projectpreferences.cpp
settings/environmentwidget.cpp
settings/environmentprofilemodel.cpp
settings/environmentprofilelistmodel.cpp
settings/environmentpreferences.cpp
settings/languagepreferences.cpp
settings/bgpreferences.cpp
settings/templateconfig.cpp
settings/templatepage.cpp
settings/analyzerspreferences.cpp
settings/runtimespreferences.cpp
settings/documentationpreferences.cpp
)
if(APPLE)
set(KDevPlatformShell_LIB_SRCS ${KDevPlatformShell_LIB_SRCS}
macdockprogressview.mm
)
endif()
declare_qt_logging_category(KDevPlatformShell_LIB_SRCS
TYPE LIBRARY
CATEGORY_BASENAME "shell"
)
kconfig_add_kcfg_files(KDevPlatformShell_LIB_SRCS
settings/uiconfig.kcfgc
settings/projectconfig.kcfgc
settings/languageconfig.kcfgc
settings/bgconfig.kcfgc
)
ki18n_wrap_ui(KDevPlatformShell_LIB_SRCS
projectinfopage.ui
launchconfigurationdialog.ui
projectsourcepage.ui
sourceformatterselectionedit.ui
settings/uiconfig.ui
settings/editstyledialog.ui
settings/sourceformattersettings.ui
settings/projectpreferences.ui
settings/environmentwidget.ui
settings/languagepreferences.ui
settings/bgpreferences.ui
settings/templateconfig.ui
settings/templatepage.ui
)
qt5_add_resources(KDevPlatformShell_LIB_SRCS kdevplatformshell.qrc)
kdevplatform_add_library(KDevPlatformShell SOURCES ${KDevPlatformShell_LIB_SRCS})
target_link_libraries(KDevPlatformShell
PUBLIC
KDev::Sublime
KDev::OutputView
KDev::Interfaces
KDev::Language
KF5::XmlGui
PRIVATE
KDev::Debugger
KDev::Project
KDev::Vcs
KDev::Util
KDev::Documentation
KF5::GuiAddons
KF5::ConfigWidgets
KF5::IconThemes
KF5::KIOFileWidgets
KF5::KIOWidgets
KF5::Parts
KF5::Notifications
KF5::NotifyConfig
KF5::TextEditor
KF5::JobWidgets
KF5::ItemViews
KF5::WindowSystem
KF5::KCMUtils #for KPluginSelector, not sure why it is in kcmutils
KF5::NewStuff # template config page
KF5::Archive # template config page
)
if(APPLE)
target_link_libraries(KDevPlatformShell PRIVATE "-framework AppKit")
endif()
install(FILES
mainwindow.h
plugincontroller.h
shellextension.h
core.h
uicontroller.h
colorschemechooser.h
projectcontroller.h
project.h
partcontroller.h
partdocument.h
textdocument.h
documentcontroller.h
languagecontroller.h
session.h
sessioncontroller.h
sessionlock.h
sourceformattercontroller.h
selectioncontroller.h
runcontroller.h
launchconfiguration.h
environmentconfigurebutton.h
sourceformatterselectionedit.h
checkerstatus.h
problem.h
problemmodel.h
problemmodelset.h
problemconstants.h
+ problemstore.h
filteredproblemstore.h
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kdevplatform/shell COMPONENT Devel
)
diff --git a/plugins/clang/kdevclang.xml b/plugins/clang/kdevclang.xml
index e30996ba4e..c576a25d41 100644
--- a/plugins/clang/kdevclang.xml
+++ b/plugins/clang/kdevclang.xml
@@ -1,73 +1,74 @@
OpenCL C source code
Codi font en C per a OpenCL
Codi font en C per a OpenCL
Zdrojový kód OpenCL C
OpenCL C Quelltext
OpenCL C source code
Código fuente de OpenCL C
Code source C OpenCL
Código fonte en C de OpenCL
Codice sorgente OpenCL C
OpenCL C broncode
Kod źródłowy OpenCL C
Código-fonte em C do OpenCL
Código-fonte em C do OpenCL
Zdrojový kód OpenCL C
OpenCL C-källkod
OpenCL C kaynak kodu
початковий код C OpenCL
OpenCL C 源代码
OpenCL
Open Computing Language
NVIDIA CUDA C source code
Codi font en C per a CUDA de NVIDIA
Codi font en C per a CUDA de NVIDIA
Zdrojový kód NVIDIA CUDA C
NVIDIA CUDA C Quelltext
NVIDIA CUDA C source code
Código fuente de NVIDIA CUDA C
Code source C CUDA NVIDIA
Código fonte en C de NVIDIA CUDA
Codice sorgente CUDA C di NVIDIA
NVIDIA CUDA C broncode
Kod źródłowy NVIDIA CUDA C
Código-fonte em CUDA C da NVIDIA
Código-fonte em CUDA C da NVIDIA
Zdrojový kód NVIDIA CUDA C
NVIDIA CUDA C-källkod
NVIDIA CUDA C kaynak kodu
початковий код C NVIDIA CUDA
NVIDIA CUDA C 源代码
NVIDIA CUDA C header
Capçalera en C per a CUDA de NVIDIA
Cabecera de NVIDIA CUDA C
Cabeceira en C de NVIDIA CUDA
NVIDIA CUDA C header
+ Nagłówek NVIDIA CUDA C
Ficheiro de inclusão em CUDA C da NVIDIA
NVIDIA CUDA C-deklarationsfil
файл заголовків C NVIDIA CUDA
diff --git a/plugins/cmake/cmakebuilddirchooser.ui b/plugins/cmake/cmakebuilddirchooser.ui
index d30da357e0..2d53b36ff7 100644
--- a/plugins/cmake/cmakebuilddirchooser.ui
+++ b/plugins/cmake/cmakebuilddirchooser.ui
@@ -1,196 +1,202 @@
CMakeBuildDirChooser
0
0
611
244
QFormLayout::ExpandingFieldsGrow
0
0
0
0
-
Available build directories:
-
-
New build directory
-
Build &directory:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
buildFolder
-
-
&Installation prefix:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
installPrefix
-
0
0
+
+ The prefix under which the project will be installed. Leaving this empty will let CMake use its default install prefix.
+
+
+ CMake's default install prefix
+
-
Build &type:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
buildType
-
true
0
-
Debug
-
Release
-
RelWithDebInfo
-
MinSizeRel
-
Extra arguments:
-
0
0
true
-
CMake &executable:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
cmakeExecutable
-
0
0
-
Status Message...
true
KComboBox
QComboBox
KUrlRequester
QWidget
diff --git a/plugins/cmake/cmakeutils.cpp b/plugins/cmake/cmakeutils.cpp
index f801bb59ee..bdea58f7c1 100644
--- a/plugins/cmake/cmakeutils.cpp
+++ b/plugins/cmake/cmakeutils.cpp
@@ -1,728 +1,722 @@
/* KDevelop CMake Support
*
* Copyright 2009 Andreas Pakulat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "cmakeutils.h"
#include "cmakeprojectdata.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "icmakedocumentation.h"
#include "cmakebuilddirchooser.h"
#include "settings/cmakecachemodel.h"
#include "debug.h"
#include "cmakebuilderconfig.h"
#include
#include "parser/cmakelistsparser.h"
using namespace KDevelop;
namespace Config
{
namespace Old
{
static const QString currentBuildDirKey = QStringLiteral("CurrentBuildDir");
static const QString oldcmakeExecutableKey = QStringLiteral("CMake Binary"); // Todo: Remove at some point
static const QString currentBuildTypeKey = QStringLiteral("CurrentBuildType");
static const QString currentInstallDirKey = QStringLiteral("CurrentInstallDir");
static const QString currentEnvironmentKey = QStringLiteral("CurrentEnvironment");
static const QString currentExtraArgumentsKey = QStringLiteral("Extra Arguments");
static const QString currentCMakeExecutableKey = QStringLiteral("Current CMake Binary");
static const QString projectRootRelativeKey = QStringLiteral("ProjectRootRelative");
static const QString projectBuildDirs = QStringLiteral("BuildDirs");
}
static const QString buildDirIndexKey_ = QStringLiteral("Current Build Directory Index");
static const QString buildDirOverrideIndexKey = QStringLiteral("Temporary Build Directory Index");
static const QString buildDirCountKey = QStringLiteral("Build Directory Count");
//the used builddir will change for every runtime
static QString buildDirIndexKey() {
const QString currentRuntime = ICore::self()->runtimeController()->currentRuntime()->name();
return buildDirIndexKey_ + QLatin1Char('-') + currentRuntime;
}
namespace Specific
{
static const QString buildDirPathKey = QStringLiteral("Build Directory Path");
// TODO: migrate to more generic & consistent key term "CMake Executable"
// Support the old "CMake Binary" key too for backwards compatibility during
// a reasonable transition period. Both keys are saved at least until 5.2.0
// is released. Import support for the old key will need to remain for a
// considerably longer period, ideally.
static const QString cmakeBinaryKey = QStringLiteral("CMake Binary");
static const QString cmakeExecutableKey = QStringLiteral("CMake Executable");
static const QString cmakeBuildTypeKey = QStringLiteral("Build Type");
static const QString cmakeInstallDirKey = QStringLiteral("Install Directory");
static const QString cmakeEnvironmentKey = QStringLiteral("Environment Profile");
static const QString cmakeArgumentsKey = QStringLiteral("Extra Arguments");
static const QString buildDirRuntime = QStringLiteral("Runtime");
}
static const QString groupNameBuildDir = QStringLiteral("CMake Build Directory %1");
static const QString groupName = QStringLiteral("CMake");
} // namespace Config
namespace
{
KConfigGroup baseGroup( KDevelop::IProject* project )
{
if (!project)
return KConfigGroup();
return project->projectConfiguration()->group( Config::groupName );
}
KConfigGroup buildDirGroup( KDevelop::IProject* project, int buildDirIndex )
{
return baseGroup(project).group( Config::groupNameBuildDir.arg(buildDirIndex) );
}
bool buildDirGroupExists( KDevelop::IProject* project, int buildDirIndex )
{
return baseGroup(project).hasGroup( Config::groupNameBuildDir.arg(buildDirIndex) );
}
QString readBuildDirParameter( KDevelop::IProject* project, const QString& key, const QString& aDefault, int buildDirectory )
{
const int buildDirIndex = buildDirectory<0 ? CMake::currentBuildDirIndex(project) : buildDirectory;
if (buildDirIndex >= 0)
return buildDirGroup( project, buildDirIndex ).readEntry( key, aDefault );
else
return aDefault;
}
void writeBuildDirParameter( KDevelop::IProject* project, const QString& key, const QString& value )
{
int buildDirIndex = CMake::currentBuildDirIndex(project);
if (buildDirIndex >= 0)
{
KConfigGroup buildDirGrp = buildDirGroup( project, buildDirIndex );
buildDirGrp.writeEntry( key, value );
}
else
{
qCWarning(CMAKE) << "cannot write key" << key << "(" << value << ")" << "when no builddir is set!";
}
}
void writeProjectBaseParameter( KDevelop::IProject* project, const QString& key, const QString& value )
{
KConfigGroup baseGrp = baseGroup(project);
baseGrp.writeEntry( key, value );
}
void setBuildDirRuntime( KDevelop::IProject* project, const QString& name)
{
writeBuildDirParameter(project, Config::Specific::buildDirRuntime, name);
}
QString buildDirRuntime( KDevelop::IProject* project, int builddir)
{
return readBuildDirParameter(project, Config::Specific::buildDirRuntime, QString(), builddir);
}
} // namespace
namespace CMake
{
KDevelop::Path::List resolveSystemDirs(KDevelop::IProject* project, const QStringList& dirs)
{
const KDevelop::Path buildDir(CMake::currentBuildDir(project));
const KDevelop::Path installDir(CMake::currentInstallDir(project));
KDevelop::Path::List newList;
newList.reserve(dirs.size());
for (const QString& s : dirs) {
KDevelop::Path dir;
if(s.startsWith(QLatin1String("#[bin_dir]")))
{
dir = KDevelop::Path(buildDir, s);
}
else if(s.startsWith(QLatin1String("#[install_dir]")))
{
dir = KDevelop::Path(installDir, s);
}
else
{
dir = KDevelop::Path(s);
}
// qCDebug(CMAKE) << "resolved" << s << "to" << d;
if (!newList.contains(dir))
{
newList.append(dir);
}
}
return newList;
}
///NOTE: when you change this, update @c defaultConfigure in cmakemanagertest.cpp
bool checkForNeedingConfigure( KDevelop::IProject* project )
{
const QString currentRuntime = ICore::self()->runtimeController()->currentRuntime()->name();
const KDevelop::Path builddir = currentBuildDir(project);
const bool isValid = (buildDirRuntime(project, -1) == currentRuntime || buildDirRuntime(project, -1).isEmpty()) && builddir.isValid();
if( !isValid )
{
CMakeBuildDirChooser bd;
bd.setProject( project );
const auto builddirs = CMake::allBuildDirs(project);
bd.setAlreadyUsed( builddirs );
bd.setShowAvailableBuildDirs(!builddirs.isEmpty());
bd.setCMakeExecutable(currentCMakeExecutable(project));
if( !bd.exec() )
{
return false;
}
if (bd.reuseBuilddir())
{
CMake::setCurrentBuildDirIndex( project, bd.alreadyUsedIndex() );
}
else
{
int addedBuildDirIndex = buildDirCount( project ); // old count is the new index
// Initialize the kconfig items with the values from the dialog, this ensures the settings
// end up in the config file once the changes are saved
qCDebug(CMAKE) << "adding to cmake config: new builddir index" << addedBuildDirIndex;
qCDebug(CMAKE) << "adding to cmake config: builddir path " << bd.buildFolder();
qCDebug(CMAKE) << "adding to cmake config: installdir " << bd.installPrefix();
qCDebug(CMAKE) << "adding to cmake config: extra args" << bd.extraArguments();
qCDebug(CMAKE) << "adding to cmake config: build type " << bd.buildType();
qCDebug(CMAKE) << "adding to cmake config: cmake executable " << bd.cmakeExecutable();
qCDebug(CMAKE) << "adding to cmake config: environment ";
CMake::setBuildDirCount( project, addedBuildDirIndex + 1 );
CMake::setCurrentBuildDirIndex( project, addedBuildDirIndex );
CMake::setCurrentBuildDir( project, bd.buildFolder() );
CMake::setCurrentInstallDir( project, bd.installPrefix() );
CMake::setCurrentExtraArguments( project, bd.extraArguments() );
CMake::setCurrentBuildType( project, bd.buildType() );
CMake::setCurrentCMakeExecutable(project, bd.cmakeExecutable());
CMake::setCurrentEnvironment( project, QString() );
}
setBuildDirRuntime( project, currentRuntime );
return true;
} else if( !QFile::exists( KDevelop::Path(builddir, QStringLiteral("CMakeCache.txt")).toLocalFile() ) ||
//TODO: maybe we could use the builder for that?
!(QFile::exists( KDevelop::Path(builddir, QStringLiteral("Makefile")).toLocalFile() ) ||
QFile::exists( KDevelop::Path(builddir, QStringLiteral("build.ninja")).toLocalFile() ) ) )
{
// User entered information already, but cmake hasn't actually been run yet.
setBuildDirRuntime( project, currentRuntime );
return true;
}
setBuildDirRuntime( project, currentRuntime );
return false;
}
QHash enumerateTargets(const KDevelop::Path& targetsFilePath, const QString& sourceDir, const KDevelop::Path &buildDir)
{
const QString buildPath = buildDir.toLocalFile();
QHash targets;
QFile targetsFile(targetsFilePath.toLocalFile());
if (!targetsFile.open(QIODevice::ReadOnly)) {
qCDebug(CMAKE) << "Couldn't find the Targets file in" << targetsFile.fileName();
}
QTextStream targetsFileStream(&targetsFile);
const QRegularExpression rx(QStringLiteral("^(.*)/CMakeFiles/(.*).dir$"));
while (!targetsFileStream.atEnd()) {
const QString line = targetsFileStream.readLine();
auto match = rx.match(line);
if (!match.isValid())
qCDebug(CMAKE) << "invalid match for" << line;
const QString sourcePath = match.captured(1).replace(buildPath, sourceDir);
targets[KDevelop::Path(sourcePath)].append(match.captured(2));
}
return targets;
}
KDevelop::Path projectRoot(KDevelop::IProject* project)
{
if (!project) {
return {};
}
return project->path().cd(CMake::projectRootRelative(project));
}
KDevelop::Path currentBuildDir( KDevelop::IProject* project, int builddir )
{
return KDevelop::Path(readBuildDirParameter( project, Config::Specific::buildDirPathKey, QString(), builddir ));
}
KDevelop::Path commandsFile(KDevelop::IProject* project)
{
auto currentBuildDir = CMake::currentBuildDir(project);
if (currentBuildDir.isEmpty()) {
return {};
}
return KDevelop::Path(currentBuildDir, QStringLiteral("compile_commands.json"));
}
KDevelop::Path targetDirectoriesFile(KDevelop::IProject* project)
{
auto currentBuildDir = CMake::currentBuildDir(project);
if (currentBuildDir.isEmpty()) {
return {};
}
return KDevelop::Path(currentBuildDir, QStringLiteral("CMakeFiles/TargetDirectories.txt"));
}
QString currentBuildType( KDevelop::IProject* project, int builddir )
{
return readBuildDirParameter( project, Config::Specific::cmakeBuildTypeKey, QStringLiteral("Release"), builddir );
}
QString findExecutable()
{
auto cmake = QStandardPaths::findExecutable(QStringLiteral("cmake"));
#ifdef Q_OS_WIN
if (cmake.isEmpty())
cmake = QStandardPaths::findExecutable(QStringLiteral("cmake"), {
QStringLiteral("C:\\Program Files (x86)\\CMake\\bin"),
QStringLiteral("C:\\Program Files\\CMake\\bin"),
QStringLiteral("C:\\Program Files (x86)\\CMake 2.8\\bin"),
QStringLiteral("C:\\Program Files\\CMake 2.8\\bin")});
#endif
return cmake;
}
KDevelop::Path currentCMakeExecutable(KDevelop::IProject* project, int builddir)
{
auto defaultCMakeExecutable = CMakeBuilderSettings::self()->cmakeExecutable().toLocalFile();
if (!QFileInfo::exists(ICore::self()->runtimeController()->currentRuntime()->pathInHost(KDevelop::Path(defaultCMakeExecutable)).toLocalFile()))
defaultCMakeExecutable = CMake::findExecutable();
if (project) {
// check for "CMake Executable" but for now also "CMake Binary", falling back to the default.
auto projectCMakeExecutable = readBuildDirParameter( project, Config::Specific::cmakeExecutableKey,
readBuildDirParameter( project, Config::Specific::cmakeBinaryKey, defaultCMakeExecutable, builddir),
builddir );
if (projectCMakeExecutable != defaultCMakeExecutable) {
QFileInfo info(projectCMakeExecutable);
if (!info.isExecutable()) {
projectCMakeExecutable = defaultCMakeExecutable;
}
}
return KDevelop::Path(projectCMakeExecutable);
}
return KDevelop::Path(defaultCMakeExecutable);
}
KDevelop::Path currentInstallDir( KDevelop::IProject* project, int builddir )
{
- const QString defaultInstallDir =
-#ifdef Q_OS_WIN
- QStringLiteral("C:\\Program Files");
-#else
- QStringLiteral("/usr/local");
-#endif
- return KDevelop::Path(readBuildDirParameter( project, Config::Specific::cmakeInstallDirKey, defaultInstallDir, builddir ));
+ return KDevelop::Path(readBuildDirParameter( project, Config::Specific::cmakeInstallDirKey, QString(), builddir ));
}
QString projectRootRelative( KDevelop::IProject* project )
{
return baseGroup(project).readEntry( Config::Old::projectRootRelativeKey, "." );
}
bool hasProjectRootRelative(KDevelop::IProject* project)
{
return baseGroup(project).hasKey( Config::Old::projectRootRelativeKey );
}
QString currentExtraArguments( KDevelop::IProject* project, int builddir )
{
return readBuildDirParameter( project, Config::Specific::cmakeArgumentsKey, QString(), builddir );
}
void setCurrentInstallDir( KDevelop::IProject* project, const KDevelop::Path& path )
{
writeBuildDirParameter( project, Config::Specific::cmakeInstallDirKey, path.toLocalFile() );
}
void setCurrentBuildType( KDevelop::IProject* project, const QString& type )
{
writeBuildDirParameter( project, Config::Specific::cmakeBuildTypeKey, type );
}
void setCurrentCMakeExecutable(KDevelop::IProject* project, const KDevelop::Path& path)
{
// maintain compatibility with older versions for now
writeBuildDirParameter(project, Config::Specific::cmakeBinaryKey, path.toLocalFile());
writeBuildDirParameter(project, Config::Specific::cmakeExecutableKey, path.toLocalFile());
}
void setCurrentBuildDir( KDevelop::IProject* project, const KDevelop::Path& path )
{
writeBuildDirParameter( project, Config::Specific::buildDirPathKey, path.toLocalFile() );
}
void setProjectRootRelative( KDevelop::IProject* project, const QString& relative)
{
writeProjectBaseParameter( project, Config::Old::projectRootRelativeKey, relative );
}
void setCurrentExtraArguments( KDevelop::IProject* project, const QString& string)
{
writeBuildDirParameter( project, Config::Specific::cmakeArgumentsKey, string );
}
QString currentEnvironment(KDevelop::IProject* project, int builddir)
{
return readBuildDirParameter( project, Config::Specific::cmakeEnvironmentKey, QString(), builddir );
}
int currentBuildDirIndex( KDevelop::IProject* project )
{
KConfigGroup baseGrp = baseGroup(project);
if ( baseGrp.hasKey( Config::buildDirOverrideIndexKey ) )
return baseGrp.readEntry( Config::buildDirOverrideIndexKey, -1 );
else if (baseGrp.hasKey(Config::buildDirIndexKey()))
return baseGrp.readEntry( Config::buildDirIndexKey(), -1 );
else
return baseGrp.readEntry( Config::buildDirIndexKey_, -1 ); // backwards compatibility
}
void setCurrentBuildDirIndex( KDevelop::IProject* project, int buildDirIndex )
{
writeProjectBaseParameter( project, Config::buildDirIndexKey(), QString::number (buildDirIndex) );
}
void setCurrentEnvironment( KDevelop::IProject* project, const QString& environment )
{
writeBuildDirParameter( project, Config::Specific::cmakeEnvironmentKey, environment );
}
void initBuildDirConfig( KDevelop::IProject* project )
{
int buildDirIndex = currentBuildDirIndex( project );
if (buildDirCount(project) <= buildDirIndex )
setBuildDirCount( project, buildDirIndex + 1 );
}
int buildDirCount( KDevelop::IProject* project )
{
return baseGroup(project).readEntry( Config::buildDirCountKey, 0 );
}
void setBuildDirCount( KDevelop::IProject* project, int count )
{
writeProjectBaseParameter( project, Config::buildDirCountKey, QString::number(count) );
}
void removeBuildDirConfig( KDevelop::IProject* project )
{
int buildDirIndex = currentBuildDirIndex( project );
if ( !buildDirGroupExists( project, buildDirIndex ) )
{
qCWarning(CMAKE) << "build directory config" << buildDirIndex << "to be removed but does not exist";
return;
}
int bdCount = buildDirCount(project);
setBuildDirCount( project, bdCount - 1 );
removeOverrideBuildDirIndex( project );
setCurrentBuildDirIndex( project, -1 );
// move (rename) the upper config groups to keep the numbering
// if there's nothing to move, just delete the group physically
if (buildDirIndex + 1 == bdCount)
buildDirGroup( project, buildDirIndex ).deleteGroup();
else for (int i = buildDirIndex + 1; i < bdCount; ++i)
{
KConfigGroup src = buildDirGroup( project, i );
KConfigGroup dest = buildDirGroup( project, i - 1 );
dest.deleteGroup();
src.copyTo(&dest);
src.deleteGroup();
}
}
QHash readCacheValues(const KDevelop::Path& cmakeCachePath, QSet variables)
{
QHash ret;
QFile file(cmakeCachePath.toLocalFile());
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(CMAKE) << "couldn't open CMakeCache.txt" << cmakeCachePath;
return ret;
}
QTextStream in(&file);
while (!in.atEnd() && !variables.isEmpty())
{
QString line = in.readLine().trimmed();
if(!line.isEmpty() && line[0].isLetter())
{
CacheLine c;
c.readLine(line);
if(!c.isCorrect())
continue;
if (variables.remove(c.name())) {
ret[c.name()] = c.value();
}
}
}
return ret;
}
void updateConfig( KDevelop::IProject* project, int buildDirIndex)
{
if (buildDirIndex < 0)
return;
KConfigGroup buildDirGrp = buildDirGroup( project, buildDirIndex );
const KDevelop::Path builddir(buildDirGrp.readEntry( Config::Specific::buildDirPathKey, QString() ));
const KDevelop::Path cacheFilePath( builddir, QStringLiteral("CMakeCache.txt"));
const QMap keys = {
{ QStringLiteral("CMAKE_COMMAND"), Config::Specific::cmakeExecutableKey },
{ QStringLiteral("CMAKE_INSTALL_PREFIX"), Config::Specific::cmakeInstallDirKey },
{ QStringLiteral("CMAKE_BUILD_TYPE"), Config::Specific::cmakeBuildTypeKey }
};
const QHash cacheValues = readCacheValues(cacheFilePath, keys.keys().toSet());
for(auto it = cacheValues.constBegin(), itEnd = cacheValues.constEnd(); it!=itEnd; ++it) {
const QString key = keys.value(it.key());
Q_ASSERT(!key.isEmpty());
// Use cache only when the config value is not set. Without this check we will always
// overwrite values provided by the user in config dialog.
if (buildDirGrp.readEntry(key).isEmpty() && !it.value().isEmpty())
{
buildDirGrp.writeEntry( key, it.value() );
}
}
}
void attemptMigrate( KDevelop::IProject* project )
{
if ( !baseGroup(project).hasKey( Config::Old::projectBuildDirs ) )
{
qCDebug(CMAKE) << "CMake settings migration: already done, exiting";
return;
}
KConfigGroup baseGrp = baseGroup(project);
KDevelop::Path buildDir( baseGrp.readEntry( Config::Old::currentBuildDirKey, QString() ) );
int buildDirIndex = -1;
const QStringList existingBuildDirs = baseGrp.readEntry( Config::Old::projectBuildDirs, QStringList() );
{
// also, find current build directory in this list (we need an index, not path)
QString currentBuildDirCanonicalPath = QDir( buildDir.toLocalFile() ).canonicalPath();
for( int i = 0; i < existingBuildDirs.count(); ++i )
{
const QString& nextBuildDir = existingBuildDirs.at(i);
if( QDir(nextBuildDir).canonicalPath() == currentBuildDirCanonicalPath )
{
buildDirIndex = i;
}
}
}
int buildDirsCount = existingBuildDirs.count();
qCDebug(CMAKE) << "CMake settings migration: existing build directories" << existingBuildDirs;
qCDebug(CMAKE) << "CMake settings migration: build directory count" << buildDirsCount;
qCDebug(CMAKE) << "CMake settings migration: current build directory" << buildDir << "(index" << buildDirIndex << ")";
baseGrp.writeEntry( Config::buildDirCountKey, buildDirsCount );
baseGrp.writeEntry( Config::buildDirIndexKey(), buildDirIndex );
for (int i = 0; i < buildDirsCount; ++i)
{
qCDebug(CMAKE) << "CMake settings migration: writing group" << i << ": path" << existingBuildDirs.at(i);
KConfigGroup buildDirGrp = buildDirGroup( project, i );
buildDirGrp.writeEntry( Config::Specific::buildDirPathKey, existingBuildDirs.at(i) );
}
baseGrp.deleteEntry( Config::Old::currentBuildDirKey );
baseGrp.deleteEntry( Config::Old::currentCMakeExecutableKey );
baseGrp.deleteEntry( Config::Old::currentBuildTypeKey );
baseGrp.deleteEntry( Config::Old::currentInstallDirKey );
baseGrp.deleteEntry( Config::Old::currentEnvironmentKey );
baseGrp.deleteEntry( Config::Old::currentExtraArgumentsKey );
baseGrp.deleteEntry( Config::Old::projectBuildDirs );
}
void setOverrideBuildDirIndex( KDevelop::IProject* project, int overrideBuildDirIndex )
{
writeProjectBaseParameter( project, Config::buildDirOverrideIndexKey, QString::number(overrideBuildDirIndex) );
}
void removeOverrideBuildDirIndex( KDevelop::IProject* project, bool writeToMainIndex )
{
KConfigGroup baseGrp = baseGroup(project);
if( !baseGrp.hasKey(Config::buildDirOverrideIndexKey) )
return;
if( writeToMainIndex )
baseGrp.writeEntry( Config::buildDirIndexKey(), baseGrp.readEntry(Config::buildDirOverrideIndexKey) );
baseGrp.deleteEntry(Config::buildDirOverrideIndexKey);
}
ICMakeDocumentation* cmakeDocumentation()
{
return KDevelop::ICore::self()->pluginController()->extensionForPlugin(QStringLiteral("org.kdevelop.ICMakeDocumentation"));
}
QStringList allBuildDirs(KDevelop::IProject* project)
{
QStringList result;
int bdCount = buildDirCount(project);
result.reserve(bdCount);
for (int i = 0; i < bdCount; ++i)
result += buildDirGroup( project, i ).readEntry( Config::Specific::buildDirPathKey );
return result;
}
QString executeProcess(const QString& execName, const QStringList& args)
{
Q_ASSERT(!execName.isEmpty());
qCDebug(CMAKE) << "Executing:" << execName << "::" << args;
QProcess p;
QTemporaryDir tmp(QStringLiteral("kdevcmakemanager"));
p.setWorkingDirectory( tmp.path() );
p.start(execName, args, QIODevice::ReadOnly);
if(!p.waitForFinished())
{
qCDebug(CMAKE) << "failed to execute:" << execName << args << p.exitStatus() << p.readAllStandardError();
}
QByteArray b = p.readAllStandardOutput();
QString t = QString::fromUtf8(b.trimmed());
return t;
}
QStringList supportedGenerators()
{
QStringList generatorNames;
bool hasNinja = ICore::self() && ICore::self()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IProjectBuilder"), QStringLiteral("KDevNinjaBuilder"));
if (hasNinja)
generatorNames << QStringLiteral("Ninja");
#ifdef Q_OS_WIN
// Visual Studio solution is the standard generator under windows, but we don't want to use
// the VS IDE, so we need nmake makefiles
generatorNames << QStringLiteral("NMake Makefiles") << QStringLiteral("MinGW Makefiles");
#endif
generatorNames << QStringLiteral("Unix Makefiles");
return generatorNames;
}
QString defaultGenerator()
{
const QStringList generatorNames = supportedGenerators();
QString defGen = generatorNames.value(CMakeBuilderSettings::self()->generator());
if (defGen.isEmpty())
{
qCWarning(CMAKE) << "Couldn't find builder with index " << CMakeBuilderSettings::self()->generator()
<< ", defaulting to 0";
CMakeBuilderSettings::self()->setGenerator(0);
defGen = generatorNames.at(0);
}
return defGen;
}
QVector importTestSuites(const Path &buildDir)
{
const auto contents = CMakeListsParser::readCMakeFile(buildDir.toLocalFile() + QLatin1String("/CTestTestfile.cmake"));
QVector tests;
for (const auto& entry: contents) {
if (entry.name == QLatin1String("add_test")) {
auto args = entry.arguments;
Test test;
test.name = args.takeFirst().value;
test.executable = args.takeFirst().value;
test.arguments = kTransform(args, [](const CMakeFunctionArgument& arg) { return arg.value; });
tests += test;
} else if (entry.name == QLatin1String("subdirs")) {
tests += importTestSuites(Path(buildDir, entry.arguments.first().value));
} else if (entry.name == QLatin1String("set_tests_properties")) {
if(entry.arguments.count() < 4 || entry.arguments.count() % 2) {
qCWarning(CMAKE) << "found set_tests_properties() with unexpected number of arguments:"
<< entry.arguments.count();
continue;
}
if (tests.isEmpty() || entry.arguments.first().value != tests.last().name) {
qCWarning(CMAKE) << "found set_tests_properties(" << entry.arguments.first().value
<< " ...), but expected test " << tests.last().name;
continue;
}
if (entry.arguments[1].value != QLatin1String("PROPERTIES")) {
qCWarning(CMAKE) << "found set_tests_properties(" << entry.arguments.first().value
<< entry.arguments.at(1).value << "...), but expected PROPERTIES as second argument";
continue;
}
Test &test = tests.last();
for (int i = 2; i < entry.arguments.count(); i += 2)
test.properties[entry.arguments[i].value] = entry.arguments[i + 1].value;
}
}
return tests;
}
}
diff --git a/plugins/cmake/cmakeutils.h b/plugins/cmake/cmakeutils.h
index 3642b94c21..ea2ac2509f 100644
--- a/plugins/cmake/cmakeutils.h
+++ b/plugins/cmake/cmakeutils.h
@@ -1,267 +1,268 @@
/* KDevelop CMake Support
*
* Copyright 2009 Andreas Pakulat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#ifndef CMAKEUTILS_H
#define CMAKEUTILS_H
#include "cmakecommonexport.h"
#include
#include
#include
namespace KDevelop
{
class ProjectBaseItem;
class IProject;
class Path;
}
struct Test;
class ICMakeDocumentation;
class CMakeCacheModel;
template
static T kTransform(const Q& list, W func)
{
T ret;
ret.reserve(list.size());
for (auto it = list.constBegin(), itEnd = list.constEnd(); it!=itEnd; ++it)
ret += func(*it);
return ret;
}
template
static int kIndexOf(const Q& list, W func)
{
int i = 0;
for (auto it = list.constBegin(), itEnd = list.constEnd(); it!=itEnd; ++it) {
if (func(*it))
return i;
++i;
}
return -1;
}
template
static T kFilter(const Q &input, _UnaryOperation op)
{
T ret;
for(const auto& v : input) {
if (op(v))
ret += v;
}
return ret;
}
namespace CMake
{
/**
* Checks whether there's a need to run cmake for the given project item
* This is the case if no builddir has been specified, in which case
* it asks for one.
*
* @returns true if configure should be run, false otherwise
*/
KDEVCMAKECOMMON_EXPORT bool checkForNeedingConfigure( KDevelop::IProject* project );
/**
* @returns the current builddir for the given project or an empty url if none
* has been set by the user.
*/
KDEVCMAKECOMMON_EXPORT KDevelop::Path currentBuildDir( KDevelop::IProject* project, int builddir = -1 );
/**
* @returns the path to the 'compile_commands.json' file in the current builddir for the given project
* or an empty url if none has been set by the user.
*/
KDEVCMAKECOMMON_EXPORT KDevelop::Path commandsFile( KDevelop::IProject* project );
/**
* @returns the path to the 'CMakeFiles/TargetDirectories.txt' file in the current builddir for the given project
* or an empty url if none has been set by the user.
*/
KDEVCMAKECOMMON_EXPORT KDevelop::Path targetDirectoriesFile( KDevelop::IProject* project );
/**
* @returns the current build type for the given project or "Release" as default value.
*/
KDEVCMAKECOMMON_EXPORT QString currentBuildType( KDevelop::IProject* project, int builddir = -1 );
/**
* @returns the CMake executable, taking into account standard
* installation dirs on Windows, or empty string in case of failure.
*/
KDEVCMAKECOMMON_EXPORT QString findExecutable();
/**
* @returns the current CMake executable for the given project, falling back to
* CMakeBuilderSettings::self()->cmakeExecutable() as the user-specified KDevelop-wide default value.
*/
KDEVCMAKECOMMON_EXPORT KDevelop::Path currentCMakeExecutable(KDevelop::IProject* project, int builddir = -1);
/**
- * @returns the current install dir for the given project or "/usr/local" as default value.
+ * @returns the current install dir for the given project or an empty string if none has been defined
+ * (in that case, whatever default CMake sets for the platform will be used.)
*/
KDEVCMAKECOMMON_EXPORT KDevelop::Path currentInstallDir( KDevelop::IProject* project, int builddir = -1 );
/**
* @returns the current extra arguments for the given project or "" as default value.
*/
KDEVCMAKECOMMON_EXPORT QString currentExtraArguments( KDevelop::IProject* project, int builddir = -1 );
/**
* @returns the current build dir for the given project.
*/
KDEVCMAKECOMMON_EXPORT QString projectRootRelative( KDevelop::IProject* project );
/**
* @returns whether there's projectRootRelative defined
*/
KDEVCMAKECOMMON_EXPORT bool hasProjectRootRelative( KDevelop::IProject* project );
/**
* Extracts target names from builddir/CMakeFiles/TargetDirectories.txt and maps corresponding source locations to them.
*/
KDEVCMAKECOMMON_EXPORT QHash enumerateTargets(const KDevelop::Path& targetsFilePath, const QString& sourceDir, const KDevelop::Path &buildDir);
/**
* Convenience function to get the project root.
*/
KDEVCMAKECOMMON_EXPORT KDevelop::Path projectRoot( KDevelop::IProject* project );
/**
* @returns the environment configuration for a @p project
*/
KDEVCMAKECOMMON_EXPORT QString currentEnvironment( KDevelop::IProject* project, int builddir = -1 );
/**
* Sets the current install dir for the given project.
*/
KDEVCMAKECOMMON_EXPORT void setCurrentInstallDir( KDevelop::IProject* project, const KDevelop::Path &path );
/**
* Sets the current build type for the given project.
*/
KDEVCMAKECOMMON_EXPORT void setCurrentBuildType( KDevelop::IProject* project, const QString& type );
/**
* Sets the current CMake executable for the given project.
*/
KDEVCMAKECOMMON_EXPORT void setCurrentCMakeExecutable(KDevelop::IProject* project, const KDevelop::Path& path);
/**
* Sets the current build dir for the given project.
*/
KDEVCMAKECOMMON_EXPORT void setCurrentBuildDir( KDevelop::IProject* project, const KDevelop::Path& path );
/**
* Sets the current build dir for the given project.
*/
KDEVCMAKECOMMON_EXPORT void setProjectRootRelative( KDevelop::IProject* project, const QString& path);
/**
* Sets the current extra arguments for the given project.
*/
KDEVCMAKECOMMON_EXPORT void setCurrentExtraArguments( KDevelop::IProject* project, const QString& args );
/**
* Obtains a cmake documentation instance if it exists
*/
KDEVCMAKECOMMON_EXPORT ICMakeDocumentation* cmakeDocumentation();
/**
* Retrieves the configured build directories for @p project.
*/
KDEVCMAKECOMMON_EXPORT QStringList allBuildDirs(KDevelop::IProject* project);
/**
* Attempts to migrate the CMake configuration to per-builddir format.
* Silently returns if the migration has already been performed.
*/
KDEVCMAKECOMMON_EXPORT void attemptMigrate( KDevelop::IProject* project );
/**
* Attempts to update CMake configuration keys from the cache data (CMakeCache.txt)
*
* The model is created based on build directory path for the given index @p buildDirectory
*/
KDEVCMAKECOMMON_EXPORT void updateConfig( KDevelop::IProject* project, int buildDirectory);
/**
* Returns the current build directory count.
*/
KDEVCMAKECOMMON_EXPORT int buildDirCount( KDevelop::IProject* project );
/**
* Sets the build directory count (equivalent to adding a new build directory).
*/
KDEVCMAKECOMMON_EXPORT void setBuildDirCount( KDevelop::IProject* project, int count );
/**
* @returns the current builddir index for the given project or -1 if none
* has been set by the user.
*/
KDEVCMAKECOMMON_EXPORT int currentBuildDirIndex( KDevelop::IProject *project );
/**
* Sets the current build dir index for the given project.
*/
KDEVCMAKECOMMON_EXPORT void setCurrentBuildDirIndex( KDevelop::IProject* project, int buildDirIndex );
/**
* A hack to avoid adding an optional "build directory index" parameter to all functions here.
* This function sets an alternate build directory index key that overrides regular build directory index.
*/
KDEVCMAKECOMMON_EXPORT void setOverrideBuildDirIndex( KDevelop::IProject* project, int overrideBuildDirIndex );
/**
* This removes build directory override key (\ref setOverrideBuildDirIndex).
* Silently returns if there is no override.
*
* @param writeToMainIndex Whether the overridden index should be saved to regular
*/
KDEVCMAKECOMMON_EXPORT void removeOverrideBuildDirIndex( KDevelop::IProject* project, bool writeToMainIndex = false );
/**
* Sets the environment configuration for the given project.
*/
KDEVCMAKECOMMON_EXPORT void setCurrentEnvironment( KDevelop::IProject* project, const QString& environment );
/**
* Removes current build directory (overridden or not) from the project configuration.
* Override is then cleared and index set to -1.
*/
KDEVCMAKECOMMON_EXPORT void removeBuildDirConfig( KDevelop::IProject* project );
KDEVCMAKECOMMON_EXPORT KDevelop::Path::List resolveSystemDirs(KDevelop::IProject* project, const QStringList& dirs);
/** Runs the process specified by @p execName with @p args */
KDEVCMAKECOMMON_EXPORT QString executeProcess(const QString& execName, const QStringList& args=QStringList());
/** Opens @p cmakeCachePath and parses it, returns a hash with the specified keys in @p variables */
KDEVCMAKECOMMON_EXPORT QHash readCacheValues(const KDevelop::Path& cmakeCachePath, QSet variables);
KDEVCMAKECOMMON_EXPORT QStringList supportedGenerators();
KDEVCMAKECOMMON_EXPORT QString defaultGenerator();
KDEVCMAKECOMMON_EXPORT QVector importTestSuites(const KDevelop::Path &buildDir);
}
#endif