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
kcombobox.h
KUrlRequester QWidget
kurlrequester.h
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