Package: kdevelop Version: 4:4.0.1-1.1 Severity: normal Tags: squeeze Incorrect parse CMake FILE command if there is GLOB or GLOB_RECURSE, like this: FILE(GLOB_RECURSE SOURCES "../../../src/*.cpp" )
This issue is already fixed in 4.1.2 and 4.2 branches of kdevelop (http://git.reviewboard.kde.org/r/100283/) In attach patch witch fix this issue. It is little bit adapted to 4.0 branch. I test and use it :) Please commit it(or rework original patch) to testing :) -- System Information: Debian Release: 6.0 APT prefers testing APT policy: (500, 'testing'), (111, 'unstable'), (110, 'experimental') Architecture: amd64 (x86_64) Kernel: Linux 2.6.32-5-amd64 (SMP w/2 CPU cores) Locale: LANG=uk_UA.UTF-8, LC_CTYPE=uk_UA.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages kdevelop depends on: ii kdebase-runtime 4:4.4.5-1 runtime components from the offici ii kdevelop-data 4:4.0.1-1.1 data files for the KDevelop IDE ii kdevplatform1-libs 1.0.1-1 shared libraries for the KDevelop ii lcov 1.8-2 Summarise Code coverage informatio ii libc6 2.11.2-7 Embedded GNU C Library: Shared lib ii libgcc1 1:4.4.5-8 GCC support library ii libkdecore5 4:4.4.5-2 the KDE Platform Core Library ii libkdeui5 4:4.4.5-2 the KDE Platform User Interface Li ii libkio5 4:4.4.5-2 the Network-enabled File Managemen ii libkparts4 4:4.4.5-2 the Framework for the KDE Platform ii libktexteditor4 4:4.4.5-2 the KTextEditor interfaces for the ii libprocessui4a 4:4.4.5-6 library for ksysguard process user ii libqt4-dbus 4:4.6.3-4 Qt 4 D-Bus module ii libqt4-help 4:4.6.3-4 Qt 4 help module ii libqt4-network 4:4.6.3-4 Qt 4 network module ii libqt4-script 4:4.6.3-4 Qt 4 script module ii libqt4-webkit 4:4.6.3-4 Qt 4 WebKit module ii libqtcore4 4:4.6.3-4 Qt 4 core module ii libqtgui4 4:4.6.3-4 Qt 4 GUI module ii libstdc++6 4.4.5-8 The GNU Standard C++ Library v3 ii libsublime1 1.0.1-1 an user interface library ii libthreadweaver4 4:4.4.5-2 the ThreadWeaver Library for the K Versions of packages kdevelop recommends: ii gdb 7.0.1-2+b1 The GNU Debugger ii valgrind 1:3.6.0~svn11254+nmu1 A memory debugger and profiler Versions of packages kdevelop suggests: ii cmake 2.8.2-2 a cross-platform, open-source make ii kdevelop-l10n-uk [kdevelop-l 4:4.0.1-1.1 Ukrainian (uk) localization files -- no debconf information
diff --git a/projectmanagers/cmake/parser/cmakeast.cpp b/projectmanagers/cmake/parser/cmakeast.cpp index 7e40013..2b6bc5d 100644 --- a/projectmanagers/cmake/parser/cmakeast.cpp +++ b/projectmanagers/cmake/parser/cmakeast.cpp @@ -1080,9 +1080,26 @@ bool FileAst::parseFunctionInfo( const CMakeFunctionDesc& func ) addOutputArgument(func.arguments[2]); break; case Glob: + addOutputArgument(func.arguments[1]); + m_variable = func.arguments[1].value; + it=func.arguments.constBegin()+2; + itEnd=func.arguments.constEnd(); + + for(; it!=itEnd; ++it) { + if(it->value=="RELATIVE") { + it++; + if(it==itEnd) + return false; + else + m_path = it->value; + } else + m_globbingExpressions << it->value; + } + break; case GlobRecurse: addOutputArgument(func.arguments[1]); m_variable = func.arguments[1].value; + m_isFollowingSymlinks = false; it=func.arguments.constBegin()+2; itEnd=func.arguments.constEnd(); @@ -1093,6 +1110,8 @@ bool FileAst::parseFunctionInfo( const CMakeFunctionDesc& func ) return false; else m_path = it->value; + } else if(it->value=="FOLLOW_SYMLINKS") { + m_isFollowingSymlinks = true; } else m_globbingExpressions << it->value; } diff --git a/projectmanagers/cmake/parser/cmakeast.h b/projectmanagers/cmake/parser/cmakeast.h index 54a52d0..a305f7d 100644 --- a/projectmanagers/cmake/parser/cmakeast.h +++ b/projectmanagers/cmake/parser/cmakeast.h @@ -252,6 +252,7 @@ CMAKE_ADD_AST_MEMBER( QString, variable ) CMAKE_ADD_AST_MEMBER( QString, directory ) CMAKE_ADD_AST_MEMBER( QString, message ) CMAKE_ADD_AST_MEMBER( QStringList, globbingExpressions ) +CMAKE_ADD_AST_MEMBER( bool, isFollowingSymlinks ) CMAKE_ADD_AST_MEMBER( QStringList, directories ) CMAKE_ADD_AST_MEMBER( KUrl, url ) diff --git a/projectmanagers/cmake/parser/cmakedebugvisitor.cpp b/projectmanagers/cmake/parser/cmakedebugvisitor.cpp index 03a0d8c..09a6854 100644 --- a/projectmanagers/cmake/parser/cmakedebugvisitor.cpp +++ b/projectmanagers/cmake/parser/cmakedebugvisitor.cpp @@ -96,7 +96,7 @@ int CMakeAstDebugVisitor::visit( const MessageAst * ast ) int CMakeAstDebugVisitor::visit( const FileAst * ast ) { - WRITEOUT << "FILE: " << "(type,variable,directory,path,globbingExpressions,message,directories) = (" << ast->type() << "," << ast->variable() << "," << ast->directory() << "," << ast->path() << "," << ast->globbingExpressions() << "," << ast->message() << "," << ast->directories() << ")"; + WRITEOUT << "FILE: " << "(type,variable,directory,path,globbingExpressions,message,directories,followSymlinks) = (" << ast->type() << "," << ast->variable() << "," << ast->directory() << "," << ast->path() << "," << ast->globbingExpressions() << "," << ast->message() << "," << ast->directories() << "," << ast->isFollowingSymlinks() << ")"; return 1; } diff --git a/projectmanagers/cmake/parser/cmakeprojectvisitor.cpp b/projectmanagers/cmake/parser/cmakeprojectvisitor.cpp index e2f16d1..96bc00c 100644 --- a/projectmanagers/cmake/parser/cmakeprojectvisitor.cpp +++ b/projectmanagers/cmake/parser/cmakeprojectvisitor.cpp @@ -1396,53 +1396,52 @@ int CMakeProjectVisitor::visit(const FileAst *file) kDebug(9042) << "FileAst: read "; } break; - case FileAst::Glob: { + case FileAst::Glob: + case FileAst::GlobRecurse: { QStringList matches; - QString relative=file->path(); - foreach(const QString& glob, file->globbingExpressions()) + foreach(QString expr, file->globbingExpressions()) { - QStringList globs; - QString current; - if(KUrl::isRelativeUrl(glob)) { - KUrl urlGlob(glob); - current=urlGlob.upUrl().path(); - - globs.append(urlGlob.fileName()); - } else if(!relative.isEmpty()) { - current=relative; - globs.append(glob); - } else { - current=m_vars->value("CMAKE_CURRENT_SOURCE_DIR").first(); - globs.append(glob); - } - - QDir d(current); - matches+=d.entryList(globs, QDir::NoDotAndDotDot | QDir::AllEntries); + if (expr.isEmpty()) + continue; + QString startPath; + if (QDir::isRelativePath(expr)) + startPath = m_vars->value("CMAKE_CURRENT_SOURCE_DIR").first(); + // startPath must start from '/' if not empty when calling traverseRecursiveGlob() + if (expr[0] == '/') + { + //moving slash to startPath (it should be empty before) + expr = expr.mid(1); + startPath += '/'; + } + else + { + if (!startPath.isEmpty()) + startPath += '/'; + } + if (file->type() == FileAst::Glob) + { + matches.append(traverseGlob(startPath, expr)); + } + else + { + matches.append(traverseGlob(startPath, expr, true, file->isFollowingSymlinks())); + } } - m_vars->insert(file->variable(), matches); - kDebug(9042) << "file glob" << file->path() << file->globbingExpressions() << matches; - } break; - case FileAst::GlobRecurse: { - QString current; - if(file->path().isEmpty()) - current=m_vars->value("CMAKE_CURRENT_SOURCE_DIR").first(); - else - current=file->path(); - QQueue<QString> candidates; - candidates.enqueue(current); - QStringList directories; - while(!candidates.isEmpty()) - { - QString dir=candidates.dequeue(); - directories.append(dir); - QDir direc(dir); - candidates += direc.entryList(QDir::NoDotAndDotDot | QDir::Dirs); + if (!file->path().isEmpty()) + { + // RELATIVE was specified, so we need to make all paths relative to file->path() + QDir relative(file->path()); + QStringList::iterator endIt = matches.end(); + for(QStringList::iterator it = matches.begin(); it != endIt; ++it) + { + *it = relative.relativeFilePath(*it); + } } - - QDir d(current); - QStringList matches=d.entryList(file->globbingExpressions(), QDir::NoDotAndDotDot | QDir::AllEntries); m_vars->insert(file->variable(), matches); - kDebug(9042) << "file glob_recurse" << file->path() << file->globbingExpressions() << matches; + if (file->type() == FileAst::Glob) + kDebug(9042) << "file glob" << file->path() << file->globbingExpressions() << matches; + else + kDebug(9042) << "file glob_recurse" << file->path() << file->globbingExpressions() << matches; } break; case FileAst::Remove: case FileAst::RemoveRecurse: @@ -2237,3 +2236,90 @@ QStringList CMakeProjectVisitor::resolveDependencies(const QStringList & files) return ret; } +QStringList CMakeProjectVisitor::traverseGlob(const QString& startPath, + const QString& expression, bool recursive, bool followSymlinks) +{ + kDebug(9042) << "Starting from (" << startPath << ", " << expression << ", " << followSymlinks << ")"; + QString expr = expression; + int firstSlash = expr.indexOf('/'); + int slashShift = 0; + while (firstSlash == slashShift) + { + slashShift++; + firstSlash = expr.indexOf('/', slashShift); + } + expr = expr.mid(slashShift); + if (firstSlash == -1) + { + kDebug(9042) << "Matching files in " << startPath << " with glob " << expr; + //We're here. Lets match files from startPath dir. + QStringList nameFilters; + nameFilters << expr; + QStringList dirsToSearch; + if (recursive) + { + QDir::Filters dirFilters = QDir::NoDotAndDotDot | QDir::Dirs; + if (!followSymlinks) + dirFilters |= QDir::NoSymLinks; + QQueue<QString> dirsToExpand; + dirsToExpand.enqueue(startPath); + while (!dirsToExpand.empty()) + { + QString dir = dirsToExpand.dequeue(); + kDebug(9042) << "Enqueueing " << dir; + dirsToSearch << dir; + QDir d(dir); + QStringList dirNames = d.entryList(dirFilters); + foreach(QString dirName, dirNames) + { + dirsToExpand << d.filePath(dirName); + } + } + } + else + dirsToSearch << startPath; + QStringList filePaths; + foreach (QString dirToSearch, dirsToSearch) + { + QDir dir(dirToSearch); + QStringList fileNames; + fileNames = dir.entryList(nameFilters, QDir::Files); + foreach (QString fileName, fileNames) + { + filePaths << dir.filePath(fileName); + } + } + return filePaths; + } + firstSlash -= slashShift; + QString dirGlob = expr.left(firstSlash); + QString rightExpression = expr.mid(firstSlash + 1); + //Now we must find match for a directory specified in dirGlob + QStringList matchedDirs; + if (dirGlob.contains('*') || dirGlob.contains('?') || dirGlob.contains('[')) + { + kDebug(9042) << "Got a dir glob " << dirGlob; + if (startPath.isEmpty()) + return QStringList(); + //it's really a glob, not just dir name + QStringList nameFilters; + nameFilters << dirGlob; + matchedDirs = QDir(startPath).entryList(nameFilters, QDir::NoDotAndDotDot | QDir::Dirs); + } + else + { + //just a directory name. Add it as a match. + kDebug(9042) << "Got a simple folder " << dirGlob; + matchedDirs << dirGlob; + } + QStringList matches; + QString path = startPath; + if (!path.isEmpty() && !path.endsWith('/')) + path += '/'; + foreach(QString dirName, matchedDirs) + { + kDebug(9042) << "Going resursive into " << path + dirName << " and glob " << rightExpression; + matches.append(traverseGlob(path + dirName, rightExpression, recursive, followSymlinks)); + } + return matches; +} diff --git a/projectmanagers/cmake/parser/cmakeprojectvisitor.h b/projectmanagers/cmake/parser/cmakeprojectvisitor.h index a825d2b..63f82c9 100644 --- a/projectmanagers/cmake/parser/cmakeprojectvisitor.h +++ b/projectmanagers/cmake/parser/cmakeprojectvisitor.h @@ -175,6 +175,9 @@ class KDEVCMAKECOMMON_EXPORT CMakeProjectVisitor : CMakeAstVisitor QStringList dependees(const QString& s) const; int declareFunction(Macro m, const CMakeFileContent& content, int initial, const QString& end); + QStringList traverseGlob(const QString& startPath, const QString& expression, + bool recursive = false, bool followSymlinks = false); + CMakeProperties m_props; QStringList m_modulePath; QString m_projectName;