kde-extraapps/kdevelop/languages/plugins/custom-definesandincludes/compilerprovider/gcclikecompiler.cpp
2015-07-26 14:23:17 +03:00

141 lines
4.7 KiB
C++

/*
* This file is part of KDevelop
*
* Copyright 2014 Sergey Kalinichev <kalinichev.so.0@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "gcclikecompiler.h"
#include <QDir>
#include <QProcess>
#include <QRegExp>
#include "../debugarea.h"
#ifdef _WIN32
#define NULL_DEVICE "NUL"
#else
#define NULL_DEVICE "/dev/null"
#endif
using namespace KDevelop;
Defines GccLikeCompiler::defines() const
{
if (!m_definesIncludes.definedMacros.isEmpty() ) {
return m_definesIncludes.definedMacros;
}
// #define a 1
// #define a
QRegExp defineExpression( "#define\\s+(\\S+)(?:\\s+(.*)\\s*)?");
QProcess proc;
proc.setProcessChannelMode( QProcess::MergedChannels );
proc.start( path(), {"-std=c++11", "-xc++", "-dM", "-E", NULL_DEVICE} );
if ( !proc.waitForStarted( 1000 ) || !proc.waitForFinished( 1000 ) ) {
definesAndIncludesDebug() << "Unable to read standard macro definitions from "<< path();
return {};
}
while ( proc.canReadLine() ) {
auto line = proc.readLine();
if ( defineExpression.indexIn( line ) != -1 ) {
m_definesIncludes.definedMacros[defineExpression.cap( 1 )] = defineExpression.cap( 2 ).trimmed();
}
}
return m_definesIncludes.definedMacros;
}
Path::List GccLikeCompiler::includes() const
{
if ( !m_definesIncludes.includePaths.isEmpty() ) {
return m_definesIncludes.includePaths;
}
QProcess proc;
proc.setProcessChannelMode( QProcess::MergedChannels );
// The following command will spit out a bunch of information we don't care
// about before spitting out the include paths. The parts we care about
// look like this:
// #include "..." search starts here:
// #include <...> search starts here:
// /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2
// /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/i486-linux-gnu
// /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/backward
// /usr/local/include
// /usr/lib/gcc/i486-linux-gnu/4.1.2/include
// /usr/include
// End of search list.
proc.start( path(), {"-std=c++11", "-xc++", "-E", "-v", NULL_DEVICE} );
if ( !proc.waitForStarted( 1000 ) || !proc.waitForFinished( 1000 ) ) {
definesAndIncludesDebug() << "Unable to read standard include paths from " << path();
return {};
}
// We'll use the following constants to know what we're currently parsing.
enum Status {
Initial,
FirstSearch,
Includes,
Finished
};
Status mode = Initial;
foreach( const QString &line, QString::fromLocal8Bit( proc.readAllStandardOutput() ).split( '\n' ) ) {
switch ( mode ) {
case Initial:
if ( line.indexOf( "#include \"...\"" ) != -1 ) {
mode = FirstSearch;
}
break;
case FirstSearch:
if ( line.indexOf( "#include <...>" ) != -1 ) {
mode = Includes;
break;
}
case Includes:
//Detect the include-paths by the first space that is prepended. Reason: The list may contain relative paths like "."
if ( !line.startsWith( ' ' ) ) {
// We've reached the end of the list.
mode = Finished;
} else {
// This is an include path, add it to the list.
m_definesIncludes.includePaths << Path( QDir::cleanPath( line.trimmed() ) );
}
break;
default:
break;
}
if ( mode == Finished ) {
break;
}
}
return m_definesIncludes.includePaths;
}
GccLikeCompiler::GccLikeCompiler(const QString& name, const QString& path, bool editable, const QString& factoryName):
ICompiler(name, path, factoryName, editable)
{}