diff options
Diffstat (limited to 'automoc/kde4automoc.cpp')
-rw-r--r-- | automoc/kde4automoc.cpp | 345 |
1 files changed, 0 insertions, 345 deletions
diff --git a/automoc/kde4automoc.cpp b/automoc/kde4automoc.cpp deleted file mode 100644 index 68ccdbdb..00000000 --- a/automoc/kde4automoc.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 2007 Matthias Kretz <kretz@kde.org> - - 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 <QtCore/QCoreApplication> -#include <QtCore/QDateTime> -#include <QtCore/QFile> -#include <QtCore/QFileInfo> -#include <QtCore/QHash> -#include <QtCore/QProcess> -#include <QtCore/QQueue> -#include <QtCore/QRegExp> -#include <QtCore/QStringList> -#include <QtCore/QTextStream> -#include <QtCore/QtDebug> -#include <cstdlib> - -class AutoMoc -{ - public: - AutoMoc(); - bool run(); - - private: - void generateMoc(const QString &sourceFile, const QString &mocFileName); - void waitForProcesses(); - void usage(const QString &); - void echoColor(const QString &msg) - { - QProcess *cmakeEcho = new QProcess; - cmakeEcho->setProcessChannelMode(QProcess::ForwardedChannels); - QStringList args(cmakeEchoColorArgs); - args << msg; - cmakeEcho->start(QLatin1String("cmake"), args, QIODevice::NotOpen); - processes.enqueue(Process(cmakeEcho, QString())); - } - - QString builddir; - QString mocExe; - QStringList mocIncludes; - QStringList cmakeEchoColorArgs; - const bool verbose; - QTextStream cerr; - QTextStream cout; - struct Process - { - Process(QProcess *a, const QString &b) : qproc(a), mocFilePath(b) {} - QProcess *qproc; - QString mocFilePath; - }; - QQueue<Process> processes; - bool failed; -}; - -void AutoMoc::usage(const QString &path) -{ - cout << "usage: " << path << " <outfile> <srcdir> <builddir> <moc executable>" << endl; - ::exit(EXIT_FAILURE); -} - -int main(int argc, char **argv) -{ - QCoreApplication app(argc, argv); - if (!AutoMoc().run()) { - return EXIT_FAILURE; - } - return 0; -} - -AutoMoc::AutoMoc() - : verbose(!qgetenv("VERBOSE").isEmpty()), cerr(stderr), cout(stdout), failed(false) -{ - const QByteArray colorEnv = qgetenv("COLOR"); - cmakeEchoColorArgs << QLatin1String("-E") << QLatin1String("cmake_echo_color") - << QLatin1String("--switch=") + colorEnv << QLatin1String("--blue") - << QLatin1String("--bold"); -} - -bool AutoMoc::run() -{ - const QStringList args = QCoreApplication::arguments(); - Q_ASSERT(args.size() > 0); - if (args.size() < 4) { - usage(args[0]); - } - QFile outfile(args[1]); - const QFileInfo outfileInfo(outfile); - - QString srcdir(args[2]); - if (!srcdir.endsWith('/')) { - srcdir += '/'; - } - builddir = args[3]; - if (!builddir.endsWith('/')) { - builddir += '/'; - } - mocExe = args[4]; - - QFile dotFiles(args[1] + ".files"); - dotFiles.open(QIODevice::ReadOnly | QIODevice::Text); - QByteArray line = dotFiles.readLine(); - Q_ASSERT(line == "MOC_INCLUDES:\n"); - line = dotFiles.readLine().trimmed(); - const QStringList incPaths = QString::fromUtf8(line).split(';'); - foreach (const QString &path, incPaths) { - if (!path.isEmpty()) { - mocIncludes << "-I" + path; - } - } - line = dotFiles.readLine(); - Q_ASSERT(line == "SOURCES:\n"); - line = dotFiles.readLine().trimmed(); - dotFiles.close(); - const QStringList sourceFiles = QString::fromUtf8(line).split(';'); - - // the program goes through all .cpp files to see which moc files are included. It is not really - // interesting how the moc file is named, but what file the moc is created from. Once a moc is - // included the same moc may not be included in the _automoc.cpp file anymore. OTOH if there's a - // header containing Q_OBJECT where no corresponding moc file is included anywhere a - // moc_<filename>.cpp file is created and included in the _automoc.cpp file. - QHash<QString, QString> includedMocs; // key = moc source filepath, value = moc output filepath - QHash<QString, QString> notIncludedMocs; // key = moc source filepath, value = moc output filename - - QRegExp mocIncludeRegExp(QLatin1String("[\n]\\s*#\\s*include\\s+[\"<](moc_[^ \">]+\\.cpp|[^ \">]+\\.moc)[\">]")); - QRegExp qObjectRegExp(QLatin1String("[\n]\\s*Q_OBJECT\\b")); - QStringList headerExtensions; - headerExtensions << ".h" << ".hpp" << ".hxx" << ".H"; - foreach (const QString &absFilename, sourceFiles) { - //qDebug() << absFilename; - const QFileInfo sourceFileInfo(absFilename); - if (absFilename.endsWith(".cpp") || absFilename.endsWith(".cc") || - absFilename.endsWith(".cxx") || absFilename.endsWith(".C")) { - //qDebug() << "check .cpp file"; - QFile sourceFile(absFilename); - sourceFile.open(QIODevice::ReadOnly); - const QByteArray contents = sourceFile.readAll(); - if (contents.isEmpty()) { - cerr << "kde4automoc: empty source file: " << absFilename << endl; - continue; - } - const QString contentsString = QString::fromUtf8(contents); - const QString absPath = sourceFileInfo.absolutePath() + '/'; - Q_ASSERT(absPath.endsWith('/')); - int matchOffset = mocIncludeRegExp.indexIn(contentsString); - if (matchOffset < 0) { - // no moc #include, look whether we need to create a moc from the .h nevertheless - //qDebug() << "no moc #include in the .cpp file"; - const QString basename = sourceFileInfo.completeBaseName(); - const QString headername = absPath + basename + ".h"; - if (QFile::exists(headername) && !includedMocs.contains(headername) && - !notIncludedMocs.contains(headername)) { - const QString currentMoc = "moc_" + basename + ".cpp"; - QFile header(headername); - header.open(QIODevice::ReadOnly); - const QByteArray contents = header.readAll(); - if (qObjectRegExp.indexIn(QString::fromUtf8(contents)) >= 0) { - //qDebug() << "header contains Q_OBJECT macro"; - notIncludedMocs.insert(headername, currentMoc); - } - } - const QString privateHeaderName = absPath + basename + "_p.h"; - if (QFile::exists(privateHeaderName) && !includedMocs.contains(privateHeaderName) && - !notIncludedMocs.contains(privateHeaderName)) { - const QString currentMoc = "moc_" + basename + "_p.cpp"; - QFile header(privateHeaderName); - header.open(QIODevice::ReadOnly); - const QByteArray contents = header.readAll(); - if (qObjectRegExp.indexIn(QString::fromUtf8(contents)) >= 0) { - //qDebug() << "header contains Q_OBJECT macro"; - notIncludedMocs.insert(privateHeaderName, currentMoc); - } - } - } else { - do { // call this for every moc include in the file - const QString currentMoc = mocIncludeRegExp.cap(1); - //qDebug() << "found moc include: " << currentMoc << " at offset " << matchOffset; - QString basename = QFileInfo(currentMoc).completeBaseName(); - const bool moc_style = currentMoc.startsWith("moc_"); - if (moc_style || qObjectRegExp.indexIn(contentsString) < 0) { - if (moc_style) { - basename = basename.right(basename.length() - 4); - } - bool headerFound = false; - foreach (const QString &ext, headerExtensions) { - QString sourceFilePath = absPath + basename + ext; - if (QFile::exists(sourceFilePath)) { - headerFound = true; - includedMocs.insert(sourceFilePath, currentMoc); - notIncludedMocs.remove(sourceFilePath); - break; - } - } - if (!headerFound) { - cerr << "kde4automoc: The file \"" << absFilename << - "\" includes the moc file \"" << currentMoc << "\", but \"" << - absPath + basename + "{" + headerExtensions.join(",") + "}" << - "\" do not exist." << endl; - ::exit(EXIT_FAILURE); - } - } else { - includedMocs.insert(absFilename, currentMoc); - notIncludedMocs.remove(absFilename); - } - - matchOffset = mocIncludeRegExp.indexIn(contentsString, - matchOffset + currentMoc.length()); - } while(matchOffset >= 0); - } - } else if (absFilename.endsWith(".h") || absFilename.endsWith(".hpp") || - absFilename.endsWith(".hxx") || absFilename.endsWith(".H")) { - if (!includedMocs.contains(absFilename) && !notIncludedMocs.contains(absFilename)) { - // if this header is not getting processed yet and is explicitly mentioned for the - // automoc the moc is run unconditionally on the header and the resulting file is - // included in the _automoc.cpp file (unless there's a .cpp file later on that - // includes the moc from this header) - const QString currentMoc = "moc_" + sourceFileInfo.completeBaseName() + ".cpp"; - notIncludedMocs.insert(absFilename, currentMoc); - } - } else { - if (verbose) { - cout << "kde4automoc: ignoring file '" << absFilename << "' with unknown suffix" << endl; - } - } - } - - // run moc on all the moc's that are #included in source files - QHash<QString, QString>::ConstIterator end = includedMocs.constEnd(); - QHash<QString, QString>::ConstIterator it = includedMocs.constBegin(); - for (; it != end; ++it) { - generateMoc(it.key(), it.value()); - } - - QByteArray automocSource; - QTextStream outStream(&automocSource, QIODevice::WriteOnly); - outStream << "/* This file is autogenerated, do not edit */\n"; - - if (notIncludedMocs.isEmpty()) { - outStream << "enum some_compilers { need_more_than_nothing };\n"; - } else { - // run moc on the remaining headers and include them in the _automoc.cpp file - end = notIncludedMocs.constEnd(); - it = notIncludedMocs.constBegin(); - for (; it != end; ++it) { - generateMoc(it.key(), it.value()); - outStream << "#include \"" << it.value() << "\"\n"; - } - } - - // let all remaining moc processes finish - waitForProcesses(); - - if (failed) { - // if any moc process failed we don't want to touch the _automoc.cpp file so that - // kde4automoc is rerun until the issue is fixed - cerr << "returning failed.."<< endl; - return false; - } - outStream.flush(); - - // source file that includes all remaining moc files - outfile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate); - outfile.write(automocSource); - outfile.close(); - - return true; -} - -void AutoMoc::waitForProcesses() -{ - while (!processes.isEmpty()) { - Process proc = processes.dequeue(); - - bool result = proc.qproc->waitForFinished(-1); - //ignore errors from the cmake echo process - if (!proc.mocFilePath.isEmpty()) { - if (!result || proc.qproc->exitCode()) { - cerr << "kde4automoc: process for " << proc.mocFilePath - << " failed: " << proc.qproc->errorString() << endl; - cerr << "pid to wait for: " << proc.qproc->pid() << endl; - cerr << "processes in queue: " << processes.size() << endl; - failed = true; - QFile::remove(proc.mocFilePath); - } - } - delete proc.qproc; - } -} - -void AutoMoc::generateMoc(const QString &sourceFile, const QString &mocFileName) -{ - //qDebug() << Q_FUNC_INFO << sourceFile << mocFileName; - const QString mocFilePath = builddir + mocFileName; - if (QFileInfo(mocFilePath).lastModified() < QFileInfo(sourceFile).lastModified()) { - if (verbose) { - echoColor("Generating " + mocFilePath + " from " + sourceFile); - } else { - echoColor("Generating " + mocFileName); - } - - // we don't want too many child processes -#ifdef Q_OS_FREEBSD - static const int max_processes = 0; -#else - static const int max_processes = 10; -#endif - - if (processes.size() > max_processes) { - waitForProcesses(); - } - - QProcess *mocProc = new QProcess; - mocProc->setProcessChannelMode(QProcess::ForwardedChannels); - QStringList args(mocIncludes); -#ifdef Q_OS_WIN - args << "-DWIN32"; -#endif - args << QLatin1String("-o") << mocFilePath << sourceFile; - //qDebug() << "executing: " << mocExe << args; - mocProc->start(mocExe, args, QIODevice::NotOpen); - if (mocProc->waitForStarted()) - processes.enqueue(Process(mocProc, mocFilePath)); - else { - cerr << "kde4automoc: process for " << mocFilePath << "failed to start: " - << mocProc->errorString() << endl; - failed = true; - delete mocProc; - } - } -} |