diff --git a/languages/clang/duchain/parsesession.cpp b/languages/clang/duchain/parsesession.cpp index 80874d90a5..5d07de74cd 100644 --- a/languages/clang/duchain/parsesession.cpp +++ b/languages/clang/duchain/parsesession.cpp @@ -1,484 +1,490 @@ /* This file is part of KDevelop Copyright 2013 Olivier de Gaalon Copyright 2013 Milian Wolff Copyright 2013 Kevin Funk This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "parsesession.h" #include #include "clangproblem.h" #include "clangdiagnosticevaluator.h" #include "todoextractor.h" #include "clanghelpers.h" #include "clangindex.h" #include "clangparsingenvironment.h" #include "util/clangdebug.h" #include "util/clangtypes.h" #include "util/clangutils.h" #include #include #include #include #include #include #include #include using namespace KDevelop; namespace { QVector extraArgs() { const auto extraArgsString = QString::fromLatin1(qgetenv("KDEV_CLANG_EXTRA_ARGUMENTS")); const auto extraArgs = KShell::splitArgs(extraArgsString); // transform to list of QByteArrays QVector result; result.reserve(extraArgs.size()); foreach (const QString& arg, extraArgs) { result << arg.toLatin1(); } clangDebug() << "Passing extra arguments to clang:" << result; return result; } QVector argsForSession(const QString& path, ParseSessionData::Options options, const ParserSettings& parserSettings) { QMimeDatabase db; if(db.mimeTypeForFile(path).name() == QStringLiteral("text/x-objcsrc")) { return {QByteArrayLiteral("-xobjective-c++")}; } // TODO: No proper mime type detection possible yet // cf. https://bugs.freedesktop.org/show_bug.cgi?id=26913 if (path.endsWith(QLatin1String(".cl"), Qt::CaseInsensitive)) { return {QByteArrayLiteral("-xcl")}; } + // TODO: No proper mime type detection possible yet + // cf. https://bugs.freedesktop.org/show_bug.cgi?id=23700 + if (path.endsWith(QLatin1String(".cu"), Qt::CaseInsensitive)) { + return {QByteArrayLiteral("-xcuda")}; + } + if (parserSettings.parserOptions.isEmpty()) { // The parserOptions can be empty for some unit tests that use ParseSession directly auto defaultArguments = ClangSettingsManager::self()->parserSettings(path).toClangAPI(); defaultArguments.append(QByteArrayLiteral("-nostdinc")); defaultArguments.append(QByteArrayLiteral("-nostdinc++")); defaultArguments.append(QByteArrayLiteral("-xc++")); return defaultArguments; } auto result = parserSettings.toClangAPI(); result.append(QByteArrayLiteral("-nostdinc")); if (parserSettings.isCpp()) { result.append(QByteArrayLiteral("-nostdinc++")); } if (options & ParseSessionData::PrecompiledHeader) { result.append(parserSettings.isCpp() ? QByteArrayLiteral("-xc++-header") : QByteArrayLiteral("-xc-header")); return result; } result.append(parserSettings.isCpp() ? QByteArrayLiteral("-xc++") : QByteArrayLiteral("-xc")); return result; } void addIncludes(QVector* args, QVector* otherArgs, const Path::List& includes, const char* cliSwitch) { foreach (const Path& url, includes) { if (url.isEmpty()) { continue; } QFileInfo info(url.toLocalFile()); QByteArray path = url.toLocalFile().toUtf8(); if (info.isFile()) { path.prepend("-include"); } else { path.prepend(cliSwitch); } otherArgs->append(path); args->append(path.constData()); } } void addFrameworkDirectories(QVector* args, QVector* otherArgs, const Path::List& frameworkDirectories, const char* cliSwitch) { foreach (const Path& url, frameworkDirectories) { if (url.isEmpty()) { continue; } QFileInfo info(url.toLocalFile()); if (!info.isDir()) { qWarning() << "supposed framework directory is not a directory:" << url.pathOrUrl(); continue; } QByteArray path = url.toLocalFile().toUtf8(); otherArgs->append(cliSwitch); otherArgs->append(path); args->append(cliSwitch); args->append(path.constData()); } } QVector toClangApi(const QVector& unsavedFiles) { QVector unsaved; unsaved.reserve(unsavedFiles.size()); std::transform(unsavedFiles.begin(), unsavedFiles.end(), std::back_inserter(unsaved), [] (const UnsavedFile& file) { return file.toClangApi(); }); return unsaved; } bool needGccCompatibility(const ClangParsingEnvironment& environment) { const auto& defines = environment.defines(); // TODO: potentially do the same for the intel compiler? return defines.contains(QStringLiteral("__GNUC__")) && !environment.defines().contains(QStringLiteral("__clang__")); } bool hasQtIncludes(const Path::List& includePaths) { return std::find_if(includePaths.begin(), includePaths.end(), [] (const Path& path) { return path.lastPathSegment() == QLatin1String("QtCore"); }) != includePaths.end(); } } ParseSessionData::ParseSessionData(const QVector& unsavedFiles, ClangIndex* index, const ClangParsingEnvironment& environment, Options options) : m_file(nullptr) , m_unit(nullptr) { unsigned int flags = CXTranslationUnit_CXXChainedPCH | CXTranslationUnit_DetailedPreprocessingRecord #if CINDEX_VERSION_MINOR >= 34 | CXTranslationUnit_KeepGoing #endif ; if (options.testFlag(SkipFunctionBodies)) { flags |= CXTranslationUnit_SkipFunctionBodies; } if (options.testFlag(PrecompiledHeader)) { flags |= CXTranslationUnit_ForSerialization; } else { flags |= CXTranslationUnit_CacheCompletionResults | CXTranslationUnit_PrecompiledPreamble; if (environment.quality() == ClangParsingEnvironment::Unknown) { flags |= CXTranslationUnit_Incomplete; } } const auto tuUrl = environment.translationUnitUrl(); Q_ASSERT(!tuUrl.isEmpty()); const auto arguments = argsForSession(tuUrl.str(), options, environment.parserSettings()); QVector clangArguments; const auto& includes = environment.includes(); const auto& pchInclude = environment.pchInclude(); // uses QByteArray as smart-pointer for const char* ownership QVector smartArgs; smartArgs.reserve(includes.system.size() + includes.project.size() + pchInclude.isValid() + arguments.size() + 1); clangArguments.reserve(smartArgs.size()); std::transform(arguments.constBegin(), arguments.constEnd(), std::back_inserter(clangArguments), [] (const QByteArray &argument) { return argument.constData(); }); // NOTE: the PCH include must come before all other includes! if (pchInclude.isValid()) { clangArguments << "-include"; QByteArray pchFile = pchInclude.toLocalFile().toUtf8(); smartArgs << pchFile; clangArguments << pchFile.constData(); } if (needGccCompatibility(environment)) { const auto compatFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kdevclangsupport/gcc_compat.h")).toUtf8(); if (!compatFile.isEmpty()) { smartArgs << compatFile; clangArguments << "-include" << compatFile.constData(); } } if (hasQtIncludes(includes.system)) { const auto wrappedQtHeaders = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kdevclangsupport/wrappedQtHeaders"), QStandardPaths::LocateDirectory).toUtf8(); if (!wrappedQtHeaders.isEmpty()) { smartArgs << wrappedQtHeaders; clangArguments << "-isystem" << wrappedQtHeaders.constData(); const auto qtCore = wrappedQtHeaders + "/QtCore"; smartArgs << qtCore; clangArguments << "-isystem" << qtCore.constData(); } } addIncludes(&clangArguments, &smartArgs, includes.system, "-isystem"); addIncludes(&clangArguments, &smartArgs, includes.project, "-I"); const auto& frameworkDirectories = environment.frameworkDirectories(); addFrameworkDirectories(&clangArguments, &smartArgs, frameworkDirectories.system, "-iframework"); addFrameworkDirectories(&clangArguments, &smartArgs, frameworkDirectories.project, "-F"); smartArgs << writeDefinesFile(environment.defines()); clangArguments << "-imacros" << smartArgs.last().constData(); // append extra args from environment variable static const auto extraArgs = ::extraArgs(); foreach (const QByteArray& arg, extraArgs) { clangArguments << arg.constData(); } QVector unsaved; //For PrecompiledHeader, we don't want unsaved contents (and contents.isEmpty()) if (!options.testFlag(PrecompiledHeader)) { unsaved = toClangApi(unsavedFiles); } // debugging: print hypothetical clang invocation including args (for easy c&p for local testing) if (qEnvironmentVariableIsSet("KDEV_CLANG_DISPLAY_ARGS")) { QTextStream out(stdout); out << "Invocation: clang"; foreach (const auto& arg, clangArguments) { out << " " << arg; } out << " " << tuUrl.byteArray().constData() << "\n"; } const CXErrorCode code = clang_parseTranslationUnit2( index->index(), tuUrl.byteArray().constData(), clangArguments.constData(), clangArguments.size(), unsaved.data(), unsaved.size(), flags, &m_unit ); if (code != CXError_Success) { qWarning() << "clang_parseTranslationUnit2 return with error code" << code; if (!qEnvironmentVariableIsSet("KDEV_CLANG_DISPLAY_DIAGS")) { qWarning() << " (start KDevelop with `KDEV_CLANG_DISPLAY_DIAGS=1 kdevelop` to see more diagnostics)"; } } if (m_unit) { setUnit(m_unit); m_environment = environment; if (options.testFlag(PrecompiledHeader)) { clang_saveTranslationUnit(m_unit, (tuUrl.byteArray() + ".pch").constData(), CXSaveTranslationUnit_None); } } else { qWarning() << "Failed to parse translation unit:" << tuUrl; } } ParseSessionData::~ParseSessionData() { clang_disposeTranslationUnit(m_unit); } QByteArray ParseSessionData::writeDefinesFile(const QMap& defines) { m_definesFile.open(); Q_ASSERT(m_definesFile.isWritable()); QTextStream definesStream(&m_definesFile); // don't show warnings about redefined macros definesStream << "#pragma clang system_header\n"; for (auto it = defines.begin(); it != defines.end(); ++it) { definesStream << QStringLiteral("#define ") << it.key() << ' ' << it.value() << '\n'; } return m_definesFile.fileName().toUtf8(); } void ParseSessionData::setUnit(CXTranslationUnit unit) { m_unit = unit; if (m_unit) { const ClangString unitFile(clang_getTranslationUnitSpelling(unit)); m_file = clang_getFile(m_unit, unitFile.c_str()); } else { m_file = nullptr; } } ClangParsingEnvironment ParseSessionData::environment() const { return m_environment; } ParseSession::ParseSession(const ParseSessionData::Ptr& data) : d(data) { if (d) { ENSURE_CHAIN_NOT_LOCKED d->m_mutex.lock(); } } ParseSession::~ParseSession() { if (d) { d->m_mutex.unlock(); } } void ParseSession::setData(const ParseSessionData::Ptr& data) { if (data == d) { return; } if (d) { d->m_mutex.unlock(); } d = data; if (d) { ENSURE_CHAIN_NOT_LOCKED d->m_mutex.lock(); } } ParseSessionData::Ptr ParseSession::data() const { return d; } IndexedString ParseSession::languageString() { static const IndexedString lang("Clang"); return lang; } QList ParseSession::problemsForFile(CXFile file) const { if (!d) { return {}; } QList problems; // extra clang diagnostics const uint numDiagnostics = clang_getNumDiagnostics(d->m_unit); problems.reserve(numDiagnostics); for (uint i = 0; i < numDiagnostics; ++i) { auto diagnostic = clang_getDiagnostic(d->m_unit, i); CXSourceLocation location = clang_getDiagnosticLocation(diagnostic); CXFile diagnosticFile; clang_getFileLocation(location, &diagnosticFile, nullptr, nullptr, nullptr); // missing-include problems are so severe in clang that we always propagate // them to this document, to ensure that the user will see the error. if (diagnosticFile != file && ClangDiagnosticEvaluator::diagnosticType(diagnostic) != ClangDiagnosticEvaluator::IncludeFileNotFoundProblem) { continue; } ProblemPointer problem(ClangDiagnosticEvaluator::createProblem(diagnostic, d->m_unit)); problems << problem; clang_disposeDiagnostic(diagnostic); } // other problem sources TodoExtractor extractor(unit(), file); problems << extractor.problems(); #if CINDEX_VERSION_MINOR > 30 // note that the below warning is triggered on every reparse when there is a precompiled preamble // see also TestDUChain::testReparseIncludeGuard const QString path = QDir(ClangString(clang_getFileName(file)).toString()).canonicalPath(); const IndexedString indexedPath(path); if (ClangHelpers::isHeader(path) && !clang_isFileMultipleIncludeGuarded(unit(), file) && !clang_Location_isInSystemHeader(clang_getLocationForOffset(d->m_unit, file, 0))) { ProblemPointer problem(new Problem); problem->setSeverity(IProblem::Warning); problem->setDescription(i18n("Header is not guarded against multiple inclusions")); problem->setExplanation(i18n("The given header is not guarded against multiple inclusions, " "either with the conventional #ifndef/#define/#endif macro guards or with #pragma once.")); problem->setFinalLocation({indexedPath, KTextEditor::Range()}); problem->setSource(IProblem::Preprocessor); problems << problem; // TODO: Easy to add an assistant here that adds the guards -- any takers? } #endif return problems; } CXTranslationUnit ParseSession::unit() const { return d ? d->m_unit : nullptr; } CXFile ParseSession::file(const QByteArray& path) const { return clang_getFile(unit(), path.constData()); } CXFile ParseSession::mainFile() const { return d ? d->m_file : nullptr; } bool ParseSession::reparse(const QVector& unsavedFiles, const ClangParsingEnvironment& environment) { if (!d || environment != d->m_environment) { return false; } auto unsaved = toClangApi(unsavedFiles); const auto code = clang_reparseTranslationUnit(d->m_unit, unsaved.size(), unsaved.data(), clang_defaultReparseOptions(d->m_unit)); if (code != CXError_Success) { qWarning() << "clang_reparseTranslationUnit return with error code" << code; // if error code != 0 => clang_reparseTranslationUnit invalidates the old translation unit => clean up clang_disposeTranslationUnit(d->m_unit); d->setUnit(nullptr); return false; } // update state d->setUnit(d->m_unit); return true; } ClangParsingEnvironment ParseSession::environment() const { return d->m_environment; } diff --git a/languages/clang/kdevclangsupport.json b/languages/clang/kdevclangsupport.json index a9284f7807..6da6611f77 100644 --- a/languages/clang/kdevclangsupport.json +++ b/languages/clang/kdevclangsupport.json @@ -1,72 +1,74 @@ { "KPlugin": { - "Description": "C/C++ Language Support (Clang-based)", - "Description[ca@valencia]": "Implementació del llenguatge C/C++ (basat en Clang)", - "Description[ca]": "Implementació del llenguatge C/C++ (basat en Clang)", - "Description[cs]": "Podpora jazyka C/C++ (založeno na Clang)", - "Description[de]": "Sprachunterstützung für C/C++ (Clang-basiert)", - "Description[es]": "Implementación del lenguaje C/C++ (basado en Clang)", - "Description[fi]": "C/C++-kielituki (Clang-pohjainen)", - "Description[fr]": "Prise en charge du langage C/C++ (utilisant Clang)", - "Description[gl]": "Compatibilidade con C e C++ (baseada en Clang)", - "Description[it]": "Supporto al linguaggio C/C++ (basato su Clang)", - "Description[nl]": "Ondersteuning voor de talen C/C++ (Clang-based)", - "Description[pl]": "Obsługa języków C/C++ (na podstawie Clang)", - "Description[pt]": "Suporte para a Linguagem C/C++ (baseado no Clang)", - "Description[pt_BR]": "Suporte à linguagem C/C++ (baseado no Clang)", - "Description[sk]": "Podpora jazyka C/C++ (založená na triedach)", - "Description[sl]": "Podpora jeziku C/C++ (temelječa na Clang)", - "Description[sv]": "C/C++ språkstöd (Clang-baserat)", - "Description[uk]": "Підтримка мови C/C++ на основі Clang", - "Description[x-test]": "xxC/C++ Language Support (Clang-based)xx", - "Description[zh_CN]": "C/C++ 语言支持 (基于 Clang)", + "Description": "C/C++ Language Support (Clang-based)", + "Description[ca@valencia]": "Implementació del llenguatge C/C++ (basat en Clang)", + "Description[ca]": "Implementació del llenguatge C/C++ (basat en Clang)", + "Description[cs]": "Podpora jazyka C/C++ (založeno na Clang)", + "Description[de]": "Sprachunterstützung für C/C++ (Clang-basiert)", + "Description[es]": "Implementación del lenguaje C/C++ (basado en Clang)", + "Description[fi]": "C/C++-kielituki (Clang-pohjainen)", + "Description[fr]": "Prise en charge du langage C/C++ (utilisant Clang)", + "Description[gl]": "Compatibilidade con C e C++ (baseada en Clang)", + "Description[it]": "Supporto al linguaggio C/C++ (basato su Clang)", + "Description[nl]": "Ondersteuning voor de talen C/C++ (Clang-based)", + "Description[pl]": "Obsługa języków C/C++ (na podstawie Clang)", + "Description[pt]": "Suporte para a Linguagem C/C++ (baseado no Clang)", + "Description[pt_BR]": "Suporte à linguagem C/C++ (baseado no Clang)", + "Description[sk]": "Podpora jazyka C/C++ (založená na triedach)", + "Description[sl]": "Podpora jeziku C/C++ (temelječa na Clang)", + "Description[sv]": "C/C++ språkstöd (Clang-baserat)", + "Description[uk]": "Підтримка мови C/C++ на основі Clang", + "Description[x-test]": "xxC/C++ Language Support (Clang-based)xx", + "Description[zh_CN]": "C/C++ 语言支持 (基于 Clang)", "Icon": "text-x-c++src", - "Id": "kdevclangsupport", - "Name": "C++ Support", - "Name[bs]": "C++ Podrška", - "Name[ca@valencia]": "Implementació del C++", - "Name[ca]": "Implementació del C++", - "Name[cs]": "Podpora C++", - "Name[de]": "Unterstützung für C++", - "Name[es]": "Implementación de C++", - "Name[fi]": "C++-tuki", - "Name[fr]": "Prise en charge du C++", - "Name[gl]": "Compatibilidade con C++", - "Name[hu]": "C++ támogatás", - "Name[it]": "Supporto C++", - "Name[nl]": "Ondersteuning voor C++", - "Name[pl]": "Obsługa C++", - "Name[pt]": "Suporte a C/C++", - "Name[pt_BR]": "Suporte à C++", - "Name[ru]": "Поддержка C++", - "Name[sk]": "Podpora C++", - "Name[sl]": "Podpora za C++", - "Name[sv]": "C++ stöd", - "Name[tr]": "C++ Desteği", - "Name[uk]": "Підтримка C++", - "Name[x-test]": "xxC++ Supportxx", - "Name[zh_CN]": "C++ 支持", + "Id": "kdevclangsupport", + "Name": "C++ Support", + "Name[bs]": "C++ Podrška", + "Name[ca@valencia]": "Implementació del C++", + "Name[ca]": "Implementació del C++", + "Name[cs]": "Podpora C++", + "Name[de]": "Unterstützung für C++", + "Name[es]": "Implementación de C++", + "Name[fi]": "C++-tuki", + "Name[fr]": "Prise en charge du C++", + "Name[gl]": "Compatibilidade con C++", + "Name[hu]": "C++ támogatás", + "Name[it]": "Supporto C++", + "Name[nl]": "Ondersteuning voor C++", + "Name[pl]": "Obsługa C++", + "Name[pt]": "Suporte a C/C++", + "Name[pt_BR]": "Suporte à C++", + "Name[ru]": "Поддержка C++", + "Name[sk]": "Podpora C++", + "Name[sl]": "Podpora za C++", + "Name[sv]": "C++ stöd", + "Name[tr]": "C++ Desteği", + "Name[uk]": "Підтримка C++", + "Name[x-test]": "xxC++ Supportxx", + "Name[zh_CN]": "C++ 支持", "ServiceTypes": [ "KDevelop/Plugin" ] - }, + }, "X-KDevelop-Interfaces": [ "ILanguageSupport" - ], + ], "X-KDevelop-Languages": [ - "C", - "C++", - "OpenCL", + "C", + "C++", + "OpenCL", + "CUDA C", "Objective-C" - ], - "X-KDevelop-LoadMode": "AlwaysOn", - "X-KDevelop-Mode": "NoGUI", + ], + "X-KDevelop-LoadMode": "AlwaysOn", + "X-KDevelop-Mode": "NoGUI", "X-KDevelop-SupportedMimeTypes": [ - "text/x-chdr", - "text/x-c++hdr", - "text/x-csrc", - "text/x-c++src", - "text/x-opencl-src", + "text/x-chdr", + "text/x-c++hdr", + "text/x-csrc", + "text/x-c++src", + "text/x-openclsrc", + "text/vnd.nvidia.cuda.csrc", "text/x-objcsrc" ] } diff --git a/languages/clang/tests/files/cuda.cu b/languages/clang/tests/files/cuda.cu new file mode 100644 index 0000000000..51b647356f --- /dev/null +++ b/languages/clang/tests/files/cuda.cu @@ -0,0 +1,144 @@ +// Thread block size +#define BLOCK_SIZE 16 + +// Matrices are stored in row-major order: +// M(row, col) = *(M.elements + row * M.stride + col) +typedef struct { + int width; + int height; + int stride; + float* elements; +} Matrix; + +// Get a matrix element +__device__ float GetElement(const Matrix A, int row, int col) +{ + return A.elements[row * A.stride + col]; +} + +// Set a matrix element +__device__ void SetElement(Matrix A, int row, int col, + float value) +{ + A.elements[row * A.stride + col] = value; +} + +// Get the BLOCK_SIZExBLOCK_SIZE sub-matrix Asub of A that is +// located col sub-matrices to the right and row sub-matrices down +// from the upper-left corner of A +__device__ Matrix GetSubMatrix(Matrix A, int row, int col) +{ + Matrix Asub; + Asub.width = BLOCK_SIZE; + Asub.height = BLOCK_SIZE; + Asub.stride = A.stride; + Asub.elements = &A.elements[A.stride * BLOCK_SIZE * row + + BLOCK_SIZE * col]; + return Asub; +} + + +__global__ void MatMulKernel(Matrix A, Matrix B, Matrix C) +{ + // Block row and column + int blockRow = blockIdx.y; + int blockCol = blockIdx.x; + + // Each thread block computes one sub-matrix Csub of C + Matrix Csub = GetSubMatrix(C, blockRow, blockCol); + + // Each thread computes one element of Csub + // by accumulating results into Cvalue + float Cvalue = 0; + + // Thread row and column within Csub + int row = threadIdx.y; + int col = threadIdx.x; + + // Loop over all the sub-matrices of A and B that are + // required to compute Csub + // Multiply each pair of sub-matrices together + // and accumulate the results + for (int m = 0; m < (A.width / BLOCK_SIZE); ++m) { + + // Get sub-matrix Asub of A + Matrix Asub = GetSubMatrix(A, blockRow, m); + + // Get sub-matrix Bsub of B + Matrix Bsub = GetSubMatrix(B, m, blockCol); + + // Shared memory used to store Asub and Bsub respectively + __shared__ float As[BLOCK_SIZE][BLOCK_SIZE]; + __shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE]; + + // Load Asub and Bsub from device memory to shared memory + // Each thread loads one element of each sub-matrix + As[row][col] = GetElement(Asub, row, col); + Bs[row][col] = GetElement(Bsub, row, col); + + // Synchronize to make sure the sub-matrices are loaded + // before starting the computation + __syncthreads(); + + // Multiply Asub and Bsub together + for (int e = 0; e < BLOCK_SIZE; ++e) + Cvalue += As[row][e] * Bs[e][col]; + + // Synchronize to make sure that the preceding + // computation is done before loading two new + // sub-matrices of A and B in the next iteration + __syncthreads(); + } + + // Write Csub to device memory + // Each thread writes one element + SetElement(Csub, row, col, Cvalue); +} + +// Matrix multiplication - Host code +// Matrix dimensions are assumed to be multiples of BLOCK_SIZE +void MatMul(const Matrix A, const Matrix B, Matrix C) +{ + // Load A and B to device memory + Matrix d_A; + d_A.width = d_A.stride = A.width; d_A.height = A.height; + size_t size = A.width * A.height * sizeof(float); + cudaMalloc(&d_A.elements, size); + cudaMemcpy(d_A.elements, A.elements, size, + cudaMemcpyHostToDevice); + Matrix d_B; + d_B.width = d_B.stride = B.width; d_B.height = B.height; + size = B.width * B.height * sizeof(float); + + cudaMalloc(&d_B.elements, size); + cudaMemcpy(d_B.elements, B.elements, size, + cudaMemcpyHostToDevice); + + // Allocate C in device memory + Matrix d_C; + d_C.width = d_C.stride = C.width; d_C.height = C.height; + size = C.width * C.height * sizeof(float); + cudaMalloc(&d_C.elements, size); + + // Invoke kernel + dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE); + dim3 dimGrid(B.width / dimBlock.x, A.height / dimBlock.y); + MatMulKernel<<>>(d_A, d_B, d_C); + + // Read C from device memory + cudaMemcpy(C.elements, d_C.elements, size, + cudaMemcpyDeviceToHost); + + // Free device memory + cudaFree(d_A.elements); + cudaFree(d_B.elements); + cudaFree(d_C.elements); +} + +// Matrix multiplication kernel called by MatMul() + +int main() +{ + Matrix a, b, c; + MatMul(a, b, c); +} diff --git a/languages/clang/tests/test_files.cpp b/languages/clang/tests/test_files.cpp index 9f785d3c70..8560cf7e48 100644 --- a/languages/clang/tests/test_files.cpp +++ b/languages/clang/tests/test_files.cpp @@ -1,95 +1,95 @@ /************************************************************************************* * Copyright (C) 2013 by Milian Wolff * * Copyright (C) 2013 Olivier de Gaalon * * * * 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 "test_files.h" #include #include #include #include #include #include #include #include "testfilepaths.h" //Include all used json tests, otherwise "Test not found" #include #include #include #include #include #include using namespace KDevelop; QTEST_MAIN(TestFiles) void TestFiles::initTestCase() { qputenv("KDEV_CLANG_JSON_TEST_RUN", "1"); qputenv("KDEV_CLANG_EXTRA_ARGUMENTS", "-Wno-unused-variable -Wno-unused-parameter -Wno-unused-comparison -Wno-unused-value -Wno-unused-private-field -Wno-ignored-attributes"); QLoggingCategory::setFilterRules(QStringLiteral("*.debug=false\ndefault.debug=true\nkdevelop.plugins.clang.debug=true\n")); QVERIFY(qputenv("KDEV_DISABLE_PLUGINS", "kdevcppsupport")); QVERIFY(qputenv("KDEV_CLANG_DISPLAY_DIAGS", "1")); AutoTestShell::init({"kdevclangsupport"}); TestCore::initialize(Core::NoUi); DUChain::self()->disablePersistentStorage(); Core::self()->languageController()->backgroundParser()->setDelay(0); CodeRepresentation::setDiskChangesForbidden(true); } void TestFiles::cleanupTestCase() { TestCore::shutdown(); } void TestFiles::testFiles_data() { QTest::addColumn("fileName"); const QString testDirPath = TEST_FILES_DIR; - const QStringList files = QDir(testDirPath).entryList({"*.h", "*.cpp", "*.c", "*.cl"}, QDir::Files); + const QStringList files = QDir(testDirPath).entryList({"*.h", "*.cpp", "*.c", "*.cl", "*.cu"}, QDir::Files); foreach (const QString& file, files) { QTest::newRow(file.toUtf8().constData()) << QString(testDirPath + '/' + file); } } void TestFiles::testFiles() { QFETCH(QString, fileName); const IndexedString indexedFileName(fileName); ReferencedTopDUContext top = DUChain::self()->waitForUpdate(indexedFileName, TopDUContext::AllDeclarationsContextsAndUses); QVERIFY(top); DUChainReadLocker lock; DeclarationValidator validator; top->visit(validator); QVERIFY(validator.testsPassed()); foreach(auto problem, top->problems()) { qDebug() << problem; } if (!QTest::currentDataTag() || strcmp("invalid.cpp", QTest::currentDataTag()) != 0) { QVERIFY(top->problems().isEmpty()); } } diff --git a/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.cpp b/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.cpp index 0aa37d99dc..171644af7c 100644 --- a/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.cpp +++ b/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.cpp @@ -1,422 +1,429 @@ /* * This file is part of KDevelop * * Copyright 2010 Andreas Pakulat * Copyright 2014 Sergey Kalinichev * * 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 "settingsmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include "compilerprovider.h" using namespace KDevelop; namespace { namespace ConfigConstants { const QString configKey = QLatin1String( "CustomDefinesAndIncludes" ); const QString definesKey = QLatin1String( "Defines" ); const QString includesKey = QLatin1String( "Includes" ); const QString projectPathPrefix = QLatin1String( "ProjectPath" ); const QString projectPathKey = QLatin1String( "Path" ); const QString customBuildSystemGroup = QLatin1String( "CustomBuildSystem" ); const QString definesAndIncludesGroup = QLatin1String( "Defines And Includes" ); const QString compilersGroup = QLatin1String( "Compilers" ); const QString compilerNameKey = QLatin1String( "Name" ); const QString compilerPathKey = QLatin1String( "Path" ); const QString compilerTypeKey = QLatin1String( "Type" ); QString parserArgumentsCPP() { return QStringLiteral("parserArguments"); } QString parserArgumentsC() { return QStringLiteral("parserArgumentsC"); } QString parseAmbiguousAsCPP() { return QStringLiteral("parseAmbiguousAsCPP"); } } // the grouplist is randomly sorted b/c it uses QSet internally // we sort the keys here, as the structure is properly defined for us QStringList sorted(QStringList list) { std::sort(list.begin(), list.end()); return list; } ParserArguments defaultArguments() { const static ParserArguments arguments{ QStringLiteral("-ferror-limit=100 -fspell-checking -Wdocumentation -Wunused-parameter -Wunreachable-code -Wall -std=c99"), QStringLiteral("-ferror-limit=100 -fspell-checking -Wdocumentation -Wunused-parameter -Wunreachable-code -Wall -std=c++11"), - QStringLiteral("-ferror-limit=100 -fspell-checking -Wdocumentation -Wunused-parameter -Wunreachable-code -Wall"), + QStringLiteral("-ferror-limit=100 -fspell-checking -Wdocumentation -Wunused-parameter -Wunreachable-code -Wall -std=c++11"), + QStringLiteral("-ferror-limit=100 -fspell-checking -Wdocumentation -Wunused-parameter -Wunreachable-code -Wall -std=c++11"), true }; return arguments; } CompilerPointer createCompilerFromConfig(KConfigGroup& cfg) { auto grp = cfg.group("Compiler"); auto name = grp.readEntry( ConfigConstants::compilerNameKey, QString() ); if (name.isEmpty()) { return SettingsManager::globalInstance()->provider()->checkCompilerExists({}); } for (auto c : SettingsManager::globalInstance()->provider()->compilers()) { if (c->name() == name) { return c; } } // Otherwise we have no such compiler registered (broken config file), return default one return SettingsManager::globalInstance()->provider()->checkCompilerExists({}); } void writeCompilerToConfig(KConfigGroup& cfg, const CompilerPointer& compiler) { Q_ASSERT(compiler); auto grp = cfg.group("Compiler"); // Store only compiler name, path and type retrieved from registered compilers grp.writeEntry(ConfigConstants::compilerNameKey, compiler->name()); } void doWriteSettings( KConfigGroup grp, const QVector& paths ) { int pathIndex = 0; for ( const auto& path : paths ) { KConfigGroup pathgrp = grp.group( ConfigConstants::projectPathPrefix + QString::number( pathIndex++ ) ); pathgrp.writeEntry(ConfigConstants::projectPathKey, path.path); pathgrp.writeEntry(ConfigConstants::parserArgumentsCPP(), path.parserArguments.cppArguments); pathgrp.writeEntry(ConfigConstants::parserArgumentsC(), path.parserArguments.cArguments); pathgrp.writeEntry(ConfigConstants::parseAmbiguousAsCPP(), path.parserArguments.parseAmbiguousAsCPP); { int index = 0; KConfigGroup includes(pathgrp.group(ConfigConstants::includesKey)); for( auto it = path.includes.begin() ; it != path.includes.end(); ++it){ includes.writeEntry(QString::number(++index), *it); } } { KConfigGroup defines(pathgrp.group(ConfigConstants::definesKey)); for (auto it = path.defines.begin(); it != path.defines.end(); ++it) { defines.writeEntry(it.key(), it.value()); } } writeCompilerToConfig(pathgrp, path.compiler); } } /// @param remove if true all read entries will be removed from the config file QVector doReadSettings( KConfigGroup grp, bool remove = false ) { QVector paths; for( const QString &grpName : sorted(grp.groupList()) ) { if ( !grpName.startsWith( ConfigConstants::projectPathPrefix ) ) { continue; } KConfigGroup pathgrp = grp.group( grpName ); ConfigEntry path; path.path = pathgrp.readEntry( ConfigConstants::projectPathKey, "" ); path.parserArguments.cppArguments = pathgrp.readEntry(ConfigConstants::parserArgumentsCPP(), defaultArguments().cppArguments); path.parserArguments.cArguments = pathgrp.readEntry(ConfigConstants::parserArgumentsC(), defaultArguments().cArguments); path.parserArguments.parseAmbiguousAsCPP = pathgrp.readEntry(ConfigConstants::parseAmbiguousAsCPP(), defaultArguments().parseAmbiguousAsCPP); if (path.parserArguments.cppArguments.isEmpty()) { path.parserArguments.cppArguments = defaultArguments().cppArguments; } if (path.parserArguments.cArguments.isEmpty()) { path.parserArguments.cArguments = defaultArguments().cArguments; } { // defines // Backwards compatibility with old config style if(pathgrp.hasKey(ConfigConstants::definesKey)) { QByteArray tmp = pathgrp.readEntry( ConfigConstants::definesKey, QByteArray() ); QDataStream s( tmp ); s.setVersion( QDataStream::Qt_4_5 ); // backwards compatible reading QHash defines; s >> defines; path.setDefines(defines); } else { KConfigGroup defines(pathgrp.group(ConfigConstants::definesKey)); QMap defMap = defines.entryMap(); path.defines.reserve(defMap.size()); for(auto it = defMap.constBegin(); it != defMap.constEnd(); ++it) { QString key = it.key(); if(key.isEmpty()) { // Toss out the invalid key and value since a valid // value needs a valid key continue; } else { path.defines.insert(key, it.value()); } } } } { // includes // Backwards compatibility with old config style if(pathgrp.hasKey(ConfigConstants::includesKey)){ QByteArray tmp = pathgrp.readEntry( ConfigConstants::includesKey, QByteArray() ); QDataStream s( tmp ); s.setVersion( QDataStream::Qt_4_5 ); s >> path.includes; } else { KConfigGroup includes(pathgrp.group(ConfigConstants::includesKey)); QMap incMap = includes.entryMap(); for(auto it = incMap.begin(); it != incMap.end(); ++it){ QString value = it.value(); if(value.isEmpty()){ continue; } path.includes += value; } } } path.compiler = createCompilerFromConfig(pathgrp); if ( remove ) { pathgrp.deleteGroup(); } Q_ASSERT(!path.parserArguments.cppArguments.isEmpty()); Q_ASSERT(!path.parserArguments.cArguments.isEmpty()); paths << path; } return paths; } /** * Reads and converts paths from old (Custom Build System's) format to the current one. * @return all converted paths (if any) */ QVector convertedPaths( KConfig* cfg ) { KConfigGroup group = cfg->group( ConfigConstants::customBuildSystemGroup ); if ( !group.isValid() ) return {}; QVector paths; foreach( const QString &grpName, sorted(group.groupList()) ) { KConfigGroup subgroup = group.group( grpName ); if ( !subgroup.isValid() ) continue; paths += doReadSettings( subgroup, true ); } return paths; } } void ConfigEntry::setDefines(const QHash& newDefines) { defines.clear(); defines.reserve(newDefines.size()); for (auto it = newDefines.begin(); it != newDefines.end(); ++it) { defines[it.key()] = it.value().toString(); } } SettingsManager::SettingsManager() : m_provider(this) {} SettingsManager::~SettingsManager() {} SettingsManager* SettingsManager::globalInstance() { Q_ASSERT(QThread::currentThread() == qApp->thread()); static SettingsManager s_globalInstance; return &s_globalInstance; } CompilerProvider* SettingsManager::provider() { return &m_provider; } const CompilerProvider* SettingsManager::provider() const { return &m_provider; } void SettingsManager::writePaths( KConfig* cfg, const QVector< ConfigEntry >& paths ) { Q_ASSERT(QThread::currentThread() == qApp->thread()); KConfigGroup grp = cfg->group( ConfigConstants::configKey ); if ( !grp.isValid() ) return; grp.deleteGroup(); doWriteSettings( grp, paths ); } QVector SettingsManager::readPaths( KConfig* cfg ) const { Q_ASSERT(QThread::currentThread() == qApp->thread()); auto converted = convertedPaths( cfg ); if ( !converted.isEmpty() ) { const_cast(this)->writePaths( cfg, converted ); return converted; } KConfigGroup grp = cfg->group( ConfigConstants::configKey ); if ( !grp.isValid() ) { return {}; } return doReadSettings( grp ); } bool SettingsManager::needToReparseCurrentProject( KConfig* cfg ) const { auto grp = cfg->group( ConfigConstants::definesAndIncludesGroup ); return grp.readEntry( "reparse", true ); } void SettingsManager::writeUserDefinedCompilers(const QVector< CompilerPointer >& compilers) { QVector< CompilerPointer > editableCompilers; for (const auto& compiler : compilers) { if (!compiler->editable()) { continue; } editableCompilers.append(compiler); } KConfigGroup config = KSharedConfig::openConfig()->group(ConfigConstants::compilersGroup); config.deleteGroup(); config.writeEntry("number", editableCompilers.count()); int i = 0; for (const auto& compiler : editableCompilers) { KConfigGroup grp = config.group(QString::number(i)); ++i; grp.writeEntry(ConfigConstants::compilerNameKey, compiler->name()); grp.writeEntry(ConfigConstants::compilerPathKey, compiler->path()); grp.writeEntry(ConfigConstants::compilerTypeKey, compiler->factoryName()); } config.sync(); } QVector< CompilerPointer > SettingsManager::userDefinedCompilers() const { QVector< CompilerPointer > compilers; KConfigGroup config = KSharedConfig::openConfig()->group(ConfigConstants::compilersGroup); int count = config.readEntry("number", 0); for (int i = 0; i < count; i++) { KConfigGroup grp = config.group(QString::number(i)); auto name = grp.readEntry(ConfigConstants::compilerNameKey, QString()); auto path = grp.readEntry(ConfigConstants::compilerPathKey, QString()); auto type = grp.readEntry(ConfigConstants::compilerTypeKey, QString()); auto cf = m_provider.compilerFactories(); for (auto f : cf) { if (f->name() == type) { auto compiler = f->createCompiler(name, path); compilers.append(compiler); } } } return compilers; } ParserArguments SettingsManager::defaultParserArguments() const { return defaultArguments(); } ConfigEntry::ConfigEntry(const QString& path) : path(path) , compiler(SettingsManager::globalInstance()->provider()->checkCompilerExists({})) , parserArguments(defaultArguments()) {} namespace Utils { LanguageType languageType(const KDevelop::Path& path, bool treatAmbiguousAsCPP) { QMimeDatabase db; const auto mimeType = db.mimeTypeForFile(path.path()).name(); if (mimeType == QStringLiteral("text/x-csrc") || mimeType == QStringLiteral("text/x-chdr") ) { if (treatAmbiguousAsCPP) { if (path.lastPathSegment().endsWith(QLatin1String(".h"), Qt::CaseInsensitive)) { return Cpp; } } // TODO: No proper mime type detection possible yet // cf. https://bugs.freedesktop.org/show_bug.cgi?id=26913 if (path.lastPathSegment().endsWith(QLatin1String(".cl"), Qt::CaseInsensitive)) { return OpenCl; } + // TODO: No proper mime type detection possible yet + // cf. https://bugs.freedesktop.org/show_bug.cgi?id=23700 + if (path.lastPathSegment().endsWith(QLatin1String(".cu"), Qt::CaseInsensitive)) { + return Cuda; + } + return C; } if (mimeType == QStringLiteral("text/x-c++src") || mimeType == QStringLiteral("text/x-c++hdr") ) { return Cpp; } if (mimeType == QStringLiteral("text/x-objcsrc")) { return ObjC; } return Other; } } diff --git a/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.h b/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.h index 5a68229b71..32867b4385 100644 --- a/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.h +++ b/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.h @@ -1,103 +1,105 @@ /* * This file is part of KDevelop * * Copyright 2014 Sergey Kalinichev * * 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 SETTINGSMANAGER_H #define SETTINGSMANAGER_H #include "../idefinesandincludesmanager.h" #include "compilerprovider.h" #include "icompiler.h" #include class KConfig; namespace KDevelop { class IProject; class ProjectBaseItem; } struct ParserArguments { QString cArguments; QString cppArguments; QString openClArguments; + QString cudaArguments; bool parseAmbiguousAsCPP; }; Q_DECLARE_METATYPE(ParserArguments); struct ConfigEntry { QString path; QStringList includes; KDevelop::Defines defines; CompilerPointer compiler; ParserArguments parserArguments; explicit ConfigEntry( const QString& path = QString() ); // FIXME: get rid of this but stay backwards compatible void setDefines(const QHash& defines); }; namespace Utils { enum LanguageType { C, Cpp, OpenCl, + Cuda, ObjC, Other = 100 }; LanguageType languageType(const KDevelop::Path& path, bool treatAmbiguousAsCPP = true); } class SettingsManager { public: ~SettingsManager(); QVector readPaths(KConfig* cfg) const; void writePaths(KConfig* cfg, const QVector& paths); QVector userDefinedCompilers() const; void writeUserDefinedCompilers(const QVector& compilers); bool needToReparseCurrentProject( KConfig* cfg ) const; ParserArguments defaultParserArguments() const; CompilerProvider* provider(); const CompilerProvider* provider() const; static SettingsManager* globalInstance(); private: SettingsManager(); CompilerProvider m_provider; }; #endif // SETTINGSMANAGER_H diff --git a/languages/plugins/custom-definesandincludes/definesandincludesmanager.cpp b/languages/plugins/custom-definesandincludes/definesandincludesmanager.cpp index 405fdd1d8b..057e28e646 100644 --- a/languages/plugins/custom-definesandincludes/definesandincludesmanager.cpp +++ b/languages/plugins/custom-definesandincludes/definesandincludesmanager.cpp @@ -1,391 +1,393 @@ /* * This file is part of KDevelop * * Copyright 2014 Sergey Kalinichev * * 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 "definesandincludesmanager.h" #include "kcm_widget/definesandincludesconfigpage.h" #include "compilerprovider/compilerprovider.h" #include "compilerprovider/widget/compilerswidget.h" #include "noprojectincludesanddefines/noprojectincludepathsmanager.h" #include #include #include #include #include #include #include #include #include using namespace KDevelop; namespace { ///@return: The ConfigEntry, with includes/defines from @p paths for all parent folders of @p item. static ConfigEntry findConfigForItem(QVector paths, const KDevelop::ProjectBaseItem* item) { ConfigEntry ret; const Path itemPath = item->path(); const Path rootDirectory = item->project()->path(); Path closestPath; std::sort(paths.begin(), paths.end(), [] (const ConfigEntry& lhs, const ConfigEntry& rhs) { // sort in reverse order to do a bottom-up search return lhs.path > rhs.path; }); for (const ConfigEntry & entry : paths) { Path targetDirectory = rootDirectory; // note: a dot represents the project root if (entry.path != ".") { targetDirectory.addPath(entry.path); } if (targetDirectory == itemPath || targetDirectory.isParentOf(itemPath)) { ret.includes += entry.includes; for (auto it = entry.defines.constBegin(); it != entry.defines.constEnd(); it++) { if (!ret.defines.contains(it.key())) { ret.defines[it.key()] = it.value(); } } if (targetDirectory.segments().size() > closestPath.segments().size()) { ret.parserArguments = entry.parserArguments; closestPath = targetDirectory; } } } ret.includes.removeDuplicates(); Q_ASSERT(!ret.parserArguments.cppArguments.isEmpty()); Q_ASSERT(!ret.parserArguments.cArguments.isEmpty()); return ret; } void merge(Defines* target, const Defines& source) { if (target->isEmpty()) { *target = source; return; } for (auto it = source.constBegin(); it != source.constEnd(); ++it) { target->insert(it.key(), it.value()); } } QString argumentsForPath(const Path& path, const ParserArguments& arguments) { auto languageType = Utils::languageType(path, arguments.parseAmbiguousAsCPP); switch (languageType) { case Utils::C: return arguments.cArguments; case Utils::Cpp: return arguments.cppArguments; case Utils::OpenCl: return arguments.openClArguments; + case Utils::Cuda: + return arguments.cudaArguments; case Utils::ObjC: return QString(); case Utils::Other: return QString(); } Q_UNREACHABLE(); return QString(); } } K_PLUGIN_FACTORY_WITH_JSON(DefinesAndIncludesManagerFactory, "kdevdefinesandincludesmanager.json", registerPlugin(); ) DefinesAndIncludesManager::DefinesAndIncludesManager( QObject* parent, const QVariantList& ) : IPlugin("kdevdefinesandincludesmanager", parent ) , m_settings(SettingsManager::globalInstance()) , m_noProjectIPM(new NoProjectIncludePathsManager()) { registerProvider(m_settings->provider()); #ifdef Q_OS_OSX m_defaultFrameworkDirectories += Path(QStringLiteral("/Library/Frameworks")); m_defaultFrameworkDirectories += Path(QStringLiteral("/System/Library/Frameworks")); #endif } DefinesAndIncludesManager::~DefinesAndIncludesManager() = default; Defines DefinesAndIncludesManager::defines( ProjectBaseItem* item, Type type ) const { Q_ASSERT(QThread::currentThread() == qApp->thread()); if (!item) { return m_settings->provider()->defines(nullptr); } Defines defines; for (auto provider : m_providers) { if (provider->type() & type) { merge(&defines, provider->defines(item)); } } if ( type & ProjectSpecific ) { auto buildManager = item->project()->buildSystemManager(); if ( buildManager ) { merge(&defines, buildManager->defines(item)); } } // Manually set defines have the highest priority and overwrite values of all other types of defines. if (type & UserDefined) { auto cfg = item->project()->projectConfiguration().data(); merge(&defines, findConfigForItem(m_settings->readPaths(cfg), item).defines); } merge(&defines, m_noProjectIPM->includesAndDefines(item->path().path()).second); return defines; } Path::List DefinesAndIncludesManager::includes( ProjectBaseItem* item, Type type ) const { Q_ASSERT(QThread::currentThread() == qApp->thread()); if (!item) { return m_settings->provider()->includes(nullptr); } Path::List includes; if (type & UserDefined) { auto cfg = item->project()->projectConfiguration().data(); includes += KDevelop::toPathList(findConfigForItem(m_settings->readPaths(cfg), item).includes); } if ( type & ProjectSpecific ) { auto buildManager = item->project()->buildSystemManager(); if ( buildManager ) { includes += buildManager->includeDirectories(item); } } for (auto provider : m_providers) { if ( !(provider->type() & type) ) { continue; } auto newItems = provider->includes(item); if ( provider->type() & DefinesAndIncludesManager::CompilerSpecific ) { // If an item occurs in the "compiler specific" list, but was previously supplied // in the user include path list already, remove it from there. // Re-ordering the system include paths causes confusion in some cases. Q_FOREACH (const auto& x, newItems ) { includes.removeAll(x); } } includes += newItems; } includes += m_noProjectIPM->includesAndDefines(item->path().path()).first; return includes; } Path::List DefinesAndIncludesManager::frameworkDirectories( ProjectBaseItem* item, Type type ) const { Q_ASSERT(QThread::currentThread() == qApp->thread()); if (!item) { return m_settings->provider()->frameworkDirectories(nullptr); } Path::List frameworkDirectories = m_defaultFrameworkDirectories; if ( type & ProjectSpecific ) { auto buildManager = item->project()->buildSystemManager(); if ( buildManager ) { frameworkDirectories += buildManager->frameworkDirectories(item); } } for (auto provider : m_providers) { if (provider->type() & type) { frameworkDirectories += provider->frameworkDirectories(item); } } return frameworkDirectories; } bool DefinesAndIncludesManager::unregisterProvider(IDefinesAndIncludesManager::Provider* provider) { int idx = m_providers.indexOf(provider); if (idx != -1) { m_providers.remove(idx); return true; } return false; } void DefinesAndIncludesManager::registerProvider(IDefinesAndIncludesManager::Provider* provider) { Q_ASSERT(provider); if (m_providers.contains(provider)) { return; } m_providers.push_back(provider); } Defines DefinesAndIncludesManager::defines(const QString& path) const { Defines ret = m_settings->provider()->defines(nullptr); merge(&ret, m_noProjectIPM->includesAndDefines(path).second); return ret; } Path::List DefinesAndIncludesManager::includes(const QString& path) const { return m_settings->provider()->includes(nullptr) + m_noProjectIPM->includesAndDefines(path).first; } Path::List DefinesAndIncludesManager::frameworkDirectories(const QString& /* path */) const { return m_settings->provider()->frameworkDirectories(nullptr); } void DefinesAndIncludesManager::openConfigurationDialog(const QString& pathToFile) { if (auto project = KDevelop::ICore::self()->projectController()->findProjectForUrl(QUrl::fromLocalFile(pathToFile))) { KDevelop::ICore::self()->projectController()->configureProject(project); } else { m_noProjectIPM->openConfigurationDialog(pathToFile); } } Path::List DefinesAndIncludesManager::includesInBackground(const QString& path) const { Path::List includes; for (auto provider: m_backgroundProviders) { includes += provider->includesInBackground(path); } return includes; } Path::List DefinesAndIncludesManager::frameworkDirectoriesInBackground(const QString& path) const { Path::List fwDirs; for (auto provider: m_backgroundProviders) { fwDirs += provider->frameworkDirectoriesInBackground(path); } return fwDirs; } Defines DefinesAndIncludesManager::definesInBackground(const QString& path) const { QHash defines; for (auto provider: m_backgroundProviders) { auto result = provider->definesInBackground(path); for (auto it = result.constBegin(); it != result.constEnd(); it++) { defines[it.key()] = it.value(); } } merge(&defines, m_noProjectIPM->includesAndDefines(path).second); return defines; } bool DefinesAndIncludesManager::unregisterBackgroundProvider(IDefinesAndIncludesManager::BackgroundProvider* provider) { int idx = m_backgroundProviders.indexOf(provider); if (idx != -1) { m_backgroundProviders.remove(idx); return true; } return false; } void DefinesAndIncludesManager::registerBackgroundProvider(IDefinesAndIncludesManager::BackgroundProvider* provider) { Q_ASSERT(provider); if (m_backgroundProviders.contains(provider)) { return; } m_backgroundProviders.push_back(provider); } QString DefinesAndIncludesManager::parserArguments(KDevelop::ProjectBaseItem* item) const { Q_ASSERT(item); Q_ASSERT(QThread::currentThread() == qApp->thread()); auto cfg = item->project()->projectConfiguration().data(); const auto arguments = findConfigForItem(m_settings->readPaths(cfg), item).parserArguments; return argumentsForPath(item->path(), arguments); } QString DefinesAndIncludesManager::parserArguments(const QString& path) const { const auto args = m_settings->defaultParserArguments(); return argumentsForPath(Path(path), args); } int DefinesAndIncludesManager::perProjectConfigPages() const { return 1; } ConfigPage* DefinesAndIncludesManager::perProjectConfigPage(int number, const ProjectConfigOptions& options, QWidget* parent) { if (number == 0) { return new DefinesAndIncludesConfigPage(this, options, parent); } return nullptr; } KDevelop::ConfigPage* DefinesAndIncludesManager::configPage(int number, QWidget* parent) { return number == 0 ? new CompilersWidget(parent) : nullptr; } int DefinesAndIncludesManager::configPages() const { return 1; } #include "definesandincludesmanager.moc" diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.cpp b/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.cpp index d794301494..8bde0b3251 100644 --- a/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.cpp +++ b/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.cpp @@ -1,163 +1,196 @@ /* * This file is part of KDevelop * * Copyright 2015 Sergey Kalinichev * * 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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, see . * */ #include "parserwidget.h" #include "ui_parserwidget.h" #include "compilerprovider/settingsmanager.h" #include namespace { QString languageStandard(const QString& arguments) { int idx = arguments.indexOf("-std="); if(idx == -1){ return QStringLiteral("c++11"); } idx += 5; int end = arguments.indexOf(' ', idx) != -1 ? arguments.indexOf(' ', idx) : arguments.size(); return arguments.mid(idx, end - idx); } bool isCustomParserArguments(const QString& arguments, const QStringList& standards) { const auto defaultArguments = SettingsManager::globalInstance()->defaultParserArguments(); auto standard = languageStandard(arguments); auto tmpArgs(arguments); tmpArgs.replace(standard, "c++11"); if (tmpArgs == defaultArguments.cppArguments && standards.contains(standard)) { return false; } return true; } const int customProfileIdx = 0; } ParserWidget::ParserWidget(QWidget* parent) : QWidget(parent) , m_ui(new Ui::ParserWidget()) { m_ui->setupUi(this); connect(m_ui->parserOptionsC, &QLineEdit::textEdited, this, &ParserWidget::textEdited); connect(m_ui->parserOptionsCpp, &QLineEdit::textEdited, this, &ParserWidget::textEdited); + connect(m_ui->parserOptionsOpenCl, &QLineEdit::textEdited, this, &ParserWidget::textEdited); + connect(m_ui->parserOptionsCuda, &QLineEdit::textEdited, this, &ParserWidget::textEdited); connect(m_ui->parseHeadersInPlainC, &QCheckBox::stateChanged, this, &ParserWidget::textEdited); - connect(m_ui->languageStandardsC, static_cast(&QComboBox::activated), this, -&ParserWidget::languageStandardChangedC); - connect(m_ui->languageStandardsCpp, static_cast(&QComboBox::activated), this, -&ParserWidget::languageStandardChangedCpp); + connect(m_ui->languageStandardsC, static_cast(&QComboBox::activated), + this, &ParserWidget::languageStandardChangedC); + connect(m_ui->languageStandardsCpp, static_cast(&QComboBox::activated), + this, &ParserWidget::languageStandardChangedCpp); + connect(m_ui->languageStandardsOpenCl, static_cast(&QComboBox::activated), + this, &ParserWidget::languageStandardChangedOpenCl); + connect(m_ui->languageStandardsCuda, static_cast(&QComboBox::activated), + this, &ParserWidget::languageStandardChangedCuda); updateEnablements(); } ParserWidget::~ParserWidget() = default; void ParserWidget::textEdited() { emit changed(); } void ParserWidget::languageStandardChangedC(const QString& standard) { if (m_ui->languageStandardsC->currentIndex() == customProfileIdx) { m_ui->parserOptionsC->setText(SettingsManager::globalInstance()->defaultParserArguments().cArguments); } else { auto text = SettingsManager::globalInstance()->defaultParserArguments().cArguments; auto currentStandard = languageStandard(text); m_ui->parserOptionsC->setText(text.replace(currentStandard, standard)); } textEdited(); updateEnablements(); } void ParserWidget::languageStandardChangedCpp(const QString& standard) { if (m_ui->languageStandardsCpp->currentIndex() == customProfileIdx) { m_ui->parserOptionsCpp->setText(SettingsManager::globalInstance()->defaultParserArguments().cppArguments); } else { auto text = SettingsManager::globalInstance()->defaultParserArguments().cppArguments; auto currentStandard = languageStandard(text); m_ui->parserOptionsCpp->setText(text.replace(currentStandard, standard)); } textEdited(); updateEnablements(); } +void ParserWidget::languageStandardChangedOpenCl(const QString& standard) +{ + if (m_ui->languageStandardsOpenCl->currentIndex() == customProfileIdx) { + m_ui->parserOptionsOpenCl->setText(SettingsManager::globalInstance()->defaultParserArguments().openClArguments); + } else { + auto text = SettingsManager::globalInstance()->defaultParserArguments().openClArguments; + auto currentStandard = languageStandard(text); + m_ui->parserOptionsOpenCl->setText(text.replace(currentStandard, standard)); + } + + textEdited(); + updateEnablements(); +} + +void ParserWidget::languageStandardChangedCuda(const QString& standard) +{ + if (m_ui->languageStandardsCuda->currentIndex() == customProfileIdx) { + m_ui->parserOptionsCuda->setText(SettingsManager::globalInstance()->defaultParserArguments().cudaArguments); + } else { + auto text = SettingsManager::globalInstance()->defaultParserArguments().cudaArguments; + auto currentStandard = languageStandard(text); + m_ui->parserOptionsCuda->setText(text.replace(currentStandard, standard)); + } + + textEdited(); + updateEnablements(); +} + void ParserWidget::setParserArguments(const ParserArguments& arguments) { auto setArguments = [this](QComboBox* languageStandards, QLineEdit* parserOptions, const QString& arguments) { QStringList standards; for (int i = 1; i < languageStandards->count(); i++) { standards << languageStandards->itemText(i); } if (isCustomParserArguments(arguments, standards)) { languageStandards->setCurrentIndex(customProfileIdx); } else { languageStandards->setCurrentText(languageStandard(arguments)); } parserOptions->setText(arguments); }; setArguments(m_ui->languageStandardsCpp, m_ui->parserOptionsCpp, arguments.cppArguments); setArguments(m_ui->languageStandardsC, m_ui->parserOptionsC, arguments.cArguments); + setArguments(m_ui->languageStandardsOpenCl, m_ui->parserOptionsOpenCl, arguments.openClArguments); + setArguments(m_ui->languageStandardsCuda, m_ui->parserOptionsCuda, arguments.cudaArguments); m_ui->parseHeadersInPlainC->setChecked(!arguments.parseAmbiguousAsCPP); updateEnablements(); } ParserArguments ParserWidget::parserArguments() const { - return {m_ui->parserOptionsC->text(), m_ui->parserOptionsCpp->text(), {}, !m_ui->parseHeadersInPlainC->isChecked()}; + return { + m_ui->parserOptionsC->text(), + m_ui->parserOptionsCpp->text(), + m_ui->parserOptionsOpenCl->text(), + m_ui->parserOptionsCuda->text(), + !m_ui->parseHeadersInPlainC->isChecked() + }; } void ParserWidget::updateEnablements() { - if (m_ui->languageStandardsCpp->currentIndex() == customProfileIdx) { - m_ui->parserOptionsCpp->setEnabled(true); - } else { - m_ui->parserOptionsCpp->setEnabled(false); - } - - if (m_ui->languageStandardsC->currentIndex() == customProfileIdx) { - m_ui->parserOptionsC->setEnabled(true); - } else { - m_ui->parserOptionsC->setEnabled(false); - } + m_ui->parserOptionsCpp->setEnabled(m_ui->languageStandardsCpp->currentIndex() == customProfileIdx); + m_ui->parserOptionsC->setEnabled(m_ui->languageStandardsC->currentIndex() == customProfileIdx); + m_ui->parserOptionsOpenCl->setEnabled(m_ui->languageStandardsOpenCl->currentIndex() == customProfileIdx); + m_ui->parserOptionsCuda->setEnabled(m_ui->languageStandardsCuda->currentIndex() == customProfileIdx); } diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.h b/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.h index 0358852b96..cb8c8fc016 100644 --- a/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.h +++ b/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.h @@ -1,65 +1,67 @@ /* * This file is part of KDevelop * * Copyright 2015 Sergey Kalinichev * * 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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, see . * */ #ifndef PARSERWIDGET_H #define PARSERWIDGET_H #include #include namespace Ui { class ParserWidget; } namespace KDevelop { class IProject; } struct ParserArguments; class ParserWidget : public QWidget { Q_OBJECT public: explicit ParserWidget(QWidget* parent); ~ParserWidget() override; void setParserArguments(const ParserArguments& arguments); ParserArguments parserArguments() const; signals: void changed(); private slots: void textEdited(); void languageStandardChangedC(const QString& standard); void languageStandardChangedCpp(const QString& standard); + void languageStandardChangedOpenCl(const QString& standard); + void languageStandardChangedCuda(const QString& standard); void updateEnablements(); private: QScopedPointer m_ui; }; #endif // PARSERWIDGET_H diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.ui b/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.ui index 85d50b4227..99372550ee 100644 --- a/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.ui +++ b/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.ui @@ -1,219 +1,393 @@ ParserWidget 0 0 579 407 0 <html><head/><body><p>Check this if you want <code>*.h</code> headers to be parsed in plain C mode. By default they are parsed as C++ headers.</p></body></html> Parse *.h headers in plain C C++ Profi&le: languageStandardsCpp 0 0 100 0 <html><head/><body><p>Choose language profile. </p><p>Use &quot;Custom&quot; profile to modify parser command-line arguments</p></body></html> Custom c++03 c++11 c++14 c99 C++ co&mmand-line arguments: parserOptionsCpp 100 0 + + + + Qt::Vertical + + + + 20 + 40 + + + + C Profi&le: - languageStandardsCpp + languageStandardsC 0 0 100 0 <html><head/><body><p>Choose language profile. </p><p>Use &quot;Custom&quot; profile to modify parser command-line arguments</p></body></html> Custom c99 gnu99 c11 gnu11 c++11 C co&mmand-line arguments: parserOptionsC 100 0 - - + + Qt::Vertical 20 40 + + + + OpenCL &Profile: + + + languageStandardsOpenCl + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + <html><head/><body><p>Choose language profile. </p><p>Use &quot;Custom&quot; profile to modify parser command-line arguments</p></body></html> + + + + Custom + + + + + c++03 + + + + + c++11 + + + + + c++14 + + + + + c99 + + + + + + + + OpenCL comma&nd-line arguments: + + + parserOptionsOpenCl + + + + + + + + 100 + 0 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + CUDA C P&rofile: + + + languageStandardsCuda + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + <html><head/><body><p>Choose language profile. </p><p>Use &quot;Custom&quot; profile to modify parser command-line arguments</p></body></html> + + + + Custom + + + + + c++03 + + + + + c++11 + + + + + c++14 + + + + + c99 + + + + + + + + CUDA C comman&d-line arguments: + + + parserOptionsCuda + + + + + + + + 100 + 0 + + + + Qt::Vertical 20 406