diff options
author | Nikolai Kosjar <nikolai.kosjar@digia.com> | 2012-10-29 13:54:33 +0100 |
---|---|---|
committer | Nikolai Kosjar <nikolai.kosjar@digia.com> | 2012-11-22 14:11:58 +0100 |
commit | d0f3d7cb89a234f88b06bc19a41e50c41b1eab0a (patch) | |
tree | 31c22e52a2f35be42d7298fab1cfc6a92e112550 | |
parent | 1a003ed29bd72009ed9c619d6af92804d099dbfc (diff) |
C++: Clean up dev tools.
* Add -h and -help options describing the tools and their usage.
* Make the tools compile and run on Windows (MinGW, MSVC).
* Rename project dirs, executables and main source files to more
meaningful names:
- Use same base name for project dir, *.pro file, main source file
and (if applicable) script file.
- Use the prefix "cplusplus-".
- The names are now:
- gen-cpp-ast/generate-ast --> cplusplus-update-frontend
- mkvisitor --> cplusplus-mkvisitor
- cplusplus-dump/cplusplus0 --> cplusplus-ast2png
* Get rid of 'c++' shell scripts.
* Get rid of duplicates of 'conf.c++'. Rename to 'pp-configuration.inc'.
* Introduce src/tools/cplusplus-tools-utils containing common stuff
that is used at least in two tools. 'pp-configuration.inc' can also be
found here.
* cplusplus-update-frontend:
- Print file paths of written files to stdout.
- Convenience: Use default values referencing the appropriate dirs and
files.
* cplusplus-mkvisitor:
- Take only one argument, namely the path to AST.h.
- Convenience: Use default path to AST.h.
* cplusplus-ast2png:
- Make it run without LD_LIBRARY_PATH.
- As the name suggests, generate image files in png format (needs
'dot' from graphviz).
- Convenience: Read from stdin, which useful for small snippets.
Change-Id: I79c4061fce4a1571c0588dfedd50d4a70715d9df
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
25 files changed, 561 insertions, 182 deletions
diff --git a/.gitignore b/.gitignore index 35bc4f285e..caaca826c5 100644 --- a/.gitignore +++ b/.gitignore @@ -109,8 +109,10 @@ bin/qml2puppet.exe bin/qtpromaker bin/qtpromaker.exe share/doc/qtcreator/*.qch -src/tools/gen-cpp-ast/generate-ast -src/tools/mkvisitor/cplusplus0 +src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor +src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.exe +src/tools/cplusplus-update-frontend/cplusplus-update-frontend +src/tools/cplusplus-update-frontend/cplusplus-update-frontend.exe src/tools/qml/qmldump/qmldump src/tools/examplesscanner/examplesscanner src/tools/valgrindfake/valgrind-fake @@ -118,13 +120,15 @@ bin/*.exe # Tests #------ -tests/manual/cplusplus-frontend/cplusplus0 -tests/manual/cplusplus-dump/cplusplus0 +tests/manual/cplusplus-frontend/cplusplus-frontend +tests/manual/cplusplus-frontend/cplusplus-frontend.exe tests/manual/qml-ast2dot/qml-ast2dot tests/manual/debugger/simple/libsimple_test_plugin.*dylib tests/manual/debugger/simple/simple_test_app tests/manual/plain-cplusplus/plain-c++ tests/manual/preprocessor/pp +tests/tools/cplusplus-ast2png/cplusplus-ast2png +tests/tools/cplusplus-ast2png/cplusplus-ast2png.exe tests/auto/cplusplus/codegen/tst_codegen tests/auto/cplusplus/ast/tst_ast tests/auto/cplusplus/codeformatter/tst_codeformatter diff --git a/src/libs/3rdparty/cplusplus/AST.cpp b/src/libs/3rdparty/cplusplus/AST.cpp index 94cdbc9611..31cacbcc43 100644 --- a/src/libs/3rdparty/cplusplus/AST.cpp +++ b/src/libs/3rdparty/cplusplus/AST.cpp @@ -29,7 +29,7 @@ /* All firstToken/lastToken methods below which have a doxygen comment with - \generated in it, will be re-generated when the tool "generate-ast" is run. + \generated in it, will be re-generated when the tool "cplusplus-update-frontend" is run. For methods which are hand-coded, or which should not be changed, make sure that the comment is gone. diff --git a/src/tools/mkvisitor/main.cpp b/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp index db85b6cbac..ae21f90d94 100644 --- a/src/tools/mkvisitor/main.cpp +++ b/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp @@ -44,6 +44,8 @@ #include <Overview.h> #include <LookupContext.h> +#include "cplusplus-tools-utils.h" + #include <QFile> #include <QList> #include <QCoreApplication> @@ -422,35 +424,65 @@ protected: } }; +void printUsage() +{ + std::cout << "Usage: " << qPrintable(QFileInfo(qApp->arguments().at(0)).fileName()) + << " [-v] [path to AST.h]\n\n" + << "Print a visitor class based on AST.h to stdout.\n\n"; + const QString defaulPath = QFileInfo(PATH_AST_H).canonicalFilePath(); + std::cout << "Default path: " << qPrintable(defaulPath) << '.' << "\n"; +} + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); + QStringList args = app.arguments(); + args.removeFirst(); - QStringList files = app.arguments(); - files.removeFirst(); + bool optionVerbose = false; - foreach (const QString &fileName, files) { - QFile file(fileName); - if (! file.open(QFile::ReadOnly)) - continue; + // Process options & arguments + if (args.contains("-v")) { + optionVerbose = true; + args.removeOne("-v"); + } + const bool helpRequested = args.contains("-h") || args.contains("-help"); + if (helpRequested || args.count() >= 2) { + printUsage(); + return helpRequested ? EXIT_SUCCESS : EXIT_FAILURE; + } - const QByteArray source = file.readAll(); - file.close(); + // Run the preprocessor + QString fileName = PATH_AST_H; + if (!args.isEmpty()) + fileName = args.first(); - Document::Ptr doc = Document::create(fileName); - //doc->control()->setDiagnosticClient(0); - doc->setUtf8Source(source); - doc->parse(); + const QString fileNamePreprocessed = fileName + QLatin1String(".preprocessed"); + CplusplusToolsUtils::SystemPreprocessor preprocessor(optionVerbose); + preprocessor.preprocessFile(fileName, fileNamePreprocessed); - doc->translationUnit()->blockErrors(true); + QFile file(fileNamePreprocessed); + if (! file.open(QFile::ReadOnly)) { + std::cerr << "Error: Could not open file \"" << qPrintable(file.fileName()) << "\"." + << std::endl; + return EXIT_FAILURE; + } - doc->check(); - Snapshot snapshot; - snapshot.insert(doc); + const QByteArray source = file.readAll(); + file.close(); - LookupContext context(doc, snapshot); - MkVisitor mkVisitor(context); - } + Document::Ptr doc = Document::create(fileName); + //doc->control()->setDiagnosticClient(0); + doc->setUtf8Source(source); + doc->parse(); + doc->translationUnit()->blockErrors(true); + doc->check(); + + Snapshot snapshot; + snapshot.insert(doc); + + LookupContext context(doc, snapshot); + MkVisitor mkVisitor(context); return EXIT_SUCCESS; } diff --git a/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.pro b/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.pro new file mode 100644 index 0000000000..aa942fc5fa --- /dev/null +++ b/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.pro @@ -0,0 +1,13 @@ +QT = core gui +macx:CONFIG -= app_bundle +win32:CONFIG += console +TEMPLATE = app +TARGET = cplusplus-mkvisitor +DESTDIR = ./ + +include(../../../qtcreator.pri) +include(../../libs/cplusplus/cplusplus-lib.pri) +include(../../../src/tools/cplusplus-tools-utils/cplusplus-tools-utils.pri) + +DEFINES += PATH_AST_H=\\\"$$PWD/../../libs/3rdparty/cplusplus/AST.h\\\" +SOURCES += cplusplus-mkvisitor.cpp diff --git a/src/tools/cplusplus-tools-utils/cplusplus-tools-utils.cpp b/src/tools/cplusplus-tools-utils/cplusplus-tools-utils.cpp new file mode 100644 index 0000000000..5ad4ce0906 --- /dev/null +++ b/src/tools/cplusplus-tools-utils/cplusplus-tools-utils.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + + +#include "cplusplus-tools-utils.h" +#include "environment.h" + +#include <QDebug> +#include <QDir> +#include <QFile> +#include <QProcess> + +namespace CplusplusToolsUtils { + +QString portableExecutableName(const QString &executable) +{ +#if defined(Q_OS_WIN) + return executable + QLatin1String(".exe"); +#else + return executable; +#endif +} + +void executeCommand(const QString &command, const QStringList &arguments, const QString &outputFile, + bool verbose) +{ + QTextStream out(stderr); + if (command.isEmpty()) { + out << "Error: " << Q_FUNC_INFO << "Got empty command to execute." << endl; + exit(EXIT_FAILURE); + } + + const QString fullCommand = command + QLatin1Char(' ') + arguments.join(QLatin1String(" ")); + if (verbose) + out << "Executing: " << fullCommand << endl; + + QProcess process; + if (!outputFile.isEmpty()) + process.setStandardOutputFile(outputFile, QIODevice::Truncate); + process.start(command, arguments); + if (!process.waitForStarted()) { + out << QString("Error: Process \"%1\" did not start within timeout: %2.") + .arg(fullCommand, process.errorString()) + << endl; + exit(EXIT_FAILURE); + } + if (!process.waitForFinished()) { + if (!verbose) + out << process.readAll() << endl; + out << QString("Error: Process \"%1\" did not finish within timeout.").arg(fullCommand) + << endl; + exit(EXIT_FAILURE); + } + const int exitCode = process.exitCode(); + if (exitCode != 0) { + out << process.readAllStandardError() << endl; + out << QString("Error: Process \"%1\" finished with non zero exit value %2") + .arg(fullCommand, exitCode) << endl; + exit(EXIT_FAILURE); + } +} + +SystemPreprocessor::SystemPreprocessor(bool verbose) + : m_verbose(verbose) +{ + m_knownCompilers[portableExecutableName("gcc")] + = QLatin1String("-DCPLUSPLUS_WITHOUT_QT -U__BLOCKS__ -xc++ -E -include"); + m_knownCompilers[portableExecutableName("cl")] + = QLatin1String("/DCPLUSPLUS_WITHOUT_QT /U__BLOCKS__ /TP /E /I . /FI"); + + QMapIterator<QString, QString> i(m_knownCompilers); + while (i.hasNext()) { + i.next(); + const QString executablePath + = Utils::Environment::systemEnvironment().searchInPath(i.key()); + if (!executablePath.isEmpty()) { + m_compiler = i.key(); + m_compilerArguments = i.value().split(QLatin1String(" "), QString::SkipEmptyParts); + m_compilerArguments + << QDir::toNativeSeparators(QLatin1String(PATH_PREPROCESSOR_CONFIG)); + break; + } + } +} + +void SystemPreprocessor::check() const +{ + QTextStream out(stderr); + if (!QFile::exists(PATH_PREPROCESSOR_CONFIG)) { + out << QString("Error: File \"%1\" does not exist.").arg(PATH_PREPROCESSOR_CONFIG) << endl; + exit(EXIT_FAILURE); + } + if (m_compiler.isEmpty()) { + const QString triedCompilers + = QStringList(m_knownCompilers.keys()).join(QLatin1String(", ")); + out << QString("Error: No compiler found. Tried %1.").arg(triedCompilers) << endl; + exit(EXIT_FAILURE); + } +} + +void SystemPreprocessor::preprocessFile(const QString &inputFile, const QString &outputFile) const +{ + check(); + if (!QFile::exists(inputFile)) { + QTextStream out(stderr); + out << QString("Error: File \"%1\" does not exist.").arg(inputFile) << endl; + exit(EXIT_FAILURE); + } + const QStringList arguments = QStringList(m_compilerArguments) + << QDir::toNativeSeparators(inputFile); + executeCommand(m_compiler, arguments, outputFile, m_verbose); +} + +} // namespace diff --git a/src/tools/cplusplus-tools-utils/cplusplus-tools-utils.h b/src/tools/cplusplus-tools-utils/cplusplus-tools-utils.h new file mode 100644 index 0000000000..bbc0c4834b --- /dev/null +++ b/src/tools/cplusplus-tools-utils/cplusplus-tools-utils.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + + +#ifndef CPLUSPLUSTOOLSUTILS_H +#define CPLUSPLUSTOOLSUTILS_H + +#include <QString> +#include <QStringList> +#include <QMap> + +namespace CplusplusToolsUtils { + +QString portableExecutableName(const QString &executable); +void executeCommand(const QString &command, const QStringList &arguments, const QString &outputFile, + bool verbose = false); + +// Preprocess a file by calling an external compiler in preprocessor mode (-E, /E). +class SystemPreprocessor +{ +public: + SystemPreprocessor(bool verbose = false); + void preprocessFile(const QString &inputFile, const QString &outputFile) const; + +private: + void check() const; + + QMap<QString, QString> m_knownCompilers; + QString m_compiler; // Compiler that will be called in preprocessor mode + QStringList m_compilerArguments; + bool m_verbose; +}; + +} // namespace + +#endif // CPLUSPLUSTOOLSUTILS_H diff --git a/src/tools/cplusplus-tools-utils/cplusplus-tools-utils.pri b/src/tools/cplusplus-tools-utils/cplusplus-tools-utils.pri new file mode 100644 index 0000000000..99002ad0d0 --- /dev/null +++ b/src/tools/cplusplus-tools-utils/cplusplus-tools-utils.pri @@ -0,0 +1,13 @@ +DEPENDPATH += $$PWD +INCLUDEPATH += $$PWD $$PWD/../../libs/utils + +DEFINES += PATH_PREPROCESSOR_CONFIG=\\\"$$PWD/pp-configuration.inc\\\" +DEFINES += QTCREATOR_UTILS_STATIC_LIB + +HEADERS += \ + $$PWD/cplusplus-tools-utils.h \ + $$PWD/../../libs/utils/environment.h + +SOURCES += \ + $$PWD/cplusplus-tools-utils.cpp \ + $$PWD/../../libs/utils/environment.cpp diff --git a/tests/manual/cplusplus-frontend/conf.c++ b/src/tools/cplusplus-tools-utils/pp-configuration.inc index 69bafe0459..5d6b0678c9 100644 --- a/tests/manual/cplusplus-frontend/conf.c++ +++ b/src/tools/cplusplus-tools-utils/pp-configuration.inc @@ -1,15 +1,17 @@ #define __extension__ #define __context__ #define __range__ -#define __asm(a...) -#define __asm__(a...) +#if !defined(_WIN32) && !defined(_WIN64) +# define __asm(a...) +# define __asm__(a...) +# define __stdcall +# define __fastcall +#endif #define restrict #define __restrict #define __restrict__ // #define __weak #define __builtin_va_arg(a,b) ((b)0) -#define __stdcall -#define __fastcall #define __imag__ #define __real__ #define __complex__ diff --git a/src/tools/gen-cpp-ast/generate-ast.cpp b/src/tools/cplusplus-update-frontend/cplusplus-update-frontend.cpp index 34d83b7326..6d8a61dc7f 100644 --- a/src/tools/gen-cpp-ast/generate-ast.cpp +++ b/src/tools/cplusplus-update-frontend/cplusplus-update-frontend.cpp @@ -91,12 +91,21 @@ static const char generatedHeader[] = "// W A R N I N G\n" "// -------------\n" "//\n" -"// This file is automatically generated.\n" +"// This file is automatically generated by \"cplusplus-update-frontend\".\n" "// Changes will be lost.\n" "//\n" "\n" ; +static void closeAndPrintFilePath(QFile &file) +{ + if (file.isOpen()) { + const QString filePath = QFileInfo(file).canonicalFilePath(); + std::cout << QDir::toNativeSeparators(filePath).toLatin1().constData() << std::endl; + file.close(); + } +} + class ASTNodes { public: @@ -226,6 +235,8 @@ public: "using namespace CPlusPlus;\n" << endl; accept(ast); + + closeAndPrintFilePath(file); } protected: @@ -354,7 +365,6 @@ public: QTextStream output(&file); out = &output; - *out << copyrightHeader << generatedHeader << "\n" "#include \"AST.h\"\n" @@ -363,6 +373,8 @@ public: "using namespace CPlusPlus;\n" << endl; accept(ast); + + closeAndPrintFilePath(file); } protected: @@ -480,6 +492,8 @@ public: << endl; accept(ast); + + closeAndPrintFilePath(file); } protected: @@ -627,7 +641,7 @@ public: accept(ast); - file.close(); + closeAndPrintFilePath(file); } protected: @@ -761,7 +775,7 @@ public: d.accept(unit->ast()); - file.close(); + closeAndPrintFilePath(file); } protected: @@ -1220,6 +1234,7 @@ void generateAST_cpp(const Snapshot &snapshot, const QDir &cplusplusDir) if (file.open(QFile::WriteOnly)) { QTextStream out(&file); out << cpp_document.toPlainText(); + closeAndPrintFilePath(file); } } @@ -1312,6 +1327,8 @@ void generateASTVisitor_H(const Snapshot &, const QDir &cplusplusDir, "} // namespace CPlusPlus\n" "\n" "#endif // CPLUSPLUS_ASTVISITOR_H\n"; + + closeAndPrintFilePath(file); } void generateASTMatcher_H(const Snapshot &, const QDir &cplusplusDir, @@ -1353,6 +1370,8 @@ void generateASTMatcher_H(const Snapshot &, const QDir &cplusplusDir, "} // namespace CPlusPlus\n" "\n" "#endif // CPLUSPLUS_ASTMATCHER_H\n"; + + closeAndPrintFilePath(file); } QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir, const QString &dumpersFile) @@ -1437,6 +1456,7 @@ QStringList generateAST_H(const Snapshot &snapshot, const QDir &cplusplusDir, co if (file.open(QFile::WriteOnly)) { QTextStream out(&file); out << document.toPlainText(); + closeAndPrintFilePath(file); } Accept0CG cg(cplusplusDir, AST_h_document->translationUnit()); @@ -1537,6 +1557,7 @@ void generateASTFwd_h(const Snapshot &snapshot, const QDir &cplusplusDir, const if (file.open(QFile::WriteOnly)) { QTextStream out(&file); out << document.toPlainText(); + closeAndPrintFilePath(file); } } @@ -1664,36 +1685,67 @@ void generateASTPatternBuilder_h(const QDir &cplusplusDir) << "} // end of namespace CPlusPlus" << endl << endl << "#endif // CPLUSPLUS_AST_PATTERN_BUILDER_H" << endl; + + closeAndPrintFilePath(file); +} + +void printUsage() +{ + const QByteArray executable = QFileInfo(qApp->arguments().first()).fileName().toLatin1(); + std::cout << "Usage: " << executable.constData() << "\n" + << " " << executable.constData() << " <frontend-dir> <dumpers-file>" + << "\n\n" + << "Generate appropriate header and source files of the C++ frontend accordingly\n" + << "to AST.h and print the paths of the written files. Run this tool after\n" + << "modifying AST.h." + << "\n\n"; + const QString defaultPathCppFrontend = QFileInfo(PATH_CPP_FRONTEND).canonicalFilePath(); + const QString defaultPathDumpersFile = QFileInfo(PATH_DUMPERS_FILE).canonicalFilePath(); + std::cout << "Default values:" << "\n" + << " frontend-dir: " << qPrintable(defaultPathCppFrontend) << "\n" + << " dumpers-file: " << qPrintable(defaultPathDumpersFile) << "\n"; } int main(int argc, char *argv[]) { MyQApplication app(argc, argv); + QStringList args = app.arguments(); + args.removeFirst(); + + QString pathCppFrontend = PATH_CPP_FRONTEND; + QString pathDumpersFile = PATH_DUMPERS_FILE; + + const bool helpRequested = args.contains("-h") || args.contains("-help"); + if (args.count() == 1 || args.count() >= 3 || helpRequested) { + printUsage(); + return helpRequested ? EXIT_SUCCESS : EXIT_FAILURE; + } else if (args.count() == 2) { + pathCppFrontend = args.at(0); + pathDumpersFile = args.at(1); + } - QStringList files = app.arguments(); - files.removeFirst(); - - if (files.size() != 1 && files.size() != 2) { - std::cerr << "Usage: cplusplus [path to C++ front-end]" << std::endl; - std::cerr << " or: cplusplus [path to C++ front-end] [dumpers file name]" << std::endl; + QDir cplusplusDir(pathCppFrontend); + if (!QFile::exists(pathCppFrontend)) { + std::cerr << "Error: Directory \"" << qPrintable(cplusplusDir.absolutePath()) + << "\" does not exist." << std::endl; return EXIT_FAILURE; } - - QDir cplusplusDir(files.first()); if (!QFileInfo(cplusplusDir, QLatin1String("AST.h")).exists()) { - std::cerr << "Cannot find AST.h in " << qPrintable(cplusplusDir.absolutePath()) - << std::endl; + std::cerr << "Error: Cannot find AST.h in \"" << qPrintable(cplusplusDir.absolutePath()) + << "\"." << std::endl; + return EXIT_FAILURE; + } + if (!QFile::exists(pathDumpersFile)) { + std::cerr << "Error: File \"" << qPrintable(pathDumpersFile) + << "\" does not exist." << std::endl; return EXIT_FAILURE; } - - QString dumpersFile; - if (files.size() == 2) - dumpersFile = files.last(); Snapshot snapshot; - QStringList astDerivedClasses = generateAST_H(snapshot, cplusplusDir, dumpersFile); + QStringList astDerivedClasses = generateAST_H(snapshot, cplusplusDir, pathDumpersFile); astDerivedClasses.sort(); generateASTFwd_h(snapshot, cplusplusDir, astDerivedClasses); - generateASTPatternBuilder_h(cplusplusDir); + + return EXIT_SUCCESS; } diff --git a/src/tools/cplusplus-update-frontend/cplusplus-update-frontend.pro b/src/tools/cplusplus-update-frontend/cplusplus-update-frontend.pro new file mode 100644 index 0000000000..7b0e853cd4 --- /dev/null +++ b/src/tools/cplusplus-update-frontend/cplusplus-update-frontend.pro @@ -0,0 +1,15 @@ +QT = core gui +macx:CONFIG -= app_bundle +win32:CONFIG += console +TEMPLATE = app +TARGET = cplusplus-update-frontend +DESTDIR = ./ +DEFINES += QTCREATOR_UTILS_STATIC_LIB +INCLUDEPATH += . ../../libs + +include(../../../qtcreator.pri) +include(../../libs/cplusplus/cplusplus-lib.pri) + +DEFINES += PATH_CPP_FRONTEND=\\\"$$PWD/../../libs/3rdparty/cplusplus\\\" +DEFINES += PATH_DUMPERS_FILE=\\\"$$PWD/../../../tests/tools/cplusplus-ast2png/dumpers.inc\\\" +SOURCES += cplusplus-update-frontend.cpp ../../libs/utils/changeset.cpp diff --git a/src/tools/gen-cpp-ast/gen-cpp-ast.pro b/src/tools/gen-cpp-ast/gen-cpp-ast.pro deleted file mode 100644 index e7fb63f3de..0000000000 --- a/src/tools/gen-cpp-ast/gen-cpp-ast.pro +++ /dev/null @@ -1,10 +0,0 @@ -QT = core gui -macx:CONFIG -= app_bundle -TEMPLATE = app -TARGET = generate-ast -INCLUDEPATH += . ../../libs - -include(../../libs/cplusplus/cplusplus-lib.pri) - -# Input -SOURCES += generate-ast.cpp ../../libs/utils/changeset.cpp diff --git a/src/tools/mkvisitor/conf.c++ b/src/tools/mkvisitor/conf.c++ deleted file mode 100644 index 69bafe0459..0000000000 --- a/src/tools/mkvisitor/conf.c++ +++ /dev/null @@ -1,15 +0,0 @@ -#define __extension__ -#define __context__ -#define __range__ -#define __asm(a...) -#define __asm__(a...) -#define restrict -#define __restrict -#define __restrict__ -// #define __weak -#define __builtin_va_arg(a,b) ((b)0) -#define __stdcall -#define __fastcall -#define __imag__ -#define __real__ -#define __complex__ diff --git a/src/tools/mkvisitor/mkvisitor b/src/tools/mkvisitor/mkvisitor deleted file mode 100755 index 1c6444ba6e..0000000000 --- a/src/tools/mkvisitor/mkvisitor +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -me=$(dirname $0) -${CPP-gcc} -DCPLUSPLUS_WITHOUT_QT -U__BLOCKS__ -xc++ -E -include $me/conf.c++ ../../libs/3rdparty/cplusplus/AST.h > $me/file.i -$me/cplusplus0 $me/file.i -rm -f $me/file.i diff --git a/src/tools/mkvisitor/mkvisitor.pro b/src/tools/mkvisitor/mkvisitor.pro deleted file mode 100644 index 03c53754d2..0000000000 --- a/src/tools/mkvisitor/mkvisitor.pro +++ /dev/null @@ -1,20 +0,0 @@ -QT = core gui -macx:CONFIG -= app_bundle -TARGET = cplusplus0 -INCLUDEPATH += . ../../libs - -include(../../libs/cplusplus/cplusplus-lib.pri) - -# Input -SOURCES += main.cpp - -unix { - debug:OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared - release:OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared - - debug:MOC_DIR = $${OUT_PWD}/.moc/debug-shared - release:MOC_DIR = $${OUT_PWD}/.moc/release-shared - - RCC_DIR = $${OUT_PWD}/.rcc/ - UI_DIR = $${OUT_PWD}/.uic/ -} diff --git a/tests/manual/cplusplus-frontend/c++ b/tests/manual/cplusplus-frontend/c++ deleted file mode 100755 index a5908b79ff..0000000000 --- a/tests/manual/cplusplus-frontend/c++ +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -me=$(dirname $0) -${CPP-gcc} -U__BLOCKS__ -xc++ -E -include $me/conf.c++ $* > $me/file.i -$me/cplusplus0 $me/file.i - diff --git a/tests/manual/cplusplus-frontend/main.cpp b/tests/manual/cplusplus-frontend/cplusplus-frontend.cpp index 7baba4de90..f31af8e5f0 100644 --- a/tests/manual/cplusplus-frontend/main.cpp +++ b/tests/manual/cplusplus-frontend/cplusplus-frontend.cpp @@ -40,6 +40,8 @@ #include <CoreTypes.h> #include <CppDocument.h> +#include "cplusplus-tools-utils.h" + #include <QFile> #include <QList> #include <QCoreApplication> @@ -54,18 +56,47 @@ using namespace CPlusPlus; +void printUsage() +{ + std::cout << "Usage: " << qPrintable(QFileInfo(qApp->arguments().at(0)).fileName()) + << " [-v] <file1> <file2> ...\n\n" + << "Run the parser with the given files.\n"; +} + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); + QStringList args = app.arguments(); + args.removeFirst(); - QStringList files = app.arguments(); - files.removeFirst(); + bool optionVerbose = false; + + // Process options & arguments + if (args.contains("-v")) { + optionVerbose = true; + args.removeOne("-v"); + } + const bool helpRequested = args.contains("-h") || args.contains("-help"); + if (args.isEmpty() || helpRequested) { + printUsage(); + return helpRequested ? EXIT_SUCCESS : EXIT_FAILURE; + } + // Process files + const QStringList files = args; foreach (const QString &fileName, files) { - QFile file(fileName); - if (! file.open(QFile::ReadOnly)) - continue; + // Run preprocessor + const QString fileNamePreprocessed = fileName + QLatin1String(".preprocessed"); + CplusplusToolsUtils::SystemPreprocessor preprocessor(optionVerbose); + preprocessor.preprocessFile(fileName, fileNamePreprocessed); + // Run parser + QFile file(fileNamePreprocessed); + if (! file.open(QFile::ReadOnly)) { + std::cerr << "Error: Could not open file \"" << qPrintable(file.fileName()) << "\"." + << std::endl; + return EXIT_FAILURE; + } const QByteArray source = file.readAll(); file.close(); diff --git a/tests/manual/cplusplus-frontend/cplusplus-frontend.pro b/tests/manual/cplusplus-frontend/cplusplus-frontend.pro index 529645f6a4..c2a6300ca0 100644 --- a/tests/manual/cplusplus-frontend/cplusplus-frontend.pro +++ b/tests/manual/cplusplus-frontend/cplusplus-frontend.pro @@ -1,21 +1,13 @@ QT = core gui macx:CONFIG -= app_bundle -TARGET = cplusplus0 -include(../../../qtcreator.pri) -include($$IDE_SOURCE_TREE/src/libs/cplusplus/cplusplus.pri) -include($$IDE_SOURCE_TREE/src/libs/languageutils/languageutils.pri) -include($$IDE_SOURCE_TREE/src/libs/utils/utils.pri) - -# Input -SOURCES += main.cpp +win32:CONFIG += console +TEMPLATE = app +TARGET = cplusplus-frontend +DESTDIR = ./ -unix { - debug:OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared - release:OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared - - debug:MOC_DIR = $${OUT_PWD}/.moc/debug-shared - release:MOC_DIR = $${OUT_PWD}/.moc/release-shared +include(../../../qtcreator.pri) +include($$IDE_SOURCE_TREE/src/libs/cplusplus/cplusplus-lib.pri) +include($$IDE_SOURCE_TREE/tests/auto/qttestrpath.pri) +include(../../../src/tools/cplusplus-tools-utils/cplusplus-tools-utils.pri) - RCC_DIR = $${OUT_PWD}/.rcc/ - UI_DIR = $${OUT_PWD}/.uic/ -} +SOURCES += cplusplus-frontend.cpp diff --git a/tests/tools/cplusplus-dump/main.cpp b/tests/tools/cplusplus-ast2png/cplusplus-ast2png.cpp index 168f7c2b11..8af2b289e5 100644 --- a/tests/tools/cplusplus-dump/main.cpp +++ b/tests/tools/cplusplus-ast2png/cplusplus-ast2png.cpp @@ -42,6 +42,9 @@ #include <SymbolVisitor.h> #include <Overview.h> +#include "cplusplus-tools-utils.h" + +#include <QDir> #include <QFile> #include <QList> #include <QCoreApplication> @@ -58,6 +61,22 @@ # include <cxxabi.h> #endif +// For isatty(), _isatty() +#if defined(Q_OS_WIN) +# include <io.h> +#else +# include <unistd.h> +#endif + +bool tty_for_stdin() +{ +#if defined(Q_OS_WIN) + return _isatty(_fileno(stdin)); +#else + return isatty(fileno(stdin)); +#endif +} + using namespace CPlusPlus; class ASTDump: protected ASTVisitor @@ -68,9 +87,6 @@ public: void operator()(AST *ast) { QByteArray basename = translationUnit()->fileName(); - int dotIdx = basename.lastIndexOf('.'); - if (dotIdx != -1) - basename.truncate(dotIdx); basename.append(".ast.dot"); out.open(basename.constData()); @@ -89,11 +105,10 @@ public: out << "}" << std::endl; out.close(); - std::cout << basename.constData() << std::endl; } // the following file can be generated by using: - // generate-ast <path to cpp stuff> <path to dumpers.inc> + // cplusplus-update-frontend <frontend-dir> <dumpers-file> #include "dumpers.inc" protected: @@ -195,9 +210,6 @@ public: void operator()(Symbol *s) { QByteArray basename = translationUnit->fileName(); - int dotIdx = basename.lastIndexOf('.'); - if (dotIdx != -1) - basename.truncate(dotIdx); basename.append(".symbols.dot"); out.open(basename.constData()); @@ -218,7 +230,6 @@ public: out << "}" << std::endl; out.close(); - std::cout << basename.constData() << std::endl; } protected: @@ -351,19 +362,103 @@ private: Overview o; }; + +void createImageFromDot(const QString &inputFile, const QString &outputFile, bool verbose) +{ + const QString command = CplusplusToolsUtils::portableExecutableName(QLatin1String("dot")); + const QStringList arguments = QStringList() + << QLatin1String("-Tpng") << QLatin1String("-o") << outputFile << inputFile; + CplusplusToolsUtils::executeCommand(command, arguments, QString(), verbose); +} + +const char PATH_STDIN_FILE[] = "_stdincontents.cpp"; + +QString example() +{ + return +#if defined(Q_OS_WIN) + QString::fromLatin1("> echo int foo() {} | %1 && %2.ast.png") +#elif defined(Q_OS_MAC) + QString::fromLatin1("$ echo \"int foo() {}\" | ./%1 && open %2.ast.png") +#else + QString::fromLatin1("$ echo \"int foo() {}\" | ./%1 && xdg-open %2.ast.png") +#endif + .arg(QFileInfo(qApp->arguments().at(0)).fileName(), PATH_STDIN_FILE); +} + +void printUsage() +{ + std::cout << "Usage: " << qPrintable(QFileInfo(qApp->arguments().at(0)).fileName()) + << " [-v] <file1> <file2> ...\n\n"; + + std::cout << qPrintable(QString::fromLatin1( + "Visualize AST and symbol hierarchy of given C++ files by generating png image files\n" + "in the same directory as the input files. Print paths to generated image files.\n" + "\n" + "Standard input is also read. The resulting files starts with \"%1\"\n" + "and are created in the current working directory. To show the AST for simple snippets\n" + "you might want to execute:\n" + "\n" + " %2\n" + "\n" + "Prerequisites:\n" + " 1) Make sure to have 'dot' from graphviz locatable by PATH.\n" + " 2) Make sure to have an up to date dumpers file by using 'cplusplus-update-frontend'.\n" + ).arg(PATH_STDIN_FILE, example())); +} + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); + QStringList args = app.arguments(); + args.removeFirst(); + + bool optionVerbose = false; + + // Data from stdin? + if (!tty_for_stdin()) { + QFile file("_stdincontents.cpp"); + if (! file.open(QFile::WriteOnly)) { + std::cerr << "Error: Cannot open file for writing\"" << qPrintable(file.fileName()) + << "\"" << std::endl; + exit(EXIT_FAILURE); + } + file.write(QTextStream(stdin).readAll().toLocal8Bit()); + file.close(); + args.append(file.fileName()); + } - QStringList files = app.arguments(); - files.removeFirst(); + // Process options & arguments + if (args.contains("-v")) { + optionVerbose = true; + args.removeOne("-v"); + } + const bool helpRequested = args.contains("-h") || args.contains("-help"); + if (args.isEmpty() || helpRequested) { + printUsage(); + return helpRequested ? EXIT_SUCCESS : EXIT_FAILURE; + } + // Process files + const QStringList files = args; foreach (const QString &fileName, files) { - QFile file(fileName); + if (! QFile::exists(fileName)) { + std::cerr << "Error: File \"" << qPrintable(fileName) << "\" does not exist." + << std::endl; + exit(EXIT_FAILURE); + } + + // Run the preprocessor + const QString fileNamePreprocessed = fileName + QLatin1String(".preprocessed"); + CplusplusToolsUtils::SystemPreprocessor preprocessor(optionVerbose); + preprocessor.preprocessFile(fileName, fileNamePreprocessed); + + // Convert to dot + QFile file(fileNamePreprocessed); if (! file.open(QFile::ReadOnly)) { - std::cerr << "Cannot open \"" << qPrintable(fileName) - << "\", skipping it." << std::endl; - continue; + std::cerr << "Error: Could not open file \"" << qPrintable(fileNamePreprocessed) + << "\"" << std::endl; + exit(EXIT_FAILURE); } const QByteArray source = file.readAll(); @@ -373,7 +468,6 @@ int main(int argc, char *argv[]) doc->control()->setDiagnosticClient(0); doc->setUtf8Source(source); doc->parse(); - doc->check(); ASTDump dump(doc->translationUnit()); @@ -381,6 +475,18 @@ int main(int argc, char *argv[]) SymbolDump dump2(doc->translationUnit()); dump2(doc->globalNamespace()); + + // Create images + typedef QPair<QString, QString> Pair; + QList<Pair> inputOutputFiles; + inputOutputFiles.append(qMakePair(QString(fileName + QLatin1String(".ast.dot")), + QString(fileName + QLatin1String(".ast.png")))); + inputOutputFiles.append(qMakePair(QString(fileName + QLatin1String(".symbols.dot")), + QString(fileName + QLatin1String(".symbols.png")))); + foreach (const Pair &pair, inputOutputFiles) { + createImageFromDot(pair.first, pair.second, optionVerbose); + std::cout << qPrintable(QDir::toNativeSeparators(pair.second)) << std::endl; + } } return EXIT_SUCCESS; diff --git a/tests/tools/cplusplus-ast2png/cplusplus-ast2png.pro b/tests/tools/cplusplus-ast2png/cplusplus-ast2png.pro new file mode 100644 index 0000000000..8a0fd726ad --- /dev/null +++ b/tests/tools/cplusplus-ast2png/cplusplus-ast2png.pro @@ -0,0 +1,12 @@ +QT = core gui +macx:CONFIG -= app_bundle +win32:CONFIG += console +TEMPLATE = app +TARGET = cplusplus-ast2png +DESTDIR = ./ + +include(../../../qtcreator.pri) +include(../../../src/libs/cplusplus/cplusplus-lib.pri) +include(../../../src/tools/cplusplus-tools-utils/cplusplus-tools-utils.pri) + +SOURCES += cplusplus-ast2png.cpp diff --git a/tests/tools/cplusplus-dump/dumpers.inc b/tests/tools/cplusplus-ast2png/dumpers.inc index 0d1d8e4620..0d1d8e4620 100644 --- a/tests/tools/cplusplus-dump/dumpers.inc +++ b/tests/tools/cplusplus-ast2png/dumpers.inc diff --git a/tests/tools/cplusplus-dump/tests/templ01.cpp b/tests/tools/cplusplus-ast2png/tests/templ01.cpp index c67299b1f1..c67299b1f1 100644 --- a/tests/tools/cplusplus-dump/tests/templ01.cpp +++ b/tests/tools/cplusplus-ast2png/tests/templ01.cpp diff --git a/tests/tools/cplusplus-dump/c++ b/tests/tools/cplusplus-dump/c++ deleted file mode 100755 index a5908b79ff..0000000000 --- a/tests/tools/cplusplus-dump/c++ +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -me=$(dirname $0) -${CPP-gcc} -U__BLOCKS__ -xc++ -E -include $me/conf.c++ $* > $me/file.i -$me/cplusplus0 $me/file.i - diff --git a/tests/tools/cplusplus-dump/conf.c++ b/tests/tools/cplusplus-dump/conf.c++ deleted file mode 100644 index 69bafe0459..0000000000 --- a/tests/tools/cplusplus-dump/conf.c++ +++ /dev/null @@ -1,15 +0,0 @@ -#define __extension__ -#define __context__ -#define __range__ -#define __asm(a...) -#define __asm__(a...) -#define restrict -#define __restrict -#define __restrict__ -// #define __weak -#define __builtin_va_arg(a,b) ((b)0) -#define __stdcall -#define __fastcall -#define __imag__ -#define __real__ -#define __complex__ diff --git a/tests/tools/cplusplus-dump/cplusplus-dump.pro b/tests/tools/cplusplus-dump/cplusplus-dump.pro deleted file mode 100644 index cd6525119e..0000000000 --- a/tests/tools/cplusplus-dump/cplusplus-dump.pro +++ /dev/null @@ -1,20 +0,0 @@ -QT = core gui -macx:CONFIG -= app_bundle -TARGET = cplusplus0 - -include(../../../qtcreator.pri) -include(../../../src/libs/cplusplus/cplusplus.pri) - -# Input -SOURCES += main.cpp - -unix { - debug:OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared - release:OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared - - debug:MOC_DIR = $${OUT_PWD}/.moc/debug-shared - release:MOC_DIR = $${OUT_PWD}/.moc/release-shared - - RCC_DIR = $${OUT_PWD}/.rcc/ - UI_DIR = $${OUT_PWD}/.uic/ -} diff --git a/tests/tools/tools.pro b/tests/tools/tools.pro index f8339cd1f8..f54f92d40c 100644 --- a/tests/tools/tools.pro +++ b/tests/tools/tools.pro @@ -1,5 +1,5 @@ TEMPLATE=subdirs SUBDIRS= \ -cplusplus-dump \ +cplusplus-ast2png \ qml-ast2dot |