diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMakeVersion.cmake | 2 | ||||
-rw-r--r-- | Source/QtDialog/CMakeLists.txt | 4 | ||||
-rw-r--r-- | Source/QtDialog/CMakeSetup.cxx | 78 | ||||
-rw-r--r-- | Source/QtDialog/CMakeSetupDialog.cxx | 36 | ||||
-rw-r--r-- | Source/QtDialog/MacInstallDialog.ui | 103 | ||||
-rw-r--r-- | Source/QtDialog/QMacInstallDialog.cxx | 121 | ||||
-rw-r--r-- | Source/QtDialog/QMacInstallDialog.h | 20 | ||||
-rw-r--r-- | Source/cmDefinitions.cxx | 42 | ||||
-rw-r--r-- | Source/cmDefinitions.h | 27 | ||||
-rw-r--r-- | Source/cmExtraQbsGenerator.cxx | 4 | ||||
-rw-r--r-- | Source/cmLocalNinjaGenerator.cxx | 4 | ||||
-rw-r--r-- | Source/cmMakefile.cxx | 239 | ||||
-rw-r--r-- | Source/cmMakefile.h | 40 | ||||
-rw-r--r-- | Source/cmMakefileTargetGenerator.cxx | 14 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 17 | ||||
-rw-r--r-- | Source/cmQtAutoGenerators.cxx | 37 | ||||
-rw-r--r-- | Source/cmTarget.cxx | 2 | ||||
-rw-r--r-- | Source/cmTest.h | 5 | ||||
-rw-r--r-- | Source/cmTryRunCommand.cxx | 2 | ||||
-rw-r--r-- | Source/cmake.h | 2 | ||||
-rw-r--r-- | Source/cmakemain.cxx | 2 | ||||
-rw-r--r-- | Source/cmcmd.cxx | 82 |
22 files changed, 345 insertions, 538 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 060aedd..54779a5 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 2) -set(CMake_VERSION_PATCH 20150519) +set(CMake_VERSION_PATCH 20150521) #set(CMake_VERSION_RC 1) diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt index 9cc993a..168f57d 100644 --- a/Source/QtDialog/CMakeLists.txt +++ b/Source/QtDialog/CMakeLists.txt @@ -99,15 +99,12 @@ set(SRCS QCMakeCacheView.h QCMakeWidgets.cxx QCMakeWidgets.h - QMacInstallDialog.cxx - QMacInstallDialog.h ) QT4_WRAP_UI(UI_SRCS CMakeSetupDialog.ui Compilers.ui CrossCompiler.ui AddCacheEntry.ui - MacInstallDialog.ui ) QT4_WRAP_CPP(MOC_SRCS AddCacheEntry.h @@ -117,7 +114,6 @@ QT4_WRAP_CPP(MOC_SRCS QCMake.h QCMakeCacheView.h QCMakeWidgets.h - QMacInstallDialog.h ) QT4_ADD_RESOURCES(RC_SRCS CMakeSetup.qrc) diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index 349269e..38d6d44 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -15,11 +15,11 @@ #include <QTranslator> #include <QLocale> #include <QTextCodec> -#include "QMacInstallDialog.h" #include "CMakeSetupDialog.h" #include "cmDocumentation.h" #include "cmake.h" #include "cmVersion.h" +#include "cmAlgorithms.h" #include <cmsys/CommandLineArguments.hxx> #include <cmsys/SystemTools.hxx> #include <cmsys/Encoding.hxx> @@ -48,6 +48,10 @@ static const char * cmDocumentationOptions[][2] = {0,0} }; +#if defined(Q_OS_MAC) +static int cmOSXInstall(std::string dir); +#endif + int main(int argc, char** argv) { cmsys::Encoding::CommandLineArguments encoding_args = @@ -79,6 +83,17 @@ int main(int argc, char** argv) return (doc.PrintRequestedDocumentation(std::cout)? 0:1); } +#if defined(Q_OS_MAC) + if (argc2 == 2 && strcmp(argv2[1], "--install") == 0) + { + return cmOSXInstall("/usr/bin"); + } + if (argc2 == 2 && cmHasLiteralPrefix(argv2[1], "--install=")) + { + return cmOSXInstall(argv2[1]+10); + } +#endif + QApplication app(argc, argv); #if defined(CMAKE_ENCODING_UTF8) @@ -93,16 +108,6 @@ int main(int argc, char** argv) QApplication::removeLibraryPath(p); } - // if arg for install - for(int i =0; i < argc2; i++) - { - if(strcmp(argv2[i], "--mac-install") == 0) - { - QMacInstallDialog setupdialog(0); - setupdialog.exec(); - return 0; - } - } // tell the cmake library where cmake is QDir cmExecDir(QApplication::applicationDirPath()); #if defined(Q_OS_MAC) @@ -189,3 +194,54 @@ int main(int argc, char** argv) return app.exec(); } +#if defined(Q_OS_MAC) +# include <errno.h> +# include <string.h> +# include <sys/stat.h> +# include <unistd.h> +static bool cmOSXInstall(std::string const& dir, std::string const& tool) +{ + if (tool.empty()) + { + return true; + } + std::string link = dir + cmSystemTools::GetFilenameName(tool); + struct stat st; + if (lstat(link.c_str(), &st) == 0 && S_ISLNK(st.st_mode)) + { + char buf[4096]; + ssize_t s = readlink(link.c_str(), buf, sizeof(buf)-1); + if (s >= 0 && std::string(buf, s) == tool) + { + std::cerr << "Exists: '" << link << "' -> '" << tool << "'\n"; + return true; + } + } + if (symlink(tool.c_str(), link.c_str()) == 0) + { + std::cerr << "Linked: '" << link << "' -> '" << tool << "'\n"; + return true; + } + else + { + int err = errno; + std::cerr << "Failed: '" << link << "' -> '" << tool << "': " + << strerror(err) << "\n"; + return false; + } +} +static int cmOSXInstall(std::string dir) +{ + if (!cmHasLiteralSuffix(dir, "/")) + { + dir += "/"; + } + return ( + cmOSXInstall(dir, cmSystemTools::GetCMakeCommand()) && + cmOSXInstall(dir, cmSystemTools::GetCTestCommand()) && + cmOSXInstall(dir, cmSystemTools::GetCPackCommand()) && + cmOSXInstall(dir, cmSystemTools::GetCMakeGUICommand()) && + cmOSXInstall(dir, cmSystemTools::GetCMakeCursesCommand()) + ) ? 0 : 1; +} +#endif diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index b8077f2..426fa12 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -27,7 +27,6 @@ #include <QUrl> #include <QShortcut> #include <QKeySequence> -#include <QMacInstallDialog.h> #include <QInputDialog> #include "QCMake.h" @@ -121,7 +120,7 @@ CMakeSetupDialog::CMakeSetupDialog() this, SLOT(showUserChanges())); #if defined(Q_WS_MAC) || defined(Q_OS_MAC) this->InstallForCommandLineAction - = ToolsMenu->addAction(tr("&Install For Command Line Use")); + = ToolsMenu->addAction(tr("&How to Install For Command Line Use")); QObject::connect(this->InstallForCommandLineAction, SIGNAL(triggered(bool)), this, SLOT(doInstallForCommandLine())); #endif @@ -420,8 +419,37 @@ bool CMakeSetupDialog::doConfigureInternal() void CMakeSetupDialog::doInstallForCommandLine() { - QMacInstallDialog setupdialog(0); - setupdialog.exec(); + QString title = tr("How to Install For Command Line Use"); + QString msg = tr( + "One may add CMake to the PATH:\n" + "\n" + " PATH=\"%1\":\"$PATH\"\n" + "\n" + "Or, to install symlinks to '/usr/bin', run:\n" + "\n" + " sudo \"%2\" --install\n" + "\n" + "Or, to install symlinks to another directory, run:\n" + "\n" + " sudo \"%3\" --install=/path/to/bin\n" + ); + msg = msg.arg(cmSystemTools::GetFilenamePath( + cmSystemTools::GetCMakeCommand()).c_str()); + msg = msg.arg(cmSystemTools::GetCMakeGUICommand().c_str()); + msg = msg.arg(cmSystemTools::GetCMakeGUICommand().c_str()); + + QDialog dialog; + dialog.setWindowTitle(title); + QVBoxLayout* l = new QVBoxLayout(&dialog); + QLabel* lab = new QLabel(&dialog); + l->addWidget(lab); + lab->setText(msg); + lab->setWordWrap(false); + QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok, + Qt::Horizontal, &dialog); + QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept())); + l->addWidget(btns); + dialog.exec(); } bool CMakeSetupDialog::doGenerateInternal() diff --git a/Source/QtDialog/MacInstallDialog.ui b/Source/QtDialog/MacInstallDialog.ui deleted file mode 100644 index c7e31db..0000000 --- a/Source/QtDialog/MacInstallDialog.ui +++ /dev/null @@ -1,103 +0,0 @@ -<ui version="4.0" > - <class>Dialog</class> - <widget class="QDialog" name="Dialog" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>470</width> - <height>159</height> - </rect> - </property> - <property name="windowTitle" > - <string>Install Command Line Tools</string> - </property> - <layout class="QGridLayout" > - <property name="margin" > - <number>9</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item row="3" column="1" > - <spacer> - <property name="orientation" > - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" > - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="0" colspan="3" > - <layout class="QHBoxLayout" > - <property name="margin" > - <number>0</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <spacer> - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" > - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="skipInstallButton" > - <property name="text" > - <string>Skip Install Command Line </string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="doInstallButton" > - <property name="text" > - <string>Install Command Line Links</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="0" column="2" > - <widget class="QPushButton" name="choosePathButton" > - <property name="text" > - <string>Choose...</string> - </property> - </widget> - </item> - <item row="0" column="0" > - <widget class="QLabel" name="label" > - <property name="text" > - <string>Install Folder:</string> - </property> - </widget> - </item> - <item row="0" column="1" > - <widget class="QLineEdit" name="InstallPrefix" /> - </item> - <item row="1" column="0" colspan="3" > - <widget class="QLabel" name="label_2" > - <property name="text" > - <string>This will create symbolic links to the command line tools of cmake into the specified install folder.</string> - </property> - <property name="wordWrap" > - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/Source/QtDialog/QMacInstallDialog.cxx b/Source/QtDialog/QMacInstallDialog.cxx deleted file mode 100644 index fa7df43..0000000 --- a/Source/QtDialog/QMacInstallDialog.cxx +++ /dev/null @@ -1,121 +0,0 @@ -#include "QMacInstallDialog.h" -#include <QMessageBox> -#include "cmSystemTools.h" -#include <iostream> -#include <QFileDialog> -#include "ui_MacInstallDialog.h" - -class QMacInstallDialog::QMacInstallDialogInternals : public Ui::Dialog -{ -public: -}; - -QMacInstallDialog::QMacInstallDialog(QWidget*w) - :QDialog(w) -{ - this->Internals = new QMacInstallDialogInternals; - this->Internals->setupUi(this); - QObject::connect(this->Internals->choosePathButton, SIGNAL(clicked(bool)), - this, SLOT(ShowBrowser())); - QObject::connect(this->Internals->skipInstallButton, SIGNAL(clicked(bool)), - this, SLOT(SkipInstall())); - QObject::connect(this->Internals->doInstallButton, SIGNAL(clicked(bool)), - this, SLOT(DoInstall())); - this->Internals->InstallPrefix->setText("/usr/bin/"); - -} - -QMacInstallDialog::~QMacInstallDialog() -{ - delete this->Internals; -} - -void QMacInstallDialog::DoInstall() -{ - QDir installDir(this->Internals->InstallPrefix->text()); - QString installTo = installDir.path(); - if(!cmSystemTools::FileExists(installTo.toLocal8Bit().data())) - { - QString message = tr("Build install does not exist, " - "should I create it?\n\n" - "Directory: "); - message += installDir.path(); - QString title = tr("Create Directory"); - QMessageBox::StandardButton btn; - btn = QMessageBox::information(this, title, message, - QMessageBox::Yes | QMessageBox::No); - if(btn == QMessageBox::Yes) - { - cmSystemTools::MakeDirectory(installTo.toLocal8Bit().data()); - } - } - QDir cmExecDir(QApplication::applicationDirPath()); - cmExecDir.cd("../bin"); - QFileInfoList list = cmExecDir.entryInfoList(); - for (int i = 0; i < list.size(); ++i) - { - QFileInfo fileInfo = list.at(i); - QString filename = fileInfo.fileName(); - if(filename.size() && filename[0] == '.') - { - continue; - } - QString file = fileInfo.absoluteFilePath(); - QString newName = installTo; - newName += "/"; - newName += filename; - // Remove the old files - if(cmSystemTools::FileExists(newName.toLocal8Bit().data())) - { - std::cout << "rm [" << newName.toLocal8Bit().data() << "]\n"; - if(!cmSystemTools::RemoveFile(newName.toLocal8Bit().data())) - { - QString message = tr("Failed to remove file " - "installation may be incomplete: "); - message += newName; - QString title = tr("Error Removing file"); - QMessageBox::StandardButton btn = - QMessageBox::critical(this, title, message, - QMessageBox::Ok|QMessageBox::Abort); - if(btn == QMessageBox::Abort) - { - return; - } - } - } - std::cout << "ln -s [" << file.toLocal8Bit().data() << "] ["; - std::cout << newName.toLocal8Bit().data() << "]\n"; - if(!cmSystemTools::CreateSymlink(file.toLocal8Bit().data(), - newName.toLocal8Bit().data())) - { - QString message = tr("Failed create symlink " - "installation may be incomplete: "); - message += newName; - QString title = tr("Error Creating Symlink"); - QMessageBox::StandardButton btn = - QMessageBox::critical(this, title, message, - QMessageBox::Ok|QMessageBox::Abort); - if(btn == QMessageBox::Abort) - { - return; - } - } - } - this->done(0); -} - -void QMacInstallDialog::SkipInstall() -{ - this->done(0); -} - - -void QMacInstallDialog::ShowBrowser() -{ - QString dir = QFileDialog::getExistingDirectory(this, - tr("Enter Install Prefix"), this->Internals->InstallPrefix->text()); - if(!dir.isEmpty()) - { - this->Internals->InstallPrefix->setText(dir); - } -} diff --git a/Source/QtDialog/QMacInstallDialog.h b/Source/QtDialog/QMacInstallDialog.h deleted file mode 100644 index efe67df..0000000 --- a/Source/QtDialog/QMacInstallDialog.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef QMacInstallDialog_h -#define QMacInstallDialog_h -#include <QDialog> - -class QMacInstallDialog : public QDialog -{ - Q_OBJECT; -public: - QMacInstallDialog(QWidget*w); - ~QMacInstallDialog(); -private slots: - void ShowBrowser(); - void SkipInstall(); - void DoInstall(); -private: - class QMacInstallDialogInternals; - QMacInstallDialogInternals* Internals; -}; - -#endif diff --git a/Source/cmDefinitions.cxx b/Source/cmDefinitions.cxx index e2c6876..2dab169 100644 --- a/Source/cmDefinitions.cxx +++ b/Source/cmDefinitions.cxx @@ -18,12 +18,13 @@ cmDefinitions::Def cmDefinitions::NoDef; //---------------------------------------------------------------------------- cmDefinitions::Def const& cmDefinitions::GetInternal( - const std::string& key, StackIter begin, StackIter end) + const std::string& key, StackIter begin, StackIter end, bool raise) { assert(begin != end); - MapType::const_iterator i = begin->Map.find(key); + MapType::iterator i = begin->Map.find(key); if (i != begin->Map.end()) { + i->second.Used = true; return i->second; } StackIter it = begin; @@ -32,7 +33,11 @@ cmDefinitions::Def const& cmDefinitions::GetInternal( { return cmDefinitions::NoDef; } - Def const& def = cmDefinitions::GetInternal(key, it, end); + Def const& def = cmDefinitions::GetInternal(key, it, end, raise); + if (!raise) + { + return def; + } return begin->Map.insert(MapType::value_type(key, def)).first->second; } @@ -40,10 +45,30 @@ cmDefinitions::Def const& cmDefinitions::GetInternal( const char* cmDefinitions::Get(const std::string& key, StackIter begin, StackIter end) { - Def const& def = cmDefinitions::GetInternal(key, begin, end); + Def const& def = cmDefinitions::GetInternal(key, begin, end, false); return def.Exists? def.c_str() : 0; } +void cmDefinitions::Raise(const std::string& key, + StackIter begin, StackIter end) +{ + cmDefinitions::GetInternal(key, begin, end, true); +} + +bool cmDefinitions::HasKey(const std::string& key, + StackConstIter begin, StackConstIter end) +{ + for (StackConstIter it = begin; it != end; ++it) + { + MapType::const_iterator i = it->Map.find(key); + if (i != it->Map.end()) + { + return true; + } + } + return false; +} + //---------------------------------------------------------------------------- void cmDefinitions::Set(const std::string& key, const char* value) { @@ -51,13 +76,8 @@ void cmDefinitions::Set(const std::string& key, const char* value) this->Map[key] = def; } -void cmDefinitions::Erase(const std::string& key) -{ - this->Map.erase(key); -} - //---------------------------------------------------------------------------- -std::vector<std::string> cmDefinitions::LocalKeys() const +std::vector<std::string> cmDefinitions::UnusedKeys() const { std::vector<std::string> keys; keys.reserve(this->Map.size()); @@ -65,7 +85,7 @@ std::vector<std::string> cmDefinitions::LocalKeys() const for(MapType::const_iterator mi = this->Map.begin(); mi != this->Map.end(); ++mi) { - if (mi->second.Exists) + if (!mi->second.Used) { keys.push_back(mi->first); } diff --git a/Source/cmDefinitions.h b/Source/cmDefinitions.h index bf791ed..5fdcaab 100644 --- a/Source/cmDefinitions.h +++ b/Source/cmDefinitions.h @@ -35,18 +35,18 @@ class cmDefinitions typedef std::list<cmDefinitions>::reverse_iterator StackIter; typedef std::list<cmDefinitions>::const_reverse_iterator StackConstIter; public: - /** Get the value associated with a key; null if none. - Store the result locally if it came from a parent. */ static const char* Get(const std::string& key, StackIter begin, StackIter end); + static void Raise(const std::string& key, StackIter begin, StackIter end); + + static bool HasKey(const std::string& key, + StackConstIter begin, StackConstIter end); + /** Set (or unset if null) a value associated with a key. */ void Set(const std::string& key, const char* value); - void Erase(const std::string& key); - - /** Get the set of all local keys. */ - std::vector<std::string> LocalKeys() const; + std::vector<std::string> UnusedKeys() const; static std::vector<std::string> ClosureKeys(StackConstIter begin, StackConstIter end); @@ -60,11 +60,16 @@ private: private: typedef std::string std_string; public: - Def(): std_string(), Exists(false) {} - Def(const char* v): std_string(v?v:""), Exists(v?true:false) {} - Def(const std_string& v): std_string(v), Exists(true) {} - Def(Def const& d): std_string(d), Exists(d.Exists) {} + Def(): std_string(), Exists(false), Used(false) {} + Def(const char* v) + : std_string(v ? v : ""), + Exists(v ? true : false), + Used(false) + {} + Def(const std_string& v): std_string(v), Exists(true), Used(false) {} + Def(Def const& d): std_string(d), Exists(d.Exists), Used(d.Used) {} bool Exists; + bool Used; }; static Def NoDef; @@ -80,7 +85,7 @@ private: MapType Map; static Def const& GetInternal(const std::string& key, - StackIter begin, StackIter end); + StackIter begin, StackIter end, bool raise); }; #endif diff --git a/Source/cmExtraQbsGenerator.cxx b/Source/cmExtraQbsGenerator.cxx index 4cc4650..c15f8da 100644 --- a/Source/cmExtraQbsGenerator.cxx +++ b/Source/cmExtraQbsGenerator.cxx @@ -182,7 +182,9 @@ void cmExtraQbsGenerator::AppendSources(cmGeneratedFileStream &fout, std::vector<cmSourceFile *> genSources; std::vector<cmSourceFile *>::const_iterator itr = sources.begin(); fout << "\t\t\tfiles: [\n" - << "\t\t\t\t\"" << t.GetMakefile()->GetCurrentListFile() << "\",\n"; + << "\t\t\t\t\"" + << t.GetMakefile()->GetDefinition("CMAKE_CURRENT_LIST_FILE") + << "\",\n"; for (; itr != sources.end(); ++itr) { if (!(*itr)->GetPropertyAsBool("GENERATED")) diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index f1f1202..bcae486 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -305,8 +305,8 @@ void cmLocalNinjaGenerator::WriteProcessedMakefile(std::ostream& os) cmGlobalNinjaGenerator::WriteDivider(os); os << "# Write statements declared in CMakeLists.txt:" << std::endl - << "# " << this->Makefile->GetCurrentListFile() << std::endl - ; + << "# " + << this->Makefile->GetDefinition("CMAKE_CURRENT_LIST_FILE") << std::endl; if(this->IsRootMakefile()) os << "# Which is the root file." << std::endl; cmGlobalNinjaGenerator::WriteDivider(os); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 2e7e6bc..2a49c8f 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -38,7 +38,6 @@ #include <cmsys/FStream.hxx> #include <cmsys/auto_ptr.hxx> -#include <stack> #include <list> #include <ctype.h> // for isspace #include <assert.h> @@ -47,8 +46,6 @@ class cmMakefile::Internals { public: std::list<cmDefinitions> VarStack; - std::stack<std::set<std::string> > VarInitStack; - std::stack<std::set<std::string> > VarUsageStack; bool IsSourceFileTryCompile; void PushDefinitions() @@ -69,6 +66,12 @@ public: this->VarStack.rend()); } + bool IsInitialized(std::string const& name) + { + return cmDefinitions::HasKey(name, this->VarStack.rbegin(), + this->VarStack.rend()); + } + void SetDefinition(std::string const& name, std::string const& value) { this->VarStack.back().Set(name, value.c_str()); @@ -76,20 +79,12 @@ public: void RemoveDefinition(std::string const& name) { - if (this->VarStack.size() > 1) - { - // In lower scopes we store keys, defined or not. - this->VarStack.back().Set(name, 0); - } - else - { - this->VarStack.back().Erase(name); - } + this->VarStack.back().Set(name, 0); } - std::vector<std::string> LocalKeys() const + std::vector<std::string> UnusedKeys() const { - return this->VarStack.back().LocalKeys(); + return this->VarStack.back().UnusedKeys(); } std::vector<std::string> ClosureKeys() const @@ -105,35 +100,32 @@ public: bool RaiseScope(std::string const& var, const char* varDef, cmMakefile* mf) { - assert(this->VarStack.size() > 0); - std::list<cmDefinitions>::reverse_iterator it = this->VarStack.rbegin(); + assert(it != this->VarStack.rend()); ++it; if(it == this->VarStack.rend()) { - if(cmLocalGenerator* plg = mf->GetLocalGenerator()->GetParent()) + cmLocalGenerator* plg = mf->GetLocalGenerator()->GetParent(); + if(!plg) { - // Update the definition in the parent directory top scope. This - // directory's scope was initialized by the closure of the parent - // scope, so we do not need to localize the definition first. - cmMakefile* parent = plg->GetMakefile(); - if (varDef) - { - parent->AddDefinition(var, varDef); - } - else - { - parent->RemoveDefinition(var); - } - return true; + return false; + } + // Update the definition in the parent directory top scope. This + // directory's scope was initialized by the closure of the parent + // scope, so we do not need to localize the definition first. + cmMakefile* parent = plg->GetMakefile(); + if (varDef) + { + parent->AddDefinition(var, varDef); } else { - return false; + parent->RemoveDefinition(var); } + return true; } // First localize the definition in the current scope. - this->GetDefinition(var); + cmDefinitions::Raise(var, this->VarStack.rbegin(), this->VarStack.rend()); // Now update the definition in the parent scope. it->Set(var, varDef); @@ -148,13 +140,11 @@ cmMakefile::cmMakefile(cmLocalGenerator* localGenerator) StateSnapshot(localGenerator->GetStateSnapshot()) { this->Internal->PushDefinitions(); - this->Internal->VarInitStack.push(std::set<std::string>()); - this->Internal->VarUsageStack.push(std::set<std::string>()); this->Internal->IsSourceFileTryCompile = false; // Initialize these first since AddDefaultDefinitions calls AddDefinition - this->WarnUnused = false; - this->CheckSystemVars = false; + this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused(); + this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars(); this->GeneratingBuildSystem = false; this->SuppressWatches = false; @@ -224,24 +214,16 @@ cmMakefile::cmMakefile(cmLocalGenerator* localGenerator) #endif this->Properties.SetCMakeInstance(this->GetCMakeInstance()); - this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused(); - this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars(); { const char* dir = this->GetCMakeInstance()->GetHomeDirectory(); this->AddDefinition("CMAKE_SOURCE_DIR", dir); - if ( !this->GetDefinition("CMAKE_CURRENT_SOURCE_DIR") ) - { - this->AddDefinition("CMAKE_CURRENT_SOURCE_DIR", dir); - } + this->AddDefinition("CMAKE_CURRENT_SOURCE_DIR", dir); } { const char* dir = this->GetCMakeInstance()->GetHomeOutputDirectory(); this->AddDefinition("CMAKE_BINARY_DIR", dir); - if ( !this->GetDefinition("CMAKE_CURRENT_BINARY_DIR") ) - { - this->AddDefinition("CMAKE_CURRENT_BINARY_DIR", dir); - } + this->AddDefinition("CMAKE_CURRENT_BINARY_DIR", dir); } } @@ -262,59 +244,6 @@ cmMakefile::~cmMakefile() } } -void cmMakefile::PrintStringVector(const char* s, - const std::vector<std::string>& v) const -{ - std::cout << s << ": ( \n" << cmWrap('"', v, '"', " ") << ")\n"; -} - -void cmMakefile -::PrintStringVector(const char* s, - const std::vector<std::pair<std::string, bool> >& v) const -{ - std::cout << s << ": ( \n"; - for(std::vector<std::pair<std::string, bool> >::const_iterator i - = v.begin(); i != v.end(); ++i) - { - std::cout << i->first << " " << i->second; - } - std::cout << " )\n"; -} - - -// call print on all the classes in the makefile -void cmMakefile::Print() const -{ - // print the class lists - std::cout << "classes:\n"; - - std::cout << " this->Targets: "; - for (cmTargets::iterator l = this->Targets.begin(); - l != this->Targets.end(); l++) - { - std::cout << l->first << std::endl; - } - - std::cout << " this->StartOutputDirectory; " << - this->GetCurrentBinaryDirectory() << std::endl; - std::cout << " this->HomeOutputDirectory; " << - this->GetHomeOutputDirectory() << std::endl; - std::cout << " this->cmStartDirectory; " << - this->GetCurrentSourceDirectory() << std::endl; - std::cout << " this->cmHomeDirectory; " << - this->GetHomeDirectory() << std::endl; - std::cout << " this->ProjectName; " - << this->ProjectName << std::endl; - this->PrintStringVector("this->LinkDirectories", this->LinkDirectories); -#if defined(CMAKE_BUILD_WITH_CMAKE) - for( std::vector<cmSourceGroup>::const_iterator i = - this->SourceGroups.begin(); i != this->SourceGroups.end(); ++i) - { - std::cout << "Source Group: " << i->GetName() << std::endl; - } -#endif -} - //---------------------------------------------------------------------------- void cmMakefile::IssueMessage(cmake::MessageType t, std::string const& text) const @@ -601,7 +530,6 @@ void cmMakefile::IncludeScope::EnforceCMP0011() bool cmMakefile::ProcessBuildsystemFile(const char* listfile) { this->AddDefinition("CMAKE_PARENT_LIST_FILE", listfile); - this->cmCurrentListFile = listfile; std::string curSrc = this->GetCurrentSourceDirectory(); return this->ReadListFile(listfile, true, curSrc == this->GetHomeDirectory()); @@ -609,17 +537,16 @@ bool cmMakefile::ProcessBuildsystemFile(const char* listfile) bool cmMakefile::ReadDependentFile(const char* listfile, bool noPolicyScope) { - this->AddDefinition("CMAKE_PARENT_LIST_FILE", this->GetCurrentListFile()); - this->cmCurrentListFile = - cmSystemTools::CollapseFullPath(listfile, - this->GetCurrentSourceDirectory()); - return this->ReadListFile(this->cmCurrentListFile.c_str(), - noPolicyScope); + this->AddDefinition("CMAKE_PARENT_LIST_FILE", + this->GetDefinition("CMAKE_CURRENT_LIST_FILE")); + return this->ReadListFile(listfile, noPolicyScope, false); +} + +bool cmMakefile::ReadListFile(const char* listfile) +{ + return this->ReadListFile(listfile, true, false); } -//---------------------------------------------------------------------------- -// Parse the given CMakeLists.txt file executing all commands -// bool cmMakefile::ReadListFile(const char* listfile, bool noPolicyScope, bool requireProjectCommand) @@ -658,7 +585,6 @@ bool cmMakefile::ReadListFile(const char* listfile, if (res) { - // Check for unused variables this->CheckForUnusedVariables(); } @@ -1793,14 +1719,11 @@ void cmMakefile::AddDefinition(const std::string& name, const char* value) return; } - this->Internal->SetDefinition(name, value); - if (!this->Internal->VarUsageStack.empty() && - this->VariableInitialized(name)) + if (this->VariableInitialized(name)) { - this->CheckForUnused("changing definition", name); - this->Internal->VarUsageStack.top().erase(name); + this->LogUnused("changing definition", name); } - this->Internal->VarInitStack.top().insert(name); + this->Internal->SetDefinition(name, value); #ifdef CMAKE_BUILD_WITH_CMAKE cmVariableWatch* vv = this->GetVariableWatch(); @@ -1869,14 +1792,11 @@ void cmMakefile::AddCacheDefinition(const std::string& name, const char* value, void cmMakefile::AddDefinition(const std::string& name, bool value) { - this->Internal->SetDefinition(name, value ? "ON" : "OFF"); - if (!this->Internal->VarUsageStack.empty() && - this->VariableInitialized(name)) + if (this->VariableInitialized(name)) { - this->CheckForUnused("changing definition", name); - this->Internal->VarUsageStack.top().erase(name); + this->LogUnused("changing definition", name); } - this->Internal->VarInitStack.top().insert(name); + this->Internal->SetDefinition(name, value ? "ON" : "OFF"); #ifdef CMAKE_BUILD_WITH_CMAKE cmVariableWatch* vv = this->GetVariableWatch(); if ( vv ) @@ -1893,43 +1813,28 @@ void cmMakefile::CheckForUnusedVariables() const { return; } - const std::vector<std::string>& locals = this->Internal->LocalKeys(); - std::vector<std::string>::const_iterator it = locals.begin(); - for (; it != locals.end(); ++it) + const std::vector<std::string>& unused = this->Internal->UnusedKeys(); + std::vector<std::string>::const_iterator it = unused.begin(); + for (; it != unused.end(); ++it) { - this->CheckForUnused("out of scope", *it); + this->LogUnused("out of scope", *it); } } void cmMakefile::MarkVariableAsUsed(const std::string& var) { - this->Internal->VarUsageStack.top().insert(var); + this->Internal->GetDefinition(var); } bool cmMakefile::VariableInitialized(const std::string& var) const { - if(this->Internal->VarInitStack.top().find(var) != - this->Internal->VarInitStack.top().end()) - { - return true; - } - return false; -} - -bool cmMakefile::VariableUsed(const std::string& var) const -{ - if(this->Internal->VarUsageStack.top().find(var) != - this->Internal->VarUsageStack.top().end()) - { - return true; - } - return false; + return this->Internal->IsInitialized(var); } -void cmMakefile::CheckForUnused(const char* reason, +void cmMakefile::LogUnused(const char* reason, const std::string& name) const { - if (this->WarnUnused && !this->VariableUsed(name)) + if (this->WarnUnused) { std::string path; cmListFileBacktrace bt(this->GetLocalGenerator()); @@ -1967,14 +1872,11 @@ void cmMakefile::CheckForUnused(const char* reason, void cmMakefile::RemoveDefinition(const std::string& name) { - this->Internal->RemoveDefinition(name); - if (!this->Internal->VarUsageStack.empty() && - this->VariableInitialized(name)) + if (this->VariableInitialized(name)) { - this->CheckForUnused("unsetting", name); - this->Internal->VarUsageStack.top().erase(name); + this->LogUnused("unsetting", name); } - this->Internal->VarInitStack.top().insert(name); + this->Internal->RemoveDefinition(name); #ifdef CMAKE_BUILD_WITH_CMAKE cmVariableWatch* vv = this->GetVariableWatch(); if ( vv ) @@ -2441,7 +2343,6 @@ const char* cmMakefile::GetRequiredDefinition(const std::string& name) const bool cmMakefile::IsDefinitionSet(const std::string& name) const { const char* def = this->Internal->GetDefinition(name); - this->Internal->VarUsageStack.top().insert(name); if(!def) { def = this->GetState()->GetInitializedCacheValue(name); @@ -2462,10 +2363,6 @@ bool cmMakefile::IsDefinitionSet(const std::string& name) const const char* cmMakefile::GetDefinition(const std::string& name) const { - if (this->WarnUnused) - { - this->Internal->VarUsageStack.top().insert(name); - } const char* def = this->Internal->GetDefinition(name); if(!def) { @@ -4363,7 +4260,7 @@ void cmMakefile::AddCMakeDependFilesFromUser() } } -std::string cmMakefile::GetListFileStack() const +std::string cmMakefile::FormatListFileStack() const { std::ostringstream tmp; size_t depth = this->ListFileStack.size(); @@ -4392,10 +4289,6 @@ std::string cmMakefile::GetListFileStack() const void cmMakefile::PushScope() { this->Internal->PushDefinitions(); - const std::set<std::string>& init = this->Internal->VarInitStack.top(); - const std::set<std::string>& usage = this->Internal->VarUsageStack.top(); - this->Internal->VarInitStack.push(init); - this->Internal->VarUsageStack.push(usage); this->PushLoopBlockBarrier(); @@ -4412,31 +4305,9 @@ void cmMakefile::PopScope() this->PopLoopBlockBarrier(); - std::set<std::string> init = this->Internal->VarInitStack.top(); - std::set<std::string> usage = this->Internal->VarUsageStack.top(); - const std::vector<std::string>& locals = this->Internal->LocalKeys(); - // Remove initialization and usage information for variables in the local - // scope. - std::vector<std::string>::const_iterator it = locals.begin(); - for (; it != locals.end(); ++it) - { - init.erase(*it); - if (!this->VariableUsed(*it)) - { - this->CheckForUnused("out of scope", *it); - } - else - { - usage.erase(*it); - } - } + this->CheckForUnusedVariables(); this->Internal->PopDefinitions(); - this->Internal->VarInitStack.pop(); - this->Internal->VarUsageStack.pop(); - // Push initialization and usage up to the parent scope. - this->Internal->VarInitStack.top().insert(init.begin(), init.end()); - this->Internal->VarUsageStack.top().insert(usage.begin(), usage.end()); } void cmMakefile::RaiseScope(const std::string& var, const char *varDef) diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 82f2715..efd73a1 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -65,14 +65,10 @@ class cmMakefile class Internals; cmsys::auto_ptr<Internals> Internal; public: - /* Check for unused variables in this scope */ - void CheckForUnusedVariables() const; /* Mark a variable as used */ void MarkVariableAsUsed(const std::string& var); /* return true if a variable has been initialized */ bool VariableInitialized(const std::string& ) const; - /* return true if a variable has been used */ - bool VariableUsed(const std::string& ) const; /** * Construct an empty makefile. @@ -84,12 +80,7 @@ public: */ ~cmMakefile(); - /** - * Read and parse a CMakeLists.txt file. - */ - bool ReadListFile(const char* listfile, - bool noPolicyScope = true, - bool requireProjectCommand = false); + bool ReadListFile(const char* listfile); bool ReadDependentFile(const char* listfile, bool noPolicyScope = true); @@ -162,11 +153,6 @@ public: */ void FinalPass(); - /** - * Print the object state to std::cout. - */ - void Print() const; - /** Add a custom command to the build. */ void AddCustomCommandToTarget(const std::string& target, const std::vector<std::string>& byproducts, @@ -418,14 +404,6 @@ public: void SetCurrentBinaryDirectory(const std::string& dir); const char* GetCurrentBinaryDirectory() const; - /* Get the current CMakeLists.txt file that is being processed. This - * is just used in order to be able to 'branch' from one file to a second - * transparently */ - const char* GetCurrentListFile() const - { - return this->cmCurrentListFile.c_str(); - } - //@} /** @@ -588,7 +566,7 @@ public: { this->ListFiles.push_back(file);} void AddCMakeDependFilesFromUser(); - std::string GetListFileStack() const; + std::string FormatListFileStack() const; /** * Get the current context backtrace. @@ -843,9 +821,7 @@ protected: void AddGlobalLinkInformation(const std::string& name, cmTarget& target); // Check for a an unused variable - void CheckForUnused(const char* reason, const std::string& name) const; - - std::string cmCurrentListFile; + void LogUnused(const char* reason, const std::string& name) const; std::string ProjectName; // project name @@ -912,6 +888,10 @@ private: cmState::Snapshot StateSnapshot; + bool ReadListFile(const char* listfile, + bool noPolicyScope, + bool requireProjectCommand); + bool ReadListFileInternal(const char* filenametoread, bool noPolicyScope, bool requireProjectCommand); @@ -923,10 +903,6 @@ private: friend class cmMakeDepend; // make depend needs direct access // to the Sources array - void PrintStringVector(const char* s, const - std::vector<std::pair<std::string, bool> >& v) const; - void PrintStringVector(const char* s, - const std::vector<std::string>& v) const; void AddDefaultDefinitions(); typedef std::vector<cmFunctionBlocker*> FunctionBlockersType; @@ -1062,6 +1038,8 @@ private: bool HaveCxxStandardAvailable(cmTarget const* target, const std::string& feature) const; + void CheckForUnusedVariables() const; + mutable bool SuppressWatches; }; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 9afe09c..0c8acc7 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -768,6 +768,20 @@ cmMakefileTargetGenerator this->LocalGenerator->ExpandRuleVariables(*i, vars); } + // Maybe insert an include-what-you-use runner. + if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) + { + std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; + const char *iwyu = this->Target->GetProperty(iwyu_prop); + if (iwyu && *iwyu) + { + std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_iwyu --iwyu="; + run_iwyu += this->LocalGenerator->EscapeForShell(iwyu); + run_iwyu += " -- "; + compileCommands.front().insert(0, run_iwyu); + } + } + // Change the command working directory to the local build tree. this->LocalGenerator->CreateCDCommand (compileCommands, diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index cdc9cc8..879d6b7 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -458,6 +458,23 @@ cmNinjaTargetGenerator std::vector<std::string> compileCmds; cmSystemTools::ExpandListArgument(compileCmd, compileCmds); + // Maybe insert an include-what-you-use runner. + if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) + { + std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; + const char *iwyu = this->Target->GetProperty(iwyu_prop); + if (iwyu && *iwyu) + { + std::string run_iwyu = + this->GetLocalGenerator()->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); + run_iwyu += " -E __run_iwyu --iwyu="; + run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu); + run_iwyu += " -- "; + compileCmds.front().insert(0, run_iwyu); + } + } + if (!compileCmds.empty()) { compileCmds.front().insert(0, cldeps); diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index a683c2a..add5e61 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -1203,23 +1203,6 @@ std::string cmQtAutoGenerators::GetRccExecutable(cmTarget const* target) return std::string(); } -static cmGlobalGenerator* CreateGlobalGenerator(cmake* cm, - const std::string& targetDirectory) -{ - cmGlobalGenerator* gg = new cmGlobalGenerator(); - gg->SetCMakeInstance(cm); - - cm->SetHomeOutputDirectory(targetDirectory); - cm->SetHomeDirectory(targetDirectory); - - cmLocalGenerator* lg = gg->MakeLocalGenerator(); - lg->GetMakefile()->SetCurrentBinaryDirectory(targetDirectory); - lg->GetMakefile()->SetCurrentSourceDirectory(targetDirectory); - gg->SetCurrentLocalGenerator(lg); - - return gg; -} - bool cmQtAutoGenerators::Run(const std::string& targetDirectory, const std::string& config) { @@ -1227,25 +1210,27 @@ bool cmQtAutoGenerators::Run(const std::string& targetDirectory, cmake cm; cm.SetHomeOutputDirectory(targetDirectory); cm.SetHomeDirectory(targetDirectory); - cmGlobalGenerator* gg = CreateGlobalGenerator(&cm, targetDirectory); - cmMakefile* makefile = gg->GetCurrentLocalGenerator()->GetMakefile(); + cmGlobalGenerator gg; + gg.SetCMakeInstance(&cm); + + cmLocalGenerator* lg = gg.MakeLocalGenerator(); + lg->GetMakefile()->SetCurrentBinaryDirectory(targetDirectory); + lg->GetMakefile()->SetCurrentSourceDirectory(targetDirectory); + gg.SetCurrentLocalGenerator(lg); - this->ReadAutogenInfoFile(makefile, targetDirectory, config); - this->ReadOldMocDefinitionsFile(makefile, targetDirectory); + this->ReadAutogenInfoFile(lg->GetMakefile(), targetDirectory, config); + this->ReadOldMocDefinitionsFile(lg->GetMakefile(), targetDirectory); this->Init(); if (this->QtMajorVersion == "4" || this->QtMajorVersion == "5") { - success = this->RunAutogen(makefile); + success = this->RunAutogen(lg->GetMakefile()); } this->WriteOldMocDefinitionsFile(targetDirectory); - delete gg->GetCurrentLocalGenerator(); - delete gg; - gg = NULL; - makefile = NULL; + delete lg; return success; } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 8feb7a5..70005b4 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -333,9 +333,11 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("MACOSX_BUNDLE", 0); this->SetPropertyDefault("MACOSX_RPATH", 0); this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", 0); + this->SetPropertyDefault("C_INCLUDE_WHAT_YOU_USE", 0); this->SetPropertyDefault("C_STANDARD", 0); this->SetPropertyDefault("C_STANDARD_REQUIRED", 0); this->SetPropertyDefault("C_EXTENSIONS", 0); + this->SetPropertyDefault("CXX_INCLUDE_WHAT_YOU_USE", 0); this->SetPropertyDefault("CXX_STANDARD", 0); this->SetPropertyDefault("CXX_STANDARD_REQUIRED", 0); this->SetPropertyDefault("CXX_EXTENSIONS", 0); diff --git a/Source/cmTest.h b/Source/cmTest.h index c6e7e42..ca88afe 100644 --- a/Source/cmTest.h +++ b/Source/cmTest.h @@ -40,11 +40,6 @@ public: return this->Command; } - /** - * Print the structure to std::cout. - */ - void Print() const; - ///! Set/Get a property of this source file void SetProperty(const std::string& prop, const char *value); void AppendProperty(const std::string& prop, diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx index 3cd92cb..b9ffe5e 100644 --- a/Source/cmTryRunCommand.cxx +++ b/Source/cmTryRunCommand.cxx @@ -375,7 +375,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs, comment += "Run arguments : "; comment += runArgs; comment += "\n"; - comment += " Called from: " + this->Makefile->GetListFileStack(); + comment += " Called from: " + this->Makefile->FormatListFileStack(); cmsys::SystemTools::ReplaceString(comment, "\n", "\n# "); file << comment << "\n\n"; diff --git a/Source/cmake.h b/Source/cmake.h index 0d1977e..0a1ee7d 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -403,7 +403,7 @@ private: #define CMAKE_STANDARD_OPTIONS_TABLE \ {"-C <initial-cache>", "Pre-load a script to populate the cache."}, \ - {"-D <var>:<type>=<value>", "Create a cmake cache entry."}, \ + {"-D <var>[:<type>]=<value>", "Create a cmake cache entry."}, \ {"-U <globbing_expr>", "Remove matching entries from CMake cache."}, \ {"-G <generator-name>", "Specify a build system generator."},\ {"-T <toolset-name>", "Specify toolset name if supported by generator."}, \ diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 577dcd9..e5f4700 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -130,7 +130,7 @@ static std::string cmakemainGetStack(void *clientdata) cmMakefile* mf=cmakemainGetMakefile(clientdata); if (mf) { - msg = mf->GetListFileStack(); + msg = mf->FormatListFileStack(); if (!msg.empty()) { msg = "\n Called from: " + msg; diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 3400625..3ea2186 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -211,6 +211,88 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) return 0; } + // run include what you use command and then run the compile + // command. This is an internal undocumented option and should + // only be used by CMake itself when running iwyu. + else if (args[1] == "__run_iwyu") + { + if (args.size() < 3) + { + std::cerr << "__run_iwyu Usage: -E __run_iwyu [--iwyu=/path/iwyu]" + " -- compile command\n"; + return 1; + } + bool doing_options = true; + std::vector<std::string> orig_cmd; + std::string iwyu; + for (std::string::size_type cc = 2; cc < args.size(); cc ++) + { + std::string const& arg = args[cc]; + if (arg == "--") + { + doing_options = false; + } + else if (doing_options && cmHasLiteralPrefix(arg, "--iwyu=")) + { + iwyu = arg.substr(7); + } + else if (doing_options) + { + std::cerr << "__run_iwyu given unknown argument: " << arg << "\n"; + return 1; + } + else + { + orig_cmd.push_back(arg); + } + } + if (iwyu.empty()) + { + std::cerr << "__run_iwyu missing --iwyu=\n"; + return 1; + } + if (orig_cmd.empty()) + { + std::cerr << "__run_iwyu missing compile command after --\n"; + return 1; + } + + // Construct the iwyu command line by taking what was given + // and adding all the arguments we give to the compiler. + std::vector<std::string> iwyu_cmd; + cmSystemTools::ExpandListArgument(iwyu, iwyu_cmd, true); + iwyu_cmd.insert(iwyu_cmd.end(), orig_cmd.begin()+1, orig_cmd.end()); + + // Run the iwyu command line. Capture its stderr and hide its stdout. + int ret = 0; + std::string stdErr; + if(!cmSystemTools::RunSingleCommand(iwyu_cmd, 0, &stdErr, &ret, + 0, cmSystemTools::OUTPUT_NONE)) + { + std::cerr << "Error running '" << iwyu_cmd[0] << "': " + << stdErr << "\n"; + return 1; + } + + // Warn if iwyu reported anything. + if(stdErr.find("should remove these lines:") != stdErr.npos + || stdErr.find("should add these lines:") != stdErr.npos) + { + std::cerr << "Warning: include-what-you-use reported diagnostics:\n" + << stdErr << "\n"; + } + + // Now run the real compiler command and return its result value. + if(!cmSystemTools::RunSingleCommand(orig_cmd, 0, &stdErr, &ret, 0, + cmSystemTools::OUTPUT_PASSTHROUGH)) + { + std::cerr << "Error running '" << orig_cmd[0] << "': " + << stdErr << "\n"; + return 1; + } + return ret; + } + // Echo string else if (args[1] == "echo" ) { |