diff options
Diffstat (limited to 'Source')
115 files changed, 2549 insertions, 486 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index ab62d2b..1893167 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -357,6 +357,10 @@ if (WIN32) cmLocalVisualStudio7Generator.h cmLocalVisualStudioGenerator.cxx cmLocalVisualStudioGenerator.h + cmVisualStudioSlnData.h + cmVisualStudioSlnData.cxx + cmVisualStudioSlnParser.h + cmVisualStudioSlnParser.cxx cmVisualStudioWCEPlatformParser.h cmVisualStudioWCEPlatformParser.cxx cmWin32ProcessExecution.cxx @@ -537,7 +541,8 @@ endif() add_executable(cmake cmakemain.cxx) target_link_libraries(cmake CMakeLib) -# Build special executable for running programs on Windows 98 +# Build special executable for running programs on Windows 98. +# Included on any Windows (unconditional packaging required!). if(WIN32) if(NOT UNIX) add_executable(cmw9xcom cmw9xcom.cxx) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 8ded30f..1230403 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,6 +1,6 @@ # CMake version number components. set(CMake_VERSION_MAJOR 2) set(CMake_VERSION_MINOR 8) -set(CMake_VERSION_PATCH 10) -set(CMake_VERSION_TWEAK 20130425) +set(CMake_VERSION_PATCH 11) +set(CMake_VERSION_TWEAK 20130603) #set(CMake_VERSION_RC 1) diff --git a/Source/CPack/cmCPackDocumentVariables.cxx b/Source/CPack/cmCPackDocumentVariables.cxx index 6a841fa..1dfaaf9 100644 --- a/Source/CPack/cmCPackDocumentVariables.cxx +++ b/Source/CPack/cmCPackDocumentVariables.cxx @@ -60,7 +60,7 @@ void cmCPackDocumentVariables::DefineVariables(cmake* cm) "It is usually invoked like this:\n" " make DESTDIR=/home/john install\n" "which will install the concerned software using the" - " installation prefix, e.g. \"/usr/local\" pre-pended with " + " installation prefix, e.g. \"/usr/local\" prepended with " "the DESTDIR value which finally gives \"/home/john/usr/local\"." " When preparing a package, CPack first installs the items to be " "packaged in a local (to the build tree) directory by using the " diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index 7cc1522..3c685bd 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -638,7 +638,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( = this->MakefileMap->GetDefinition("CMAKE_MAKE_PROGRAM"); std::string buildCommand = globalGenerator->GenerateBuildCommand(cmakeMakeProgram, - installProjectName.c_str(), 0, + installProjectName.c_str(), 0, 0, globalGenerator->GetPreinstallTargetName(), buildConfig, false, false); cmCPackLogger(cmCPackLog::LOG_DEBUG, diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx index f4d38ce..1f63185 100644 --- a/Source/CTest/cmCTestBuildCommand.cxx +++ b/Source/CTest/cmCTestBuildCommand.cxx @@ -130,10 +130,11 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() cmakeBuildConfiguration = config; } + std::string dir = this->CTest->GetCTestConfiguration("BuildDirectory"); std::string buildCommand = this->GlobalGenerator-> GenerateBuildCommand(cmakeMakeProgram, - cmakeProjectName, + cmakeProjectName, dir.c_str(), cmakeBuildAdditionalFlags, cmakeBuildTarget, cmakeBuildConfiguration, true, false); cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx index d6d39a9..db33cb6 100644 --- a/Source/CTest/cmCTestConfigureCommand.cxx +++ b/Source/CTest/cmCTestConfigureCommand.cxx @@ -31,32 +31,6 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() cmSystemTools::ExpandListArgument(this->Values[ctc_OPTIONS], options); } - if ( this->Values[ct_BUILD] ) - { - this->CTest->SetCTestConfiguration("BuildDirectory", - cmSystemTools::CollapseFullPath( - this->Values[ct_BUILD]).c_str()); - } - else - { - this->CTest->SetCTestConfiguration("BuildDirectory", - cmSystemTools::CollapseFullPath( - this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY")).c_str()); - } - - if ( this->Values[ct_SOURCE] ) - { - this->CTest->SetCTestConfiguration("SourceDirectory", - cmSystemTools::CollapseFullPath( - this->Values[ct_SOURCE]).c_str()); - } - else - { - this->CTest->SetCTestConfiguration("SourceDirectory", - cmSystemTools::CollapseFullPath( - this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")).c_str()); - } - if ( this->CTest->GetCTestConfiguration("BuildDirectory").empty() ) { this->SetError("Build directory not specified. Either use BUILD " diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 453e32c..2e2feb0 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -70,19 +70,6 @@ bool cmCTestHandlerCommand this->CTest->SetConfigType(ctestConfigType); } - cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl;); - cmCTestGenericHandler* handler = this->InitializeHandler(); - if ( !handler ) - { - cmCTestLog(this->CTest, ERROR_MESSAGE, - "Cannot instantiate test handler " << this->GetName() - << std::endl); - return false; - } - - handler->SetAppendXML(this->AppendXML); - - handler->PopulateCustomVectors(this->Makefile); if ( this->Values[ct_BUILD] ) { this->CTest->SetCTestConfiguration("BuildDirectory", @@ -119,6 +106,20 @@ bool cmCTestHandlerCommand cmSystemTools::CollapseFullPath( this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")).c_str()); } + + cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl;); + cmCTestGenericHandler* handler = this->InitializeHandler(); + if ( !handler ) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Cannot instantiate test handler " << this->GetName() + << std::endl); + return false; + } + + handler->SetAppendXML(this->AppendXML); + + handler->PopulateCustomVectors(this->Makefile); if ( this->Values[ct_SUBMIT_INDEX] ) { if(!this->CTest->GetDropSiteCDash() && this->CTest->GetDartVersion() <= 1) diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 80218ad..8baa673 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -43,8 +43,7 @@ static CatToErrorType cmCTestMemCheckBoundsChecker[] = { {0,0} }; -// parse the xml file storing the installed version of Xcode on -// the machine +// parse the xml file containing the results of last BoundsChecker run class cmBoundsCheckerParser : public cmXMLParser { public: @@ -461,13 +460,6 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() return false; } - if ( this->MemoryTester[0] == '\"' && - this->MemoryTester[this->MemoryTester.size()-1] == '\"' ) - { - this->MemoryTester - = this->MemoryTester.substr(1, this->MemoryTester.size()-2); - } - // Setup the options std::string memoryTesterOptions; if ( this->CTest->GetCTestConfiguration( @@ -491,13 +483,13 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() switch ( this->MemoryTesterStyle ) { case cmCTestMemCheckHandler::VALGRIND: + { if ( this->MemoryTesterOptions.empty() ) { this->MemoryTesterOptions.push_back("-q"); this->MemoryTesterOptions.push_back("--tool=memcheck"); this->MemoryTesterOptions.push_back("--leak-check=yes"); this->MemoryTesterOptions.push_back("--show-reachable=yes"); - this->MemoryTesterOptions.push_back("--workaround-gcc296-bugs=yes"); this->MemoryTesterOptions.push_back("--num-callers=50"); } if ( this->CTest->GetCTestConfiguration( @@ -516,7 +508,11 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() + this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile"); this->MemoryTesterOptions.push_back(suppressions); } + std::string outputFile = "--log-file=" + + this->MemoryTesterOutputFile; + this->MemoryTesterOptions.push_back(outputFile); break; + } case cmCTestMemCheckHandler::PURIFY: { std::string outputFile; @@ -948,6 +944,21 @@ cmCTestMemCheckHandler::PostProcessPurifyTest(cmCTestTestResult& res) cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "PostProcessPurifyTest for : " << res.Name.c_str() << std::endl); + appendMemTesterOutput(res); +} + +void +cmCTestMemCheckHandler::PostProcessValgrindTest(cmCTestTestResult& res) +{ + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "PostProcessValgrindTest for : " + << res.Name.c_str() << std::endl); + appendMemTesterOutput(res); +} + +void +cmCTestMemCheckHandler::appendMemTesterOutput(cmCTestTestResult& res) +{ if ( !cmSystemTools::FileExists(this->MemoryTesterOutputFile.c_str()) ) { std::string log = "Cannot find memory tester output file: " diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h index 1e81c89..0a8c1b3 100644 --- a/Source/CTest/cmCTestMemCheckHandler.h +++ b/Source/CTest/cmCTestMemCheckHandler.h @@ -119,6 +119,10 @@ private: void PostProcessPurifyTest(cmCTestTestResult& res); void PostProcessBoundsCheckerTest(cmCTestTestResult& res); + void PostProcessValgrindTest(cmCTestTestResult& res); + + ///! append MemoryTesterOutputFile to the test log + void appendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res); }; #endif diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 5eabf3f..ddd7e45 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -166,6 +166,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) { found = true; reason = "Required regular expression found."; + break; } } if ( !found ) @@ -196,6 +197,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) reason += passIt->second; reason += "]"; forceFail = true; + break; } } } @@ -384,13 +386,19 @@ void cmCTestRunTest::MemCheckPostProcess() << this->TestResult.Name.c_str() << std::endl); cmCTestMemCheckHandler * handler = static_cast<cmCTestMemCheckHandler*> (this->TestHandler); - if(handler->MemoryTesterStyle == cmCTestMemCheckHandler::BOUNDS_CHECKER) - { - handler->PostProcessBoundsCheckerTest(this->TestResult); - } - else if(handler->MemoryTesterStyle == cmCTestMemCheckHandler::PURIFY) + switch ( handler->MemoryTesterStyle ) { - handler->PostProcessPurifyTest(this->TestResult); + case cmCTestMemCheckHandler::VALGRIND: + handler->PostProcessValgrindTest(this->TestResult); + break; + case cmCTestMemCheckHandler::PURIFY: + handler->PostProcessPurifyTest(this->TestResult); + break; + case cmCTestMemCheckHandler::BOUNDS_CHECKER: + handler->PostProcessBoundsCheckerTest(this->TestResult); + break; + default: + break; } } diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index e7491bb..0508448 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -82,7 +82,6 @@ bool cmCTestSubdirCommand std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); for ( it = args.begin(); it != args.end(); ++ it ) { - cmSystemTools::ChangeDirectory(cwd.c_str()); std::string fname; if(cmSystemTools::FileIsFullPath(it->c_str())) @@ -116,7 +115,6 @@ bool cmCTestSubdirCommand else { // No CTestTestfile? Who cares... - cmSystemTools::ChangeDirectory(cwd.c_str()); continue; } fname += "/"; @@ -133,6 +131,7 @@ bool cmCTestSubdirCommand return false; } } + cmSystemTools::ChangeDirectory(cwd.c_str()); return true; } @@ -1363,7 +1362,7 @@ void cmCTestTestHandler tempPath += filename; attempted.push_back(tempPath); attemptedConfigs.push_back(ctest->GetConfigType()); - // If the file is an OSX bundle then the configtyp + // If the file is an OSX bundle then the configtype // will be at the start of the path tempPath = ctest->GetConfigType(); tempPath += "/"; @@ -1374,7 +1373,7 @@ void cmCTestTestHandler } else { - // no config specified to try some options + // no config specified - try some options... tempPath = filepath; tempPath += "Release/"; tempPath += filename; diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 000bc85..167b992 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -175,6 +175,14 @@ int cmProcess::GetNextOutputLine(std::string& line, double timeout) // Record exit information. this->ExitValue = cmsysProcess_GetExitValue(this->Process); this->TotalTime = cmSystemTools::GetTime() - this->StartTime; + // Because of a processor clock scew the runtime may become slightly + // negative. If someone changed the system clock while the process was + // running this may be even more. Make sure not to report a negative + // duration here. + if (this->TotalTime <= 0.0) + { + this->TotalTime = 0.0; + } // std::cerr << "Time to run: " << this->TotalTime << "\n"; return cmsysProcess_Pipe_None; } diff --git a/Source/CursesDialog/form/frm_driver.c b/Source/CursesDialog/form/frm_driver.c index f234722..b9611bf 100644 --- a/Source/CursesDialog/form/frm_driver.c +++ b/Source/CursesDialog/form/frm_driver.c @@ -176,7 +176,7 @@ static int FE_Delete_Previous(FORM *); #define Address_Of_Current_Position_In_Buffer(form) \ Address_Of_Current_Position_In_Nth_Buffer(form,0) -/* Logic to decide wether or not a field is actually a field with +/* Logic to decide whether or not a field is actually a field with vertical or horizontal scrolling */ #define Is_Scroll_Field(field) \ (((field)->drows > (field)->rows) || \ @@ -2100,7 +2100,7 @@ static int Insert_String(FORM *form, int row, char *txt, int len) | the wrapping. | | Return Values : E_OK - no wrapping required or wrapping -| was successfull +| was successful | E_REQUEST_DENIED - | E_SYSTEM_ERROR - some system error +--------------------------------------------------------------------------*/ @@ -3825,7 +3825,7 @@ int set_field_buffer(FIELD * field, int buffer, const char * value) (int)(1 + (vlen-len)/((field->rows+field->nrow)*field->cols)))) RETURN(E_SYSTEM_ERROR); - /* in this case we also have to check, wether or not the remaining + /* in this case we also have to check, whether or not the remaining characters in value are also printable for buffer 0. */ if (buffer==0) { diff --git a/Source/CursesDialog/form/fty_enum.c b/Source/CursesDialog/form/fty_enum.c index 8fc4cd7..59058a9 100644 --- a/Source/CursesDialog/form/fty_enum.c +++ b/Source/CursesDialog/form/fty_enum.c @@ -101,7 +101,7 @@ static void Free_Enum_Type(void * argp) | const unsigned char * buf, | bool ccase ) | -| Description : Check wether or not the text in 'buf' matches the +| Description : Check whether or not the text in 'buf' matches the | text in 's', at least partial. | | Return Values : NOMATCH - buffer doesn't match diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index c0dde1c..4d62f72 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -28,6 +28,7 @@ #include <QShortcut> #include <QKeySequence> #include <QMacInstallDialog.h> +#include <QInputDialog> #include "QCMake.h" #include "QCMakeCacheView.h" @@ -122,6 +123,22 @@ CMakeSetupDialog::CMakeSetupDialog() QObject::connect(this->InstallForCommandLineAction, SIGNAL(triggered(bool)), this, SLOT(doInstallForCommandLine())); #endif + ToolsMenu->addSeparator(); + ToolsMenu->addAction(tr("&Find in Output..."), + this, SLOT(doOutputFindDialog()), + QKeySequence::Find); + ToolsMenu->addAction(tr("Find Next"), + this, SLOT(doOutputFindNext()), + QKeySequence::FindNext); + ToolsMenu->addAction(tr("Find Previous"), + this, SLOT(doOutputFindPrev()), + QKeySequence::FindPrevious); + ToolsMenu->addAction(tr("Goto Next Error"), + this, SLOT(doOutputErrorNext()), + QKeySequence(Qt::Key_F8)); // in Visual Studio + new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Period), + this, SLOT(doOutputErrorNext())); // in Eclipse + QMenu* OptionsMenu = this->menuBar()->addMenu(tr("&Options")); this->SuppressDevWarningsAction = OptionsMenu->addAction(tr("&Suppress dev Warnings (-Wno-dev)")); @@ -154,10 +171,6 @@ CMakeSetupDialog::CMakeSetupDialog() QObject::connect(a, SIGNAL(triggered(bool)), this, SLOT(doHelp())); - QShortcut* filterShortcut = new QShortcut(QKeySequence::Find, this); - QObject::connect(filterShortcut, SIGNAL(activated()), - this, SLOT(startSearch())); - this->setAcceptDrops(true); // get the saved binary directories @@ -172,6 +185,10 @@ CMakeSetupDialog::CMakeSetupDialog() this->Output->setFont(outputFont); this->ErrorFormat.setForeground(QBrush(Qt::red)); + this->Output->setContextMenuPolicy(Qt::CustomContextMenu); + connect(this->Output, SIGNAL(customContextMenuRequested(const QPoint&)), + this, SLOT(doOutputContextMenu(const QPoint &))); + // start the cmake worker thread this->CMakeThread = new QCMakeThread(this); QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()), @@ -637,7 +654,13 @@ void CMakeSetupDialog::showProgress(const QString& /*msg*/, float percent) void CMakeSetupDialog::error(const QString& msg) { this->Output->setCurrentCharFormat(this->ErrorFormat); - this->Output->append(msg); + //QTextEdit will terminate the msg with a ParagraphSeparator, but it also replaces + //all newlines with ParagraphSeparators. By replacing the newlines by ourself, one + //error msg will be one paragraph. + QString paragraph(msg); + paragraph.replace(QLatin1Char('\n'), QChar::LineSeparator); + this->Output->append(paragraph); + } void CMakeSetupDialog::message(const QString& msg) @@ -1149,4 +1172,134 @@ void CMakeSetupDialog::setSearchFilter(const QString& str) this->CacheValues->setSearchFilter(str); } +void CMakeSetupDialog::doOutputContextMenu(const QPoint &pt) +{ + QMenu *menu = this->Output->createStandardContextMenu(); + + menu->addSeparator(); + menu->addAction(tr("Find..."), + this, SLOT(doOutputFindDialog()), QKeySequence::Find); + menu->addAction(tr("Find Next"), + this, SLOT(doOutputFindNext()), QKeySequence::FindNext); + menu->addAction(tr("Find Previous"), + this, SLOT(doOutputFindPrev()), QKeySequence::FindPrevious); + menu->addSeparator(); + menu->addAction(tr("Goto Next Error"), + this, SLOT(doOutputErrorNext()), QKeySequence(Qt::Key_F8)); + + menu->exec(this->Output->mapToGlobal(pt)); + delete menu; +} + +void CMakeSetupDialog::doOutputFindDialog() +{ + QStringList strings(this->FindHistory); + + QString selection = this->Output->textCursor().selectedText(); + if (!selection.isEmpty() && + !selection.contains(QChar::ParagraphSeparator) && + !selection.contains(QChar::LineSeparator)) + { + strings.push_front(selection); + } + + bool ok; + QString search = QInputDialog::getItem(this, tr("Find in Output"), + tr("Find:"), strings, 0, true, &ok); + if (ok && !search.isEmpty()) + { + if (!this->FindHistory.contains(search)) + { + this->FindHistory.push_front(search); + } + doOutputFindNext(); + } +} + +void CMakeSetupDialog::doOutputFindPrev() +{ + doOutputFindNext(false); +} + +void CMakeSetupDialog::doOutputFindNext(bool directionForward) +{ + if (this->FindHistory.isEmpty()) + { + doOutputFindDialog(); //will re-call this function again + return; + } + + QString search = this->FindHistory.front(); + + QTextCursor cursor = this->Output->textCursor(); + QTextDocument* document = this->Output->document(); + QTextDocument::FindFlags flags; + if (!directionForward) + { + flags |= QTextDocument::FindBackward; + } + + cursor = document->find(search, cursor, flags); + + if (cursor.isNull()) + { + // first search found nothing, wrap around and search again + cursor = this->Output->textCursor(); + cursor.movePosition(directionForward ? QTextCursor::Start + : QTextCursor::End); + cursor = document->find(search, cursor, flags); + } + + if (cursor.hasSelection()) + { + this->Output->setTextCursor(cursor); + } +} + +void CMakeSetupDialog::doOutputErrorNext() +{ + QTextCursor cursor = this->Output->textCursor(); + bool atEnd = false; + // move cursor out of current error-block + if (cursor.blockCharFormat() == this->ErrorFormat) + { + atEnd = !cursor.movePosition(QTextCursor::NextBlock); + } + + // move cursor to next error-block + while (cursor.blockCharFormat() != this->ErrorFormat && !atEnd) + { + atEnd = !cursor.movePosition(QTextCursor::NextBlock); + } + + if (atEnd) + { + // first search found nothing, wrap around and search again + atEnd = !cursor.movePosition(QTextCursor::Start); + + // move cursor to next error-block + while (cursor.blockCharFormat() != this->ErrorFormat && !atEnd) + { + atEnd = !cursor.movePosition(QTextCursor::NextBlock); + } + } + + if (!atEnd) + { + cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + + QTextCharFormat selectionFormat; + selectionFormat.setBackground(Qt::yellow); + QTextEdit::ExtraSelection extraSelection = {cursor, selectionFormat}; + this->Output->setExtraSelections(QList<QTextEdit::ExtraSelection>() + << extraSelection); + + // make the whole error-block visible + this->Output->setTextCursor(cursor); + + // remove the selection to see the extraSelection + cursor.setPosition(cursor.anchor()); + this->Output->setTextCursor(cursor); + } +} diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h index 2599675..963c7d1 100644 --- a/Source/QtDialog/CMakeSetupDialog.h +++ b/Source/QtDialog/CMakeSetupDialog.h @@ -77,6 +77,11 @@ protected slots: bool doConfigureInternal(); bool doGenerateInternal(); void exitLoop(int); + void doOutputContextMenu(const QPoint &); + void doOutputFindDialog(); + void doOutputFindNext(bool directionForward = true); + void doOutputFindPrev(); + void doOutputErrorNext(); protected: @@ -106,6 +111,7 @@ protected: QTextCharFormat MessageFormat; QStringList AddVariableCompletions; + QStringList FindHistory; QEventLoop LocalLoop; diff --git a/Source/QtDialog/CMakeSetupDialog.ui b/Source/QtDialog/CMakeSetupDialog.ui index dc8ee3f..98da249 100644 --- a/Source/QtDialog/CMakeSetupDialog.ui +++ b/Source/QtDialog/CMakeSetupDialog.ui @@ -107,7 +107,10 @@ </sizepolicy> </property> <property name="text"> - <string>Search:</string> + <string>S&earch:</string> + </property> + <property name="buddy"> + <cstring>Search</cstring> </property> </widget> </item> diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx index 6006758..bae6a30 100644 --- a/Source/QtDialog/QCMakeCacheView.cxx +++ b/Source/QtDialog/QCMakeCacheView.cxx @@ -177,7 +177,7 @@ QModelIndex QCMakeCacheView::moveCursor(CursorAction act, void QCMakeCacheView::setShowAdvanced(bool s) { #if QT_VERSION >= 040300 - // new 4.3 api that needs to be called. what about an older Qt? + // new 4.3 API that needs to be called. what about an older Qt? this->SearchFilter->invalidate(); #endif diff --git a/Source/cmAddDefinitionsCommand.h b/Source/cmAddDefinitionsCommand.h index 7bb3767..6705d11 100644 --- a/Source/cmAddDefinitionsCommand.h +++ b/Source/cmAddDefinitionsCommand.h @@ -63,7 +63,7 @@ public: "but it was originally intended to add preprocessor definitions. " "Flags beginning in -D or /D that look like preprocessor definitions " "are automatically added to the COMPILE_DEFINITIONS property for " - "the current directory. Definitions with non-trival values may be " + "the current directory. Definitions with non-trivial values may be " "left in the set of flags instead of being converted for reasons of " "backwards compatibility. See documentation of the directory, " "target, and source file COMPILE_DEFINITIONS properties for details " diff --git a/Source/cmAddSubDirectoryCommand.h b/Source/cmAddSubDirectoryCommand.h index fa322b0..e7f907c 100644 --- a/Source/cmAddSubDirectoryCommand.h +++ b/Source/cmAddSubDirectoryCommand.h @@ -61,7 +61,7 @@ public: " add_subdirectory(source_dir [binary_dir] \n" " [EXCLUDE_FROM_ALL])\n" "Add a subdirectory to the build. The source_dir specifies the " - "directory in which the source CmakeLists.txt and code files are " + "directory in which the source CMakeLists.txt and code files are " "located. If it is a relative " "path it will be evaluated with respect to the current " "directory (the typical usage), but it may also be an absolute path. " diff --git a/Source/cmBootstrapCommands.cxx b/Source/cmBootstrapCommands.cxx index e3a2ad4..1b7a751 100644 --- a/Source/cmBootstrapCommands.cxx +++ b/Source/cmBootstrapCommands.cxx @@ -52,6 +52,7 @@ #include "cmFindProgramCommand.cxx" #include "cmForEachCommand.cxx" #include "cmFunctionCommand.cxx" +#include "cmGeneratorExpressionEvaluationFile.cxx" #include "cmGetCMakePropertyCommand.cxx" #include "cmGetDirectoryPropertyCommand.cxx" #include "cmGetFilenameComponentCommand.cxx" diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx index 91d55a5..b6e2569 100644 --- a/Source/cmBuildCommand.cxx +++ b/Source/cmBuildCommand.cxx @@ -122,7 +122,7 @@ bool cmBuildCommand // std::string makecommand = this->Makefile->GetLocalGenerator() ->GetGlobalGenerator()->GenerateBuildCommand - (makeprogram, project_name, 0, target, configuration, true, false); + (makeprogram, project_name, 0, 0, target, configuration, true, false); this->Makefile->AddDefinition(variable, makecommand.c_str()); @@ -153,7 +153,7 @@ bool cmBuildCommand std::string makecommand = this->Makefile->GetLocalGenerator() ->GetGlobalGenerator()->GenerateBuildCommand - (makeprogram.c_str(), this->Makefile->GetProjectName(), 0, + (makeprogram.c_str(), this->Makefile->GetProjectName(), 0, 0, 0, configType.c_str(), true, false); if(cacheValue) diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 322a6a2..69ffb97 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -294,6 +294,7 @@ cmCTest::cmCTest() { this->LabelSummary = true; this->ParallelLevel = 1; + this->ParallelLevelSetInCli = false; this->SubmitIndex = 0; this->Failover = false; this->BatchJobs = false; @@ -1999,11 +2000,13 @@ void cmCTest::HandleCommandLineArguments(size_t &i, i++; int plevel = atoi(args[i].c_str()); this->SetParallelLevel(plevel); + this->ParallelLevelSetInCli = true; } else if(arg.find("-j") == 0) { int plevel = atoi(arg.substr(2).c_str()); this->SetParallelLevel(plevel); + this->ParallelLevelSetInCli = true; } if(this->CheckArgument(arg, "--no-compress-output")) @@ -2398,6 +2401,14 @@ int cmCTest::Run(std::vector<std::string> &args, std::string* output) } } // the close of the for argument loop + if (!this->ParallelLevelSetInCli) + { + if (const char *parallel = cmSystemTools::GetEnv("CTEST_PARALLEL_LEVEL")) + { + int plevel = atoi(parallel); + this->SetParallelLevel(plevel); + } + } // now what sould cmake do? if --build-and-test was specified then // we run the build and test handler and return @@ -2413,7 +2424,7 @@ int cmCTest::Run(std::vector<std::string> &args, std::string* output) #endif if(retv != 0) { - cmCTestLog(this, DEBUG, "build and test failing returing: " << retv + cmCTestLog(this, DEBUG, "build and test failing returning: " << retv << std::endl); } return retv; diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 587a6db..5dd35ce 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -485,6 +485,7 @@ private: int MaxTestNameWidth; int ParallelLevel; + bool ParallelLevelSetInCli; int CompatibilityMode; diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index 3d5b24b..864df8e 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -491,7 +491,7 @@ bool cmCacheManager::SaveCache(const char* path) << "# The syntax for the file is as follows:\n" << "# KEY:TYPE=VALUE\n" << "# KEY is the name of a variable in the cache.\n" - << "# TYPE is a hint to GUI's for the type of VALUE, DO NOT EDIT " + << "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT " "TYPE!." << std::endl << "# VALUE is the current value for the KEY.\n\n"; diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h index 4a5ee45..a5e5eee 100644 --- a/Source/cmCacheManager.h +++ b/Source/cmCacheManager.h @@ -82,7 +82,7 @@ public: { this->Find(key); } - } + } private: CacheEntry const& GetEntry() const { return this->Position->second; } CacheEntry& GetEntry() { return this->Position->second; } diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 9affeff..02495c4 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -882,7 +882,8 @@ void cmComputeLinkInformation::ComputeItemParserInfo() } // Compute a regex to match link extensions. - std::string libext = this->CreateExtensionRegex(this->LinkExtensions); + std::string libext = this->CreateExtensionRegex(this->LinkExtensions, + LinkUnknown); // Create regex to remove any library extension. std::string reg("(.*)"); @@ -916,7 +917,8 @@ void cmComputeLinkInformation::ComputeItemParserInfo() if(!this->StaticLinkExtensions.empty()) { std::string reg_static = reg; - reg_static += this->CreateExtensionRegex(this->StaticLinkExtensions); + reg_static += this->CreateExtensionRegex(this->StaticLinkExtensions, + LinkStatic); #ifdef CM_COMPUTE_LINK_INFO_DEBUG fprintf(stderr, "static regex [%s]\n", reg_static.c_str()); #endif @@ -928,7 +930,7 @@ void cmComputeLinkInformation::ComputeItemParserInfo() { std::string reg_shared = reg; this->SharedRegexString = - this->CreateExtensionRegex(this->SharedLinkExtensions); + this->CreateExtensionRegex(this->SharedLinkExtensions, LinkShared); reg_shared += this->SharedRegexString; #ifdef CM_COMPUTE_LINK_INFO_DEBUG fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str()); @@ -966,7 +968,7 @@ void cmComputeLinkInformation::AddLinkExtension(const char* e, LinkType type) //---------------------------------------------------------------------------- std::string cmComputeLinkInformation -::CreateExtensionRegex(std::vector<std::string> const& exts) +::CreateExtensionRegex(std::vector<std::string> const& exts, LinkType type) { // Build a list of extension choices. std::string libext = "("; @@ -995,6 +997,10 @@ cmComputeLinkInformation { libext += "(\\.[0-9]+\\.[0-9]+)?"; } + else if(type == LinkShared) + { + libext += "(\\.[0-9]+)?"; + } libext += "$"; return libext; diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 1a76922..e6ee871 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -134,7 +134,8 @@ private: bool OpenBSD; void AddLinkPrefix(const char* p); void AddLinkExtension(const char* e, LinkType type); - std::string CreateExtensionRegex(std::vector<std::string> const& exts); + std::string CreateExtensionRegex(std::vector<std::string> const& exts, + LinkType type); std::string NoCaseExpression(const char* str); // Handling of link items. diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 9f38b25..85e49a9 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -111,7 +111,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) ++i) { extraArgs++; - libsToLink += argv[i] + " "; + libsToLink += "\"" + cmSystemTools::TrimWhitespace(argv[i]) + "\" "; cmTarget *tgt = this->Makefile->FindTargetToUse(argv[i].c_str()); if (!tgt) { diff --git a/Source/cmDocumentCompileDefinitions.h b/Source/cmDocumentCompileDefinitions.h index ef3b3e7..d15bd6d 100644 --- a/Source/cmDocumentCompileDefinitions.h +++ b/Source/cmDocumentCompileDefinitions.h @@ -23,7 +23,7 @@ "in a (configured) header file. Then report the limitation. " \ "Known limitations include:\n" \ " # - broken almost everywhere\n" \ - " ; - broken in VS IDE and Borland Makefiles\n" \ + " ; - broken in VS IDE 7.0 and Borland Makefiles\n" \ " , - broken in VS IDE\n" \ " % - broken in some cases in NMake\n" \ " & | - broken in some cases on MinGW\n" \ diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h index 6cc3f25..656810d 100644 --- a/Source/cmDocumentGeneratorExpressions.h +++ b/Source/cmDocumentGeneratorExpressions.h @@ -13,7 +13,7 @@ #define cmDocumentGeneratorExpressions_h #define CM_DOCUMENT_ADD_TEST_GENERATOR_EXPRESSIONS \ - "Generator expressions are evaluted during build system generation " \ + "Generator expressions are evaluated during build system generation " \ "to produce information specific to each build configuration. " \ "Valid expressions are:\n" \ " $<0:...> = empty string (ignores \"...\")\n" \ @@ -28,6 +28,8 @@ "strings which contain a ',' for example.\n" \ " $<SEMICOLON> = A literal ';'. Used to prevent " \ "list expansion on an argument with ';'.\n" \ + " $<JOIN:list,...> = joins the list with the content of " \ + "\"...\"\n" \ " $<TARGET_NAME:...> = Marks ... as being the name of a " \ "target. This is required if exporting targets to multiple " \ "dependent export sets. The '...' must be a literal name of a " \ @@ -72,4 +74,12 @@ "the target on which the generator expression is evaluated.\n" \ "" +#define CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS \ + "Language related expressions:\n" \ + " $<LINK_LANGUAGE> = The link language of the target " \ + "being generated.\n" \ + " $<LINK_LANGUAGE:lang> = '1' if the link language of the " \ + "target being generated matches lang, else '0'.\n" \ + "" + #endif diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index 50509a0..b383265 100644 --- a/Source/cmDocumentVariables.cxx +++ b/Source/cmDocumentVariables.cxx @@ -10,7 +10,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_AR", cmProperty::VARIABLE, "Name of archiving tool for static libraries.", - "This specifies name of the program that creates archive " + "This specifies the name of the program that creates archive " "or static libraries.",false, "Variables that Provide Information"); @@ -129,9 +129,9 @@ void cmDocumentVariables::DefineVariables(cmake* cm) " needed to build the output of CMake. If the " "generator selected was Visual Studio 6, the " "CMAKE_BUILD_TOOL will be set to msdev, for " - "Unix makefiles it will be set to make or gmake, " + "Unix Makefiles it will be set to make or gmake, " "and for Visual Studio 7 it set to devenv. For " - "Nmake Makefiles the value is nmake. This can be " + "NMake Makefiles the value is nmake. This can be " "useful for adding special flags and commands based" " on the final build environment. ", false, "Variables that Provide Information"); @@ -152,7 +152,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_CACHE_MAJOR_VERSION", cmProperty::VARIABLE, "Major version of CMake used to create the CMakeCache.txt file", - "This is stores the major version of CMake used to " + "This stores the major version of CMake used to " "write a CMake cache file. It is only different when " "a different version of CMake is run on a previously " "created cache file.", false, @@ -160,7 +160,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_CACHE_MINOR_VERSION", cmProperty::VARIABLE, "Minor version of CMake used to create the CMakeCache.txt file", - "This is stores the minor version of CMake used to " + "This stores the minor version of CMake used to " "write a CMake cache file. It is only different when " "a different version of CMake is run on a previously " "created cache file.", false, @@ -169,7 +169,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_CACHE_PATCH_VERSION", cmProperty::VARIABLE, "Patch version of CMake used to create the CMakeCache.txt file", - "This is stores the patch version of CMake used to " + "This stores the patch version of CMake used to " "write a CMake cache file. It is only different when " "a different version of CMake is run on a previously " "created cache file.", false, @@ -270,12 +270,13 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_LINK_LIBRARY_SUFFIX", cmProperty::VARIABLE, "The suffix for libraries that you link to.", - "The suffix to use for the end of a library, .lib on Windows.",false, + "The suffix to use for the end of a library filename, .lib on Windows." + ,false, "Variables that Provide Information"); cm->DefineProperty ("CMAKE_EXECUTABLE_SUFFIX", cmProperty::VARIABLE, "The suffix for executables on this platform.", - "The suffix to use for the end of an executable if any, " + "The suffix to use for the end of an executable filename if any, " ".exe on Windows." "\n" "CMAKE_EXECUTABLE_SUFFIX_<LANG> overrides this for language <LANG>." @@ -452,8 +453,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ,false, "Variables that Provide Information"); cm->DefineProperty ("CMAKE_IMPORT_LIBRARY_SUFFIX", cmProperty::VARIABLE, - "The suffix for import libraries that you link to.", - "The suffix to use for the end of an import library if used " + "The suffix for import libraries that you link to.", + "The suffix to use for the end of an import library filename if used " "on this platform." "\n" "CMAKE_IMPORT_LIBRARY_SUFFIX_<LANG> overrides this for language <LANG>." @@ -468,7 +469,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_SHARED_LIBRARY_SUFFIX", cmProperty::VARIABLE, "The suffix for shared libraries that you link to.", - "The suffix to use for the end of a shared library, .dll on Windows." + "The suffix to use for the end of a shared library filename, " + ".dll on Windows." "\n" "CMAKE_SHARED_LIBRARY_SUFFIX_<LANG> overrides this for language <LANG>." ,false, "Variables that Provide Information"); @@ -482,7 +484,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_SHARED_MODULE_SUFFIX", cmProperty::VARIABLE, "The suffix for shared libraries that you link to.", - "The suffix to use for the end of a loadable module on this platform" + "The suffix to use for the end of a loadable module filename " + "on this platform" "\n" "CMAKE_SHARED_MODULE_SUFFIX_<LANG> overrides this for language <LANG>." ,false, "Variables that Provide Information"); @@ -496,7 +499,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_STATIC_LIBRARY_SUFFIX", cmProperty::VARIABLE, "The suffix for static libraries that you link to.", - "The suffix to use for the end of a static library, .lib on Windows." + "The suffix to use for the end of a static library filename, " + ".lib on Windows." "\n" "CMAKE_STATIC_LIBRARY_SUFFIX_<LANG> overrides this for language <LANG>." ,false, "Variables that Provide Information"); @@ -577,26 +581,37 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_CONFIGURATION_TYPES", cmProperty::VARIABLE, - "Specifies the available build types.", - "This specifies what build types will be available such as " - "Debug, Release, RelWithDebInfo etc. This has reasonable defaults " - "on most platforms. But can be extended to provide other " - "build types. See also CMAKE_BUILD_TYPE.", - false, + "Specifies the available build types on multi-config generators.", + "This specifies what build types (configurations) will be available " + "such as Debug, Release, RelWithDebInfo etc. " + "This has reasonable defaults on most platforms, " + "but can be extended to provide other build types. " + "See also CMAKE_BUILD_TYPE for details of managing configuration data, " + "and CMAKE_CFG_INTDIR." + ,false, "Variables That Change Behavior"); cm->DefineProperty ("CMAKE_BUILD_TYPE", cmProperty::VARIABLE, - "Specifies the build type for make based generators.", - "This specifies what build type will be built in this tree. " - " Possible values are empty, Debug, Release, RelWithDebInfo" - " and MinSizeRel. This variable is only supported for " - "make based generators. If this variable is supported, " - "then CMake will also provide initial values for the " - "variables with the name " - " CMAKE_C_FLAGS_[DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL]." - " For example, if CMAKE_BUILD_TYPE is Debug, then " - "CMAKE_C_FLAGS_DEBUG will be added to the CMAKE_C_FLAGS.",false, + "Specifies the build type on single-configuration generators.", + "This statically specifies what build type (configuration) " + "will be built in this build tree. Possible values are " + "empty, Debug, Release, RelWithDebInfo and MinSizeRel. " + "This variable is only meaningful to single-configuration generators " + "(such as make and Ninja) i.e. " + "those which choose a single configuration " + "when CMake runs to generate a build tree as opposed to " + "multi-configuration generators which offer selection of the build " + "configuration within the generated build environment. " + "There are many per-config properties and variables " + "(usually following clean SOME_VAR_<CONFIG> order conventions), " + "such as CMAKE_C_FLAGS_<CONFIG>, specified as uppercase: " + "CMAKE_C_FLAGS_[DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL]. " + "For example, in a build tree configured " + "to build type Debug, CMake will see to having " + "CMAKE_C_FLAGS_DEBUG settings get added to the CMAKE_C_FLAGS settings. " + "See also CMAKE_CONFIGURATION_TYPES." + ,false, "Variables That Change Behavior"); cm->DefineProperty @@ -616,7 +631,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_INSTALL_PREFIX", cmProperty::VARIABLE, "Install directory used by install.", "If \"make install\" is invoked or INSTALL is built" - ", this directory is pre-pended onto all install " + ", this directory is prepended onto all install " "directories. This variable defaults to /usr/local" " on UNIX and c:/Program Files on Windows.\n" "On UNIX one can use the DESTDIR mechanism in order" @@ -627,11 +642,11 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "It is usually invoked like this:\n" " make DESTDIR=/home/john install\n" "which will install the concerned software using the" - " installation prefix, e.g. \"/usr/local\" pre-pended with " + " installation prefix, e.g. \"/usr/local\" prepended with " "the DESTDIR value which finally gives \"/home/john/usr/local\".\n" "WARNING: DESTDIR may not be used on Windows because installation" " prefix usually contains a drive letter like in \"C:/Program Files\"" - " which cannot be pre-pended with some other prefix." + " which cannot be prepended with some other prefix." ,false, "Variables That Change Behavior"); @@ -792,7 +807,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "This switch should be used during the initial CMake run. Otherwise if " "the package has already been found in a previous CMake run, the " "variables which have been stored in the cache will still be there. " - "In the case it is recommended to remove the cache variables for " + "In that case it is recommended to remove the cache variables for " "this package from the cache using the cache editor or cmake -U", false, "Variables That Change Behavior"); @@ -888,7 +903,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) " an ABSOLUTE DESTINATION path.", "This variable is defined by CMake-generated cmake_install.cmake " "scripts." - " It can be used (read-only) by program or script that source those" + " It can be used (read-only) by programs or scripts that source those" " install scripts. This is used by some CPack generators (e.g. RPM).", false, "Variables That Change Behavior"); @@ -898,7 +913,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "Ask cmake_install.cmake script to warn each time a file with " "absolute INSTALL DESTINATION is encountered.", "This variable is used by CMake-generated cmake_install.cmake" - " scripts. If ones set this variable to ON while running the" + " scripts. If one sets this variable to ON while running the" " script, it may get warning messages from the script.", false, "Variables That Change Behavior"); @@ -909,7 +924,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "The fatal error is emitted before the installation of " "the offending file takes place." " This variable is used by CMake-generated cmake_install.cmake" - " scripts. If ones set this variable to ON while running the" + " scripts. If one sets this variable to ON while running the" " script, it may get fatal error messages from the script.",false, "Variables That Change Behavior"); @@ -940,7 +955,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "which CMake is targeting. On systems that " "have the uname command, this variable is set " "to the output of uname -s. Linux, Windows, " - " and Darwin for Mac OSX are the values found " + " and Darwin for Mac OS X are the values found " " on the big three operating systems." ,false, "Variables That Describe the System"); cm->DefineProperty @@ -999,20 +1014,22 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("APPLE", cmProperty::VARIABLE, - "True if running on Mac OSX.", - "Set to true on Mac OSX.",false, + "True if running on Mac OS X.", + "Set to true on Mac OS X." + ,false, "Variables That Describe the System"); cm->DefineProperty ("BORLAND", cmProperty::VARIABLE, - "True if the borland compiler is being used.", + "True if the Borland compiler is being used.", "This is set to true if the Borland compiler is being used.",false, "Variables That Describe the System"); cm->DefineProperty ("CYGWIN", cmProperty::VARIABLE, - "True for cygwin.", - "Set to true when using CYGWIN.",false, + "True for Cygwin.", + "Set to true when using Cygwin." + ,false, "Variables That Describe the System"); cm->DefineProperty @@ -1110,8 +1127,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_HOST_APPLE", cmProperty::VARIABLE, - "True for Apple OSXoperating systems.", - "Set to true when the host system is Apple OSX.", + "True for Apple OS X operating systems.", + "Set to true when the host system is Apple OS X.", false, "Variables That Describe the System"); @@ -1125,7 +1142,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_HOST_WIN32", cmProperty::VARIABLE, "True on windows systems, including win64.", - "Set to true when the host system is Windows and on cygwin.",false, + "Set to true when the host system is Windows and on Cygwin." + ,false, "Variables That Describe the System"); cm->DefineProperty @@ -1198,7 +1216,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_INSTALL_NAME_DIR", cmProperty::VARIABLE, - "Mac OSX directory name for installed targets.", + "Mac OS X directory name for installed targets.", "CMAKE_INSTALL_NAME_DIR is used to initialize the " "INSTALL_NAME_DIR property on all targets. See that target " "property for more information.", @@ -1252,7 +1270,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_PDB_OUTPUT_DIRECTORY", cmProperty::VARIABLE, - "Where to put all the MS debug symbol files.", + "Where to put all the MS debug symbol files from linker.", "This variable is used to initialize the " "PDB_OUTPUT_DIRECTORY property on all the targets. " "See that target property for additional information.", @@ -1358,44 +1376,47 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_EXE_LINKER_FLAGS", cmProperty::VARIABLE, - "Linker flags used to create executables.", - "Flags used by the linker when creating an executable.",false, + "Linker flags to be used to create executables.", + "These flags will be used by the linker when creating an executable." + ,false, "Variables that Control the Build"); cm->DefineProperty - ("CMAKE_EXE_LINKER_FLAGS_[CMAKE_BUILD_TYPE]", cmProperty::VARIABLE, - "Flag used when linking an executable.", + ("CMAKE_EXE_LINKER_FLAGS_<CONFIG>", cmProperty::VARIABLE, + "Flags to be used when linking an executable.", "Same as CMAKE_C_FLAGS_* but used by the linker " "when creating executables.",false, "Variables that Control the Build"); cm->DefineProperty ("CMAKE_LIBRARY_PATH_FLAG", cmProperty::VARIABLE, - "The flag used to add a library search path to a compiler.", - "The flag used to specify a library directory to the compiler. " + "The flag to be used to add a library search path to a compiler.", + "The flag will be used to specify a library directory to the compiler. " "On most compilers this is \"-L\".",false, "Variables that Control the Build"); cm->DefineProperty ("CMAKE_LINK_DEF_FILE_FLAG ", cmProperty::VARIABLE, - "Linker flag used to specify a .def file for dll creation.", - "The flag used to add a .def file when creating " - "a dll on Windows, this is only defined on Windows.",false, + "Linker flag to be used to specify a .def file for dll creation.", + "The flag will be used to add a .def file when creating " + "a dll on Windows; this is only defined on Windows." + ,false, "Variables that Control the Build"); cm->DefineProperty ("CMAKE_LINK_LIBRARY_FLAG", cmProperty::VARIABLE, - "Flag used to link a library into an executable.", - "The flag used to specify a library to link to an executable. " + "Flag to be used to link a library into an executable.", + "The flag will be used to specify a library to link to an executable. " "On most compilers this is \"-l\".",false, "Variables that Control the Build"); cm->DefineProperty ("CMAKE_LINK_LIBRARY_FILE_FLAG", cmProperty::VARIABLE, - "Flag used to link a library specified by a path to its file.", - "The flag used before a library file path is given to the linker. " + "Flag to be used to link a library specified by a path to its file.", + "The flag will be used before a library file path is given to the " + "linker. " "This is needed only on very few platforms.", false, "Variables that Control the Build"); cm->DefineProperty ("CMAKE_USE_RELATIVE_PATHS", cmProperty::VARIABLE, "Use relative paths (May not work!).", - "If this is set to TRUE, then the CMake will use " + "If this is set to TRUE, then CMake will use " "relative paths between the source and binary tree. " "This option does not work for more complicated " "projects, and relative paths are used when possible. " @@ -1591,7 +1612,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_<LANG>_COMPILE_OBJECT", cmProperty::VARIABLE, "Rule variable to compile a single object file.", "This is a rule variable that tells CMake how to " - "compile a single object file for for the language <LANG>.",false, + "compile a single object file for the language <LANG>." + ,false, "Variables for Languages"); cm->DefineProperty @@ -1727,8 +1749,9 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_<LANG>_LINK_EXECUTABLE ", cmProperty::VARIABLE, - "Rule variable to link and executable.", - "Rule variable to link and executable for the given language.",false, + "Rule variable to link an executable.", + "Rule variable to link an executable for the given language." + ,false, "Variables for Languages"); cm->DefineProperty @@ -1742,7 +1765,9 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS", cmProperty::VARIABLE, "Extensions of source files for the given language.", "This is the list of extensions for a " - "given languages source files.",false,"Variables for Languages"); + "given language's source files." + ,false, + "Variables for Languages"); cm->DefineProperty( "CMAKE_<LANG>_COMPILER_LOADED", cmProperty::VARIABLE, diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx index debde3b..4edacbb 100644 --- a/Source/cmDocumentation.cxx +++ b/Source/cmDocumentation.cxx @@ -53,7 +53,7 @@ static const char *cmModulesDocumentationDescription[][3] = "This is the documentation for the modules and scripts coming with CMake. " "Using these modules you can check the computer system for " "installed software packages, features of the compiler and the " - "existance of headers to name just a few.", 0}, + "existence of headers to name just a few.", 0}, {0,0,0} }; @@ -67,7 +67,7 @@ static const char *cmCustomModulesDocumentationDescription[][3] = "This is the documentation for additional modules and scripts for CMake. " "Using these modules you can check the computer system for " "installed software packages, features of the compiler and the " - "existance of headers to name just a few.", 0}, + "existence of headers to name just a few.", 0}, {0,0,0} }; diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 75a8aba..39184fb 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -30,7 +30,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) tei = this->Exports->begin(); tei != this->Exports->end(); ++tei) { - expectedTargets += sep + this->Namespace + (*tei)->GetName(); + expectedTargets += sep + this->Namespace + (*tei)->GetExportName(); sep = " "; cmTarget* te = *tei; if(this->ExportedTargets.insert(te).second) @@ -189,7 +189,7 @@ cmExportBuildFileGenerator::HandleMissingTarget( // Assume the target will be exported by another command. // Append it with the export namespace. link_libs += this->Namespace; - link_libs += dependee->GetName(); + link_libs += dependee->GetExportName(); } //---------------------------------------------------------------------------- diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 1cc1754..ffa8b51 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -210,7 +210,7 @@ bool cmExportCommand::HandlePackage(std::vector<std::string> const& args) else { cmOStringStream e; - e << "PACKAGE given unknown argumsnt: " << args[i]; + e << "PACKAGE given unknown argument: " << args[i]; this->SetError(e.str().c_str()); return false; } diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index c465a68..6bef017 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -376,7 +376,7 @@ void cmExportFileGenerator::GenerateInterfaceProperties(cmTarget *target, if (!properties.empty()) { std::string targetName = this->Namespace; - targetName += target->GetName(); + targetName += target->GetExportName(); os << "set_target_properties(" << targetName << " PROPERTIES\n"; for(ImportPropertyMap::const_iterator pi = properties.begin(); pi != properties.end(); ++pi) @@ -407,7 +407,7 @@ cmExportFileGenerator::AddTargetNamespace(std::string &input, } if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) { - input = this->Namespace + input; + input = this->Namespace + tgt->GetExportName(); } else { @@ -776,7 +776,8 @@ cmExportFileGenerator { // Construct the imported target name. std::string targetName = this->Namespace; - targetName += target->GetName(); + + targetName += target->GetExportName(); // Create the imported target. os << "# Create imported target " << targetName << "\n"; @@ -839,7 +840,8 @@ cmExportFileGenerator { // Construct the imported target name. std::string targetName = this->Namespace; - targetName += target->GetName(); + + targetName += target->GetExportName(); // Set the import properties. os << "# Import target \"" << targetName << "\" for configuration \"" @@ -958,7 +960,7 @@ cmExportFileGenerator { // Construct the imported target name. std::string targetName = this->Namespace; - targetName += target->GetName(); + targetName += target->GetExportName(); os << "list(APPEND _IMPORT_CHECK_TARGETS " << targetName << " )\n" "list(APPEND _IMPORT_CHECK_FILES_FOR_" << targetName << " "; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 9d1bdaf..dfcf472 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -47,7 +47,7 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) tei = this->IEGen->GetExportSet()->GetTargetExports()->begin(); tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei) { - expectedTargets += sep + this->Namespace + (*tei)->Target->GetName(); + expectedTargets += sep + this->Namespace + (*tei)->Target->GetExportName(); sep = " "; cmTargetExport const* te = *tei; if(this->ExportedTargets.insert(te->Target).second) @@ -389,13 +389,14 @@ cmExportInstallFileGenerator::HandleMissingTarget( std::string& link_libs, std::vector<std::string>& missingTargets, cmMakefile* mf, cmTarget* depender, cmTarget* dependee) { - std::string name = dependee->GetName(); + const std::string name = dependee->GetName(); std::vector<std::string> namespaces = this->FindNamespaces(mf, name); int targetOccurrences = (int)namespaces.size(); if (targetOccurrences == 1) { std::string missingTarget = namespaces[0]; - missingTarget += name; + + missingTarget += dependee->GetExportName(); link_libs += missingTarget; missingTargets.push_back(missingTarget); } diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 97ab086..6b02e15 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -39,6 +39,7 @@ cmExtraEclipseCDT4Generator this->SupportsVirtualFolders = true; this->GenerateLinkedResources = true; + this->SupportsGmakeErrorParser = true; } //---------------------------------------------------------------------------- @@ -50,7 +51,7 @@ void cmExtraEclipseCDT4Generator entry.Full = "Project files for Eclipse will be created in the top directory. " "In out of source builds, a linked resource to the top level source " - "directory will be created." + "directory will be created. " "Additionally a hierarchy of makefiles is generated into the " "build tree. The appropriate make program can build the project through " "the default make target. A \"make install\" target is also provided."; @@ -77,6 +78,10 @@ void cmExtraEclipseCDT4Generator::Generate() { this->SupportsVirtualFolders = false; } + if (version < 3007) // 3.7 is Indigo + { + this->SupportsGmakeErrorParser = false; + } } } @@ -403,8 +408,17 @@ void cmExtraEclipseCDT4Generator::CreateProjectFile() { fout << "org.eclipse.cdt.core.ICCErrorParser;"; } + + if (this->SupportsGmakeErrorParser) + { + fout << "org.eclipse.cdt.core.GmakeErrorParser;"; + } + else + { + fout << "org.eclipse.cdt.core.MakeErrorParser;"; + } + fout << - "org.eclipse.cdt.core.MakeErrorParser;" "org.eclipse.cdt.core.GCCErrorParser;" "org.eclipse.cdt.core.GASErrorParser;" "org.eclipse.cdt.core.GLDErrorParser;" diff --git a/Source/cmExtraEclipseCDT4Generator.h b/Source/cmExtraEclipseCDT4Generator.h index 31ad68d..b31cce7 100644 --- a/Source/cmExtraEclipseCDT4Generator.h +++ b/Source/cmExtraEclipseCDT4Generator.h @@ -111,6 +111,7 @@ private: bool GenerateSourceProject; bool GenerateLinkedResources; bool SupportsVirtualFolders; + bool SupportsGmakeErrorParser; }; diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index e4802d5..62e9194 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -457,7 +457,7 @@ cmExtraSublimeTextGenerator::ComputeFlagsForObject(cmSourceFile* source, } // Add source file specific flags. - lg->AppendFlags(flags, target->GetProperty("COMPILE_FLAGS")); + lg->AppendFlags(flags, source->GetProperty("COMPILE_FLAGS")); // TODO: Handle Apple frameworks. diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 018ce7e..e72e756 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -167,6 +167,10 @@ bool cmFileCommand { return this->HandleTimestampCommand(args); } + else if ( subCommand == "GENERATE" ) + { + return this->HandleGenerateCommand(args); + } std::string e = "does not recognize sub-command "+subCommand; this->SetError(e.c_str()); @@ -1970,7 +1974,7 @@ bool cmFileInstaller else { cmOStringStream e; - e << "Option TYPE given uknown value \"" << stype << "\"."; + e << "Option TYPE given unknown value \"" << stype << "\"."; this->FileCommand->SetError(e.str().c_str()); return false; } @@ -1985,7 +1989,7 @@ bool cmFileInstaller::HandleInstallDestination() // allow for / to be a valid destination if ( destination.size() < 2 && destination != "/" ) { - this->FileCommand->SetError("called with inapropriate arguments. " + this->FileCommand->SetError("called with inappropriate arguments. " "No DESTINATION provided or ."); return false; } @@ -3250,6 +3254,80 @@ cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args) } //---------------------------------------------------------------------------- +void cmFileCommand::AddEvaluationFile(const std::string &inputName, + const std::string &outputExpr, + const std::string &condition, + bool inputIsContent + ) +{ + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + + cmGeneratorExpression outputGe(lfbt); + cmsys::auto_ptr<cmCompiledGeneratorExpression> outputCge + = outputGe.Parse(outputExpr); + + cmGeneratorExpression conditionGe(lfbt); + cmsys::auto_ptr<cmCompiledGeneratorExpression> conditionCge + = conditionGe.Parse(condition); + + this->Makefile->GetLocalGenerator() + ->GetGlobalGenerator()->AddEvaluationFile(inputName, + outputCge, + this->Makefile, + conditionCge, + inputIsContent); +} + +//---------------------------------------------------------------------------- +bool cmFileCommand::HandleGenerateCommand( + std::vector<std::string> const& args) +{ + if (args.size() < 5) + { + this->SetError("Incorrect arguments to GENERATE subcommand."); + return false; + } + if (args[1] != "OUTPUT") + { + this->SetError("Incorrect arguments to GENERATE subcommand."); + return false; + } + std::string condition; + if (args.size() > 5) + { + if (args[5] != "CONDITION") + { + this->SetError("Incorrect arguments to GENERATE subcommand."); + return false; + } + if (args.size() != 7) + { + this->SetError("Incorrect arguments to GENERATE subcommand."); + return false; + } + condition = args[6]; + if (condition.empty()) + { + this->SetError("CONDITION of sub-command GENERATE must not be empty if " + "specified."); + return false; + } + } + std::string output = args[2]; + const bool inputIsContent = args[3] != "INPUT"; + if (inputIsContent && args[3] != "CONTENT") + { + this->SetError("Incorrect arguments to GENERATE subcommand."); + return false; + } + std::string input = args[4]; + + this->AddEvaluationFile(input, output, condition, inputIsContent); + return true; +} + +//---------------------------------------------------------------------------- bool cmFileCommand::HandleTimestampCommand( std::vector<std::string> const& args) { diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h index 5973fa7..586fee2 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -88,6 +88,9 @@ public: " file(UPLOAD filename url [INACTIVITY_TIMEOUT timeout]\n" " [TIMEOUT timeout] [STATUS status] [LOG log] [SHOW_PROGRESS])\n" " file(TIMESTAMP filename variable [<format string>] [UTC])\n" + " file(GENERATE OUTPUT output_file\n" + " <INPUT input_file|CONTENT input_content>\n" + " CONDITION expression)\n" "WRITE will write a message into a file called 'filename'. It " "overwrites the file if it already exists, and creates the file " "if it does not exist. (If the file is a build input, use " @@ -231,6 +234,15 @@ public: "it prints status messages, and NO_SOURCE_PERMISSIONS is default. " "Installation scripts generated by the install() command use this " "signature (with some undocumented options for internal use)." + "\n" + "GENERATE will write an <output_file> with content from an " + "<input_file>, or from <input_content>. The output is generated " + "conditionally based on the content of the <condition>. The file is " + "written at CMake generate-time and the input may contain generator " + "expressions. The <condition>, <output_file> and <input_file> may " + "also contain generator expressions. The <condition> must evaluate to " + "either '0' or '1'. The <output_file> must evaluate to a unique name " + "among all configurations and among all invocations of file(GENERATE)." // Undocumented INSTALL options: // - RENAME <name> // - OPTIONAL @@ -269,6 +281,13 @@ protected: bool HandleUploadCommand(std::vector<std::string> const& args); bool HandleTimestampCommand(std::vector<std::string> const& args); + bool HandleGenerateCommand(std::vector<std::string> const& args); + +private: + void AddEvaluationFile(const std::string &inputName, + const std::string &outputExpr, + const std::string &condition, + bool inputIsContent); }; diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 10b47b9..a126cd1 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -267,7 +267,7 @@ ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf) std::vector<std::string> expandedArguments; mf.ExpandArguments(lff.Arguments, expandedArguments); // if the endfunction has arguments then make sure - // they match the ones in the openeing function command + // they match the ones in the opening function command if ((expandedArguments.empty() || (expandedArguments[0] == this->Args[0]))) { diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx new file mode 100644 index 0000000..cab99ed --- /dev/null +++ b/Source/cmGeneratorExpressionEvaluationFile.cxx @@ -0,0 +1,151 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 Stephen Kelly <steveire@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmGeneratorExpressionEvaluationFile.h" + +#include "cmMakefile.h" + +#include <assert.h> + +//---------------------------------------------------------------------------- +cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile( + const std::string &input, + cmsys::auto_ptr<cmCompiledGeneratorExpression> outputFileExpr, + cmMakefile *makefile, + cmsys::auto_ptr<cmCompiledGeneratorExpression> condition, + bool inputIsContent) + : Input(input), + OutputFileExpr(outputFileExpr), + Makefile(makefile), + Condition(condition), + InputIsContent(inputIsContent) +{ +} + +//---------------------------------------------------------------------------- +void cmGeneratorExpressionEvaluationFile::Generate(const char *config, + cmCompiledGeneratorExpression* inputExpression, + std::map<std::string, std::string> &outputFiles) +{ + std::string rawCondition = this->Condition->GetInput(); + if (!rawCondition.empty()) + { + std::string condResult = this->Condition->Evaluate(this->Makefile, config); + if (condResult == "0") + { + return; + } + if (condResult != "1") + { + cmOStringStream e; + e << "Evaluation file condition \"" << rawCondition << "\" did " + "not evaluate to valid content. Got \"" << condResult << "\"."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); + return; + } + } + + const std::string outputFileName + = this->OutputFileExpr->Evaluate(this->Makefile, config); + const std::string outputContent + = inputExpression->Evaluate(this->Makefile, config); + + std::map<std::string, std::string>::iterator it + = outputFiles.find(outputFileName); + + if(it != outputFiles.end()) + { + if (it->second == outputContent) + { + return; + } + cmOStringStream e; + e << "Evaluation file to be written multiple times for different " + "configurations with different content:\n " << outputFileName; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); + return; + } + + this->Files.push_back(outputFileName); + outputFiles[outputFileName] = outputContent; + + std::ofstream fout(outputFileName.c_str()); + + if(!fout) + { + cmOStringStream e; + e << "Evaluation file \"" << outputFileName << "\" cannot be written."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); + return; + } + + fout << outputContent; + + fout.close(); +} + +//---------------------------------------------------------------------------- +void cmGeneratorExpressionEvaluationFile::Generate() +{ + std::string inputContent; + if (this->InputIsContent) + { + inputContent = this->Input; + } + else + { + std::ifstream fin(this->Input.c_str()); + if(!fin) + { + cmOStringStream e; + e << "Evaluation file \"" << this->Input << "\" cannot be read."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); + return; + } + + std::string line; + std::string sep; + while(cmSystemTools::GetLineFromStream(fin, line)) + { + inputContent += sep + line; + sep = "\n"; + } + inputContent += sep; + } + + cmListFileBacktrace lfbt = this->OutputFileExpr->GetBacktrace(); + cmGeneratorExpression contentGE(lfbt); + cmsys::auto_ptr<cmCompiledGeneratorExpression> inputExpression + = contentGE.Parse(inputContent); + + std::map<std::string, std::string> outputFiles; + + std::vector<std::string> allConfigs; + this->Makefile->GetConfigurations(allConfigs); + + if (allConfigs.empty()) + { + this->Generate(0, inputExpression.get(), outputFiles); + } + else + { + for(std::vector<std::string>::const_iterator li = allConfigs.begin(); + li != allConfigs.end(); ++li) + { + this->Generate(li->c_str(), inputExpression.get(), outputFiles); + if(cmSystemTools::GetFatalErrorOccured()) + { + return; + } + } + } +} diff --git a/Source/cmGeneratorExpressionEvaluationFile.h b/Source/cmGeneratorExpressionEvaluationFile.h new file mode 100644 index 0000000..20ee5cb --- /dev/null +++ b/Source/cmGeneratorExpressionEvaluationFile.h @@ -0,0 +1,48 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 Stephen Kelly <steveire@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmGeneratorExpressionEvaluationFile_h +#define cmGeneratorExpressionEvaluationFile_h + +#include "cmStandardIncludes.h" +#include <cmsys/auto_ptr.hxx> + +#include "cmGeneratorExpression.h" + +//---------------------------------------------------------------------------- +class cmGeneratorExpressionEvaluationFile +{ +public: + cmGeneratorExpressionEvaluationFile(const std::string &input, + cmsys::auto_ptr<cmCompiledGeneratorExpression> outputFileExpr, + cmMakefile *makefile, + cmsys::auto_ptr<cmCompiledGeneratorExpression> condition, + bool inputIsContent); + + void Generate(); + + std::vector<std::string> GetFiles() const { return this->Files; } + +private: + void Generate(const char *config, + cmCompiledGeneratorExpression* inputExpression, + std::map<std::string, std::string> &outputFiles); + +private: + const std::string Input; + const cmsys::auto_ptr<cmCompiledGeneratorExpression> OutputFileExpr; + cmMakefile *Makefile; + const cmsys::auto_ptr<cmCompiledGeneratorExpression> Condition; + std::vector<std::string> Files; + const bool InputIsContent; +}; + +#endif diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 6618e83..df52368 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -45,13 +45,18 @@ void reportError(cmGeneratorExpressionContext *context, //---------------------------------------------------------------------------- struct cmGeneratorExpressionNode { + enum { + DynamicParameters = 0, + OneOrMoreParameters = -1, + ZeroOrMoreParameters = -2 + }; virtual ~cmGeneratorExpressionNode() {} virtual bool GeneratesContent() const { return true; } virtual bool RequiresLiteralInput() const { return false; } - virtual bool AcceptsSingleArbitraryContentParameter() const + virtual bool AcceptsArbitraryContentParameter() const { return false; } virtual int NumExpectedParameters() const { return 1; } @@ -70,7 +75,7 @@ static const struct ZeroNode : public cmGeneratorExpressionNode virtual bool GeneratesContent() const { return false; } - virtual bool AcceptsSingleArbitraryContentParameter() const { return true; } + virtual bool AcceptsArbitraryContentParameter() const { return true; } std::string Evaluate(const std::vector<std::string> &, cmGeneratorExpressionContext *, @@ -87,7 +92,7 @@ static const struct OneNode : public cmGeneratorExpressionNode { OneNode() {} - virtual bool AcceptsSingleArbitraryContentParameter() const { return true; } + virtual bool AcceptsArbitraryContentParameter() const { return true; } std::string Evaluate(const std::vector<std::string> &, cmGeneratorExpressionContext *, @@ -110,8 +115,7 @@ static const struct ZeroNode installInterfaceNode; static const struct OP ## Node : public cmGeneratorExpressionNode \ { \ OP ## Node () {} \ -/* We let -1 carry the meaning 'at least one' */ \ - virtual int NumExpectedParameters() const { return -1; } \ + virtual int NumExpectedParameters() const { return OneOrMoreParameters; } \ \ std::string Evaluate(const std::vector<std::string> ¶meters, \ cmGeneratorExpressionContext *context, \ @@ -306,6 +310,88 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode } } configurationTestNode; +//---------------------------------------------------------------------------- +static const struct LinkLanguageNode : public cmGeneratorExpressionNode +{ + LinkLanguageNode() {} + + virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *) const + { + if (parameters.size() != 0 && parameters.size() != 1) + { + reportError(context, content->GetOriginalExpression(), + "$<LINK_LANGUAGE> expression requires one or two parameters"); + return std::string(); + } + cmTarget* target = context->HeadTarget; + if (!target) + { + reportError(context, content->GetOriginalExpression(), + "$<LINK_LANGUAGE> may only be used with targets. It may not " + "be used with add_custom_command."); + } + + const char *lang = target->GetLinkerLanguage(context->Config); + if (parameters.size() == 0) + { + return lang ? lang : ""; + } + else + { + cmsys::RegularExpression langValidator; + langValidator.compile("^[A-Za-z0-9_]*$"); + if (!langValidator.find(parameters.begin()->c_str())) + { + reportError(context, content->GetOriginalExpression(), + "Expression syntax not recognized."); + return std::string(); + } + if (!lang) + { + return parameters.front().empty() ? "1" : "0"; + } + + if (strcmp(parameters.begin()->c_str(), lang) == 0) + { + return "1"; + } + return "0"; + } + } +} linkLanguageNode; + +static const struct JoinNode : public cmGeneratorExpressionNode +{ + JoinNode() {} + + virtual int NumExpectedParameters() const { return 2; } + + virtual bool AcceptsArbitraryContentParameter() const { return true; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + std::string result; + + std::vector<std::string> list; + cmSystemTools::ExpandListArgument(parameters.front(), list); + std::string sep; + for(std::vector<std::string>::const_iterator li = list.begin(); + li != list.end(); ++li) + { + result += sep + *li; + sep = parameters[1]; + } + return result; + } +} joinNode; //---------------------------------------------------------------------------- static const char* targetPropertyTransitiveWhitelist[] = { @@ -313,13 +399,66 @@ static const char* targetPropertyTransitiveWhitelist[] = { , "INTERFACE_COMPILE_DEFINITIONS" }; +std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, + cmTarget *target, + cmGeneratorExpressionContext *context, + cmGeneratorExpressionDAGChecker *dagChecker, + const std::string &interfacePropertyName) +{ + cmGeneratorExpression ge(context->Backtrace); + + std::string sep; + std::string depString; + for (std::vector<std::string>::const_iterator + it = libraries.begin(); + it != libraries.end(); ++it) + { + if (*it == target->GetName()) + { + // Broken code can have a target in its own link interface. + // Don't follow such link interface entries so as not to create a + // self-referencing loop. + continue; + } + if (context->Makefile->FindTargetToUse(it->c_str())) + { + depString += + sep + "$<TARGET_PROPERTY:" + *it + "," + interfacePropertyName + ">"; + sep = ";"; + } + } + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depString); + std::string linkedTargetsContent = cge->Evaluate(context->Makefile, + context->Config, + context->Quiet, + context->HeadTarget, + target, + dagChecker); + if (cge->GetHadContextSensitiveCondition()) + { + context->HadContextSensitiveCondition = true; + } + return linkedTargetsContent; +} + +//---------------------------------------------------------------------------- +struct TransitiveWhitelistCompare +{ + explicit TransitiveWhitelistCompare(const std::string &needle) + : Needle(needle) {} + bool operator() (const char *item) + { return strcmp(item, this->Needle.c_str()) == 0; } +private: + std::string Needle; +}; + //---------------------------------------------------------------------------- static const struct TargetPropertyNode : public cmGeneratorExpressionNode { TargetPropertyNode() {} // This node handles errors on parameter count itself. - virtual int NumExpectedParameters() const { return -1; } + virtual int NumExpectedParameters() const { return OneOrMoreParameters; } std::string Evaluate(const std::vector<std::string> ¶meters, cmGeneratorExpressionContext *context, @@ -485,49 +624,36 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS"; } - if (interfacePropertyName == "INTERFACE_INCLUDE_DIRECTORIES" - || interfacePropertyName == "INTERFACE_COMPILE_DEFINITIONS") + const char **transBegin = targetPropertyTransitiveWhitelist; + const char **transEnd = targetPropertyTransitiveWhitelist + + (sizeof(targetPropertyTransitiveWhitelist) / + sizeof(*targetPropertyTransitiveWhitelist)); + if (std::find_if(transBegin, transEnd, + TransitiveWhitelistCompare(propertyName)) != transEnd) { const cmTarget::LinkInterface *iface = target->GetLinkInterface( context->Config, context->HeadTarget); if(iface) { - cmGeneratorExpression ge(context->Backtrace); - - std::string sep; - std::string depString; - for (std::vector<std::string>::const_iterator - it = iface->Libraries.begin(); - it != iface->Libraries.end(); ++it) - { - if (*it == target->GetName()) - { - // Broken code can have a target in its own link interface. - // Don't follow such link interface entries so as not to create a - // self-referencing loop. - continue; - } - if (context->Makefile->FindTargetToUse(it->c_str())) - { - depString += - sep + "$<TARGET_PROPERTY:" + *it + "," - + interfacePropertyName + ">"; - sep = ";"; - } - } - cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = - ge.Parse(depString); - linkedTargetsContent = cge->Evaluate(context->Makefile, - context->Config, - context->Quiet, - context->HeadTarget, - target, - &dagChecker); - if (cge->GetHadContextSensitiveCondition()) - { - context->HadContextSensitiveCondition = true; - } + linkedTargetsContent = + getLinkedTargetsContent(iface->Libraries, target, + context, &dagChecker, + interfacePropertyName); + } + } + else if (std::find_if(transBegin, transEnd, + TransitiveWhitelistCompare(interfacePropertyName)) != transEnd) + { + const cmTarget::LinkImplementation *impl = target->GetLinkImplementation( + context->Config, + context->HeadTarget); + if(impl) + { + linkedTargetsContent = + getLinkedTargetsContent(impl->Libraries, target, + context, &dagChecker, + interfacePropertyName); } } @@ -600,7 +726,7 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode virtual bool GeneratesContent() const { return true; } - virtual bool AcceptsSingleArbitraryContentParameter() const { return true; } + virtual bool AcceptsArbitraryContentParameter() const { return true; } virtual bool RequiresLiteralInput() const { return true; } std::string Evaluate(const std::vector<std::string> ¶meters, @@ -933,6 +1059,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) return &configurationNode; else if (identifier == "CONFIG") return &configurationTestNode; + else if (identifier == "LINK_LANGUAGE") + return &linkLanguageNode; else if (identifier == "TARGET_FILE") return &targetFileNode; else if (identifier == "TARGET_LINKER_FILE") @@ -973,6 +1101,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) return &installInterfaceNode; else if (identifier == "INSTALL_PREFIX") return &installPrefixNode; + else if (identifier == "JOIN") + return &joinNode; return 0; } @@ -993,6 +1123,57 @@ std::string GeneratorExpressionContent::GetOriginalExpression() const } //---------------------------------------------------------------------------- +std::string GeneratorExpressionContent::ProcessArbitraryContent( + const cmGeneratorExpressionNode *node, + const std::string &identifier, + cmGeneratorExpressionContext *context, + cmGeneratorExpressionDAGChecker *dagChecker, + std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator + pit) const +{ + std::string result; + + const + std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator + pend = this->ParamChildren.end(); + for ( ; pit != pend; ++pit) + { + std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it + = pit->begin(); + const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end + = pit->end(); + for ( ; it != end; ++it) + { + if (node->RequiresLiteralInput()) + { + if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text) + { + reportError(context, this->GetOriginalExpression(), + "$<" + identifier + "> expression requires literal input."); + return std::string(); + } + } + result += (*it)->Evaluate(context, dagChecker); + if (context->HadError) + { + return std::string(); + } + } + if ((pit + 1) != pend) + { + result += ","; + } + } + if (node->RequiresLiteralInput()) + { + std::vector<std::string> parameters; + parameters.push_back(result); + return node->Evaluate(parameters, context, this, dagChecker); + } + return result; +} + +//---------------------------------------------------------------------------- std::string GeneratorExpressionContent::Evaluate( cmGeneratorExpressionContext *context, cmGeneratorExpressionDAGChecker *dagChecker) const @@ -1024,7 +1205,8 @@ std::string GeneratorExpressionContent::Evaluate( if (!node->GeneratesContent()) { - if (node->AcceptsSingleArbitraryContentParameter()) + if (node->NumExpectedParameters() == 1 + && node->AcceptsArbitraryContentParameter()) { if (this->ParamChildren.empty()) { @@ -1041,50 +1223,12 @@ std::string GeneratorExpressionContent::Evaluate( return std::string(); } - if (node->AcceptsSingleArbitraryContentParameter()) + if (node->NumExpectedParameters() == 1 + && node->AcceptsArbitraryContentParameter()) { - std::string result; - std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator - pit = this->ParamChildren.begin(); - const - std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator - pend = this->ParamChildren.end(); - for ( ; pit != pend; ++pit) - { - if (!result.empty()) - { - result += ","; - } - - std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it - = pit->begin(); - const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end - = pit->end(); - for ( ; it != end; ++it) - { - if (node->RequiresLiteralInput()) - { - if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text) - { - reportError(context, this->GetOriginalExpression(), - "$<" + identifier + "> expression requires literal input."); - return std::string(); - } - } - result += (*it)->Evaluate(context, dagChecker); - if (context->HadError) - { - return std::string(); - } - } - } - if (node->RequiresLiteralInput()) - { - std::vector<std::string> parameters; - parameters.push_back(result); - return node->Evaluate(parameters, context, this, dagChecker); - } - return result; + return this->ProcessArbitraryContent(node, identifier, context, + dagChecker, + this->ParamChildren.begin()); } std::vector<std::string> parameters; @@ -1105,12 +1249,15 @@ std::string GeneratorExpressionContent::EvaluateParameters( cmGeneratorExpressionDAGChecker *dagChecker, std::vector<std::string> ¶meters) const { + const int numExpected = node->NumExpectedParameters(); { std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator pit = this->ParamChildren.begin(); const std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator pend = this->ParamChildren.end(); + const bool acceptsArbitraryContent + = node->AcceptsArbitraryContentParameter(); for ( ; pit != pend; ++pit) { std::string parameter; @@ -1127,11 +1274,22 @@ std::string GeneratorExpressionContent::EvaluateParameters( } } parameters.push_back(parameter); + if (acceptsArbitraryContent + && parameters.size() == (unsigned int)numExpected - 1) + { + assert(pit != pend); + std::string lastParam = this->ProcessArbitraryContent(node, identifier, + context, + dagChecker, + pit + 1); + parameters.push_back(lastParam); + return std::string(); + } } } - int numExpected = node->NumExpectedParameters(); - if ((numExpected != -1 && (unsigned int)numExpected != parameters.size())) + if ((numExpected > cmGeneratorExpressionNode::DynamicParameters + && (unsigned int)numExpected != parameters.size())) { if (numExpected == 0) { @@ -1156,7 +1314,8 @@ std::string GeneratorExpressionContent::EvaluateParameters( return std::string(); } - if (numExpected == -1 && parameters.empty()) + if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters + && parameters.empty()) { reportError(context, this->GetOriginalExpression(), "$<" + identifier + "> expression requires at least one parameter."); @@ -1183,7 +1342,6 @@ GeneratorExpressionContent::~GeneratorExpressionContent() deleteAll(this->IdentifierChildren); typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector; - typedef std::vector<cmGeneratorExpressionToken> TokenVector; std::vector<EvaluatorVector>::const_iterator pit = this->ParamChildren.begin(); const std::vector<EvaluatorVector>::const_iterator pend = diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index ce7ad69..218abf1 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -129,6 +129,14 @@ private: cmGeneratorExpressionDAGChecker *dagChecker, std::vector<std::string> ¶meters) const; + std::string ProcessArbitraryContent( + const cmGeneratorExpressionNode *node, + const std::string &identifier, + cmGeneratorExpressionContext *context, + cmGeneratorExpressionDAGChecker *dagChecker, + std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator + pit) const; + private: std::vector<cmGeneratorExpressionEvaluator*> IdentifierChildren; std::vector<std::vector<cmGeneratorExpressionEvaluator*> > ParamChildren; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 335ba0f..f5d1560 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -98,6 +98,18 @@ void cmGeneratorTarget::ClassifySources() this->IDLSources.push_back(sf); if(isObjLib) { badObjLib.push_back(sf); } } + else if(ext == "resx") + { + // Build and save the name of the corresponding .h file + // This relationship will be used later when building the project files. + // Both names would have been auto generated from Visual Studio + // where the user supplied the file name and Visual Studio + // appended the suffix. + std::string resx = sf->GetFullPath(); + std::string hFileName = resx.substr(0, resx.find_last_of(".")) + ".h"; + this->ExpectedResxHeaders.insert(hFileName); + this->ResxSources.push_back(sf); + } else if(header.find(sf->GetFullPath().c_str())) { this->HeaderSources.push_back(sf); diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index cbcd8a5..5f7019d 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -44,11 +44,15 @@ public: std::vector<cmSourceFile*> ObjectSources; std::vector<cmSourceFile*> ExternalObjects; std::vector<cmSourceFile*> IDLSources; + std::vector<cmSourceFile*> ResxSources; + std::string ModuleDefinitionFile; std::map<cmSourceFile const*, std::string> Objects; std::set<cmSourceFile const*> ExplicitObjectName; + std::set<std::string> ExpectedResxHeaders; + /** Full path with trailing slash to the top-level directory holding object files for this target. Includes the build time config name placeholder if needed for the generator. */ diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx index fd1ad60..1d7fefc 100644 --- a/Source/cmGetFilenameComponentCommand.cxx +++ b/Source/cmGetFilenameComponentCommand.cxx @@ -58,7 +58,7 @@ bool cmGetFilenameComponentCommand } std::string storeArgs; std::string programArgs; - if (args[2] == "PATH") + if (args[2] == "DIRECTORY" || args[2] == "PATH") { result = cmSystemTools::GetFilenamePath(filename); } diff --git a/Source/cmGetFilenameComponentCommand.h b/Source/cmGetFilenameComponentCommand.h index f294daa..09af332 100644 --- a/Source/cmGetFilenameComponentCommand.h +++ b/Source/cmGetFilenameComponentCommand.h @@ -64,12 +64,13 @@ public: return " get_filename_component(<VAR> <FileName> <COMP> [CACHE])\n" "Set <VAR> to a component of <FileName>, where <COMP> is one of:\n" - " PATH = Directory without file name\n" + " DIRECTORY = Directory without file name\n" " NAME = File name without directory\n" " EXT = File name longest extension (.b.c from d/a.b.c)\n" " NAME_WE = File name without directory or longest extension\n" " ABSOLUTE = Full path to file\n" " REALPATH = Full path to existing file with symlinks resolved\n" + " PATH = Legacy alias for DIRECTORY (use for CMake <= 2.8.11)\n" "Paths are returned with forward slashes and have no trailing slahes. " "The longest file extension is always considered. " "If the optional CACHE argument is specified, the result variable is " diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index df14331..3496823 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -26,6 +26,7 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGeneratorExpression.h" +#include "cmGeneratorExpressionEvaluationFile.h" #include <cmsys/Directory.hxx> @@ -69,6 +70,13 @@ cmGlobalGenerator::~cmGlobalGenerator() { delete this->LocalGenerators[i]; } + for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator + li = this->EvaluationFiles.begin(); + li != this->EvaluationFiles.end(); + ++li) + { + delete *li; + } this->LocalGenerators.clear(); if (this->ExtraGenerator) @@ -423,7 +431,7 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages, { if (this->CMakeInstance->GetIsInTryCompile()) { - cmSystemTools::Error("This should not have happen. " + cmSystemTools::Error("This should not have happened. " "If you see this message, you are probably " "using a broken CMakeLists.txt file or a " "problematic release of CMake"); @@ -981,6 +989,8 @@ void cmGlobalGenerator::Generate() // Create per-target generator information. this->CreateGeneratorTargets(); + this->ProcessEvaluationFiles(); + // Compute the inter-target dependencies. if(!this->ComputeTargetDepends()) { @@ -1340,11 +1350,13 @@ int cmGlobalGenerator::TryCompile(const char *srcdir, const char *bindir, std::string cmGlobalGenerator ::GenerateBuildCommand(const char* makeProgram, const char *projectName, - const char* additionalOptions, const char *targetName, - const char* config, bool ignoreErrors, bool) + const char *projectDir, const char* additionalOptions, + const char *targetName, const char* config, + bool ignoreErrors, bool) { - // Project name and config are not used yet. + // Project name & dir and config are not used yet. (void)projectName; + (void)projectDir; (void)config; std::string makeCommand = @@ -1411,7 +1423,7 @@ int cmGlobalGenerator::Build( if (clean) { std::string cleanCommand = - this->GenerateBuildCommand(makeCommandCSTR, projectName, + this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, 0, "clean", config, false, fast); if(output) { @@ -1443,7 +1455,7 @@ int cmGlobalGenerator::Build( // now build std::string makeCommand = - this->GenerateBuildCommand(makeCommandCSTR, projectName, + this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, extraOptions, target, config, false, fast); if(output) @@ -2558,3 +2570,44 @@ std::string cmGlobalGenerator::EscapeJSON(const std::string& s) { } return result; } + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::AddEvaluationFile(const std::string &inputFile, + cmsys::auto_ptr<cmCompiledGeneratorExpression> outputExpr, + cmMakefile *makefile, + cmsys::auto_ptr<cmCompiledGeneratorExpression> condition, + bool inputIsContent) +{ + this->EvaluationFiles.push_back( + new cmGeneratorExpressionEvaluationFile(inputFile, outputExpr, + makefile, condition, + inputIsContent)); +} + +//---------------------------------------------------------------------------- +void cmGlobalGenerator::ProcessEvaluationFiles() +{ + std::set<std::string> generatedFiles; + for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator + li = this->EvaluationFiles.begin(); + li != this->EvaluationFiles.end(); + ++li) + { + (*li)->Generate(); + if (cmSystemTools::GetFatalErrorOccured()) + { + return; + } + std::vector<std::string> files = (*li)->GetFiles(); + for(std::vector<std::string>::const_iterator fi = files.begin(); + fi != files.end(); ++fi) + { + if (!generatedFiles.insert(*fi).second) + { + cmSystemTools::Error("File to be generated by multiple different " + "commands: ", fi->c_str()); + return; + } + } + } +} diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 11616e0..2fcdc43 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -20,9 +20,11 @@ #include "cmSystemTools.h" // for cmSystemTools::OutputOption #include "cmExportSetMap.h" // For cmExportSetMap #include "cmGeneratorTarget.h" +#include "cmGeneratorExpression.h" class cmake; class cmGeneratorTarget; +class cmGeneratorExpressionEvaluationFile; class cmMakefile; class cmLocalGenerator; class cmExternalMakefileProjectGenerator; @@ -121,9 +123,10 @@ public: virtual std::string GenerateBuildCommand( const char* makeProgram, - const char *projectName, const char* additionalOptions, - const char *targetName, - const char* config, bool ignoreErrors, bool fast); + const char *projectName, const char *projectDir, + const char* additionalOptions, + const char *targetName, const char* config, + bool ignoreErrors, bool fast); ///! Set the CMake instance @@ -278,6 +281,14 @@ public: static std::string EscapeJSON(const std::string& s); + void AddEvaluationFile(const std::string &inputFile, + cmsys::auto_ptr<cmCompiledGeneratorExpression> outputName, + cmMakefile *makefile, + cmsys::auto_ptr<cmCompiledGeneratorExpression> condition, + bool inputIsContent); + + void ProcessEvaluationFiles(); + protected: typedef std::vector<cmLocalGenerator*> GeneratorVector; // for a project collect all its targets by following depend @@ -337,6 +348,7 @@ protected: // All targets in the entire project. std::map<cmStdString,cmTarget *> TotalTargets; std::map<cmStdString,cmTarget *> ImportedTargets; + std::vector<cmGeneratorExpressionEvaluationFile*> EvaluationFiles; virtual const char* GetPredefinedTargetsFolder(); virtual bool UseFolderProperty(); diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index fa277b1..fff972e 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -523,14 +523,16 @@ bool cmGlobalNinjaGenerator::UsingMinGW = false; std::string cmGlobalNinjaGenerator ::GenerateBuildCommand(const char* makeProgram, const char* projectName, + const char* projectDir, const char* additionalOptions, const char* targetName, const char* config, bool ignoreErrors, bool fast) { - // Project name and config are not used yet. + // Project name & dir and config are not used yet. (void)projectName; + (void)projectDir; (void)config; // Ninja does not have -i equivalent option yet. (void)ignoreErrors; diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index c3df7d9..6e93788 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -191,6 +191,7 @@ public: /// Overloaded methods. @see cmGlobalGenerator::GenerateBuildCommand() virtual std::string GenerateBuildCommand(const char* makeProgram, const char* projectName, + const char* projectDir, const char* additionalOptions, const char* targetName, const char* config, diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index e26cca9..88cd6e5 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -517,11 +517,13 @@ cmGlobalUnixMakefileGenerator3 std::string cmGlobalUnixMakefileGenerator3 ::GenerateBuildCommand(const char* makeProgram, const char *projectName, - const char* additionalOptions, const char *targetName, - const char* config, bool ignoreErrors, bool fast) + const char *projectDir, const char* additionalOptions, + const char *targetName, const char* config, + bool ignoreErrors, bool fast) { - // Project name and config are not used yet. + // Project name & dir and config are not used yet. (void)projectName; + (void)projectDir; (void)config; std::string makeCommand = diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index 385cdc4..5e9dce3 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -107,7 +107,8 @@ public: // change the build command for speed virtual std::string GenerateBuildCommand (const char* makeProgram, - const char *projectName, const char* additionalOptions, + const char *projectName, const char *projectDir, + const char* additionalOptions, const char *targetName, const char* config, bool ignoreErrors, bool fast); diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index b8c4939..742ab78 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -14,6 +14,8 @@ #include "cmLocalVisualStudio10Generator.h" #include "cmMakefile.h" #include "cmSourceFile.h" +#include "cmVisualStudioSlnData.h" +#include "cmVisualStudioSlnParser.h" #include "cmake.h" static const char vs10Win32generatorName[] = "Visual Studio 10"; @@ -215,7 +217,7 @@ std::string cmGlobalVisualStudio10Generator::GetUserMacrosRegKeyBase() std::string cmGlobalVisualStudio10Generator ::GenerateBuildCommand(const char* makeProgram, - const char *projectName, + const char *projectName, const char *projectDir, const char* additionalOptions, const char *targetName, const char* config, bool ignoreErrors, bool fast) { @@ -230,7 +232,8 @@ std::string cmGlobalVisualStudio10Generator lowerCaseCommand.find("VCExpress") != std::string::npos) { return cmGlobalVisualStudio7Generator::GenerateBuildCommand(makeProgram, - projectName, additionalOptions, targetName, config, ignoreErrors, fast); + projectName, projectDir, additionalOptions, targetName, config, + ignoreErrors, fast); } // Otherwise, assume MSBuild command line, and construct accordingly. @@ -258,9 +261,38 @@ std::string cmGlobalVisualStudio10Generator } else { + std::string targetProject(targetName); + targetProject += ".vcxproj"; + if (targetProject.find('/') == std::string::npos) + { + // it might be in a subdir + cmVisualStudioSlnParser parser; + cmSlnData slnData; + std::string slnFile; + if (projectDir && *projectDir) + { + slnFile = projectDir; + slnFile += '/'; + slnFile += projectName; + } + else + { + slnFile = projectName; + } + if (parser.ParseFile(slnFile + ".sln", slnData, + cmVisualStudioSlnParser::DataGroupProjects)) + { + if (cmSlnProjectEntry const* proj = + slnData.GetProjectByName(targetName)) + { + targetProject = proj->GetRelativePath(); + cmSystemTools::ConvertToUnixSlashes(targetProject); + } + } + } + makeCommand += " "; + makeCommand += targetProject; makeCommand += " "; - makeCommand += targetName; - makeCommand += ".vcxproj "; } makeCommand += "/p:Configuration="; if(config && strlen(config)) diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 5926e0f..dbe6044 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -32,7 +32,7 @@ public: virtual std::string GenerateBuildCommand(const char* makeProgram, - const char *projectName, + const char *projectName, const char *projectDir, const char* additionalOptions, const char *targetName, const char* config, bool ignoreErrors, bool); diff --git a/Source/cmGlobalVisualStudio6Generator.cxx b/Source/cmGlobalVisualStudio6Generator.cxx index 9f3af71..b3fabda 100644 --- a/Source/cmGlobalVisualStudio6Generator.cxx +++ b/Source/cmGlobalVisualStudio6Generator.cxx @@ -80,12 +80,15 @@ void cmGlobalVisualStudio6Generator::GenerateConfigurations(cmMakefile* mf) std::string cmGlobalVisualStudio6Generator ::GenerateBuildCommand(const char* makeProgram, const char *projectName, + const char *projectDir, const char* additionalOptions, const char *targetName, const char* config, bool ignoreErrors, bool) { + // Visual studio 6 doesn't need project dir + (void) projectDir; // Ingoring errors is not implemented in visual studio 6 (void) ignoreErrors; diff --git a/Source/cmGlobalVisualStudio6Generator.h b/Source/cmGlobalVisualStudio6Generator.h index 40149e9..6bd39ca 100644 --- a/Source/cmGlobalVisualStudio6Generator.h +++ b/Source/cmGlobalVisualStudio6Generator.h @@ -54,6 +54,7 @@ public: */ virtual std::string GenerateBuildCommand(const char* makeProgram, const char *projectName, + const char *projectDir, const char* additionalOptions, const char *targetName, const char* config, diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 63cbdb8..9a34ecf 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -31,6 +31,16 @@ void cmGlobalVisualStudio7Generator mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1"); mf->AddDefinition("CMAKE_GENERATOR_FC", "ifort"); this->AddPlatformDefinitions(mf); + if(!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) + { + mf->AddCacheDefinition( + "CMAKE_CONFIGURATION_TYPES", + "Debug;Release;MinSizeRel;RelWithDebInfo", + "Semicolon separated list of supported configuration types, " + "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, " + "anything else will be ignored.", + cmCacheManager::STRING); + } // Create list of configurations requested by user's cache, if any. this->cmGlobalGenerator::EnableLanguage(lang, mf, optional); @@ -56,10 +66,12 @@ void cmGlobalVisualStudio7Generator std::string cmGlobalVisualStudio7Generator ::GenerateBuildCommand(const char* makeProgram, - const char *projectName, + const char *projectName, const char *projectDir, const char* additionalOptions, const char *targetName, const char* config, bool ignoreErrors, bool) { + // Visual studio 7 doesn't need project dir + (void) projectDir; // Ingoring errors is not implemented in visual studio 6 (void) ignoreErrors; diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index 6e78620..3ebb408 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -55,6 +55,7 @@ public: */ virtual std::string GenerateBuildCommand(const char* makeProgram, const char *projectName, + const char *projectDir, const char* additionalOptions, const char *targetName, const char* config, diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 808664d..f4be0ce 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -449,7 +449,7 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(cmTarget& target) } } - // Collext explicit util dependencies (add_dependencies). + // Collect explicit util dependencies (add_dependencies). std::set<cmTarget*> utilDepends; for(TargetDependSet::const_iterator di = depends.begin(); di != depends.end(); ++di) diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index f2bb9d7..d782a06 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -260,6 +260,7 @@ void cmGlobalXCodeGenerator::EnableLanguage(std::vector<std::string>const& std::string cmGlobalXCodeGenerator ::GenerateBuildCommand(const char* makeProgram, const char *projectName, + const char *projectDir, const char* additionalOptions, const char *targetName, const char* config, @@ -268,6 +269,7 @@ std::string cmGlobalXCodeGenerator { // Config is not used yet (void) ignoreErrors; + (void) projectDir; // now build the test if(makeProgram == 0 || !strlen(makeProgram)) @@ -839,7 +841,7 @@ GetSourcecodeValueFromFileExtension(const std::string& _ext, // // Already specialized above or we leave sourcecode == "sourcecode" // // which is probably the most correct choice. Extensionless headers, // // for example... Or file types unknown to Xcode that do not map to a - // // valid lastKnownFileType value. + // // valid explicitFileType value. // } return sourcecode; @@ -882,7 +884,7 @@ cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( std::string sourcecode = GetSourcecodeValueFromFileExtension(ext, lang); - fileRef->AddAttribute("lastKnownFileType", + fileRef->AddAttribute("explicitFileType", this->CreateString(sourcecode.c_str())); // Store the file path relative to the top of the source tree. @@ -1003,7 +1005,7 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, *i, cmtarget); cmXCodeObject* fr = xsf->GetObject("fileRef"); cmXCodeObject* filetype = - fr->GetObject()->GetObject("lastKnownFileType"); + fr->GetObject()->GetObject("explicitFileType"); cmTarget::SourceFileFlags tsFlags = cmtarget.GetTargetSourceFileFlags(*i); @@ -1746,30 +1748,26 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, buildSettings->AddAttribute ("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList()); + std::string extraLinkOptionsVar; std::string extraLinkOptions; if(target.GetType() == cmTarget::EXECUTABLE) { - extraLinkOptions = - this->CurrentMakefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS"); - std::string var = "CMAKE_EXE_LINKER_FLAGS_"; - var += cmSystemTools::UpperCase(configName); - std::string val = - this->CurrentMakefile->GetSafeDefinition(var.c_str()); - if(val.size()) - { - extraLinkOptions += " "; - extraLinkOptions += val; - } + extraLinkOptionsVar = "CMAKE_EXE_LINKER_FLAGS"; } - if(target.GetType() == cmTarget::SHARED_LIBRARY) + else if(target.GetType() == cmTarget::SHARED_LIBRARY) { - extraLinkOptions = this->CurrentMakefile-> - GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS"); + extraLinkOptionsVar = "CMAKE_SHARED_LINKER_FLAGS"; } - if(target.GetType() == cmTarget::MODULE_LIBRARY) + else if(target.GetType() == cmTarget::MODULE_LIBRARY) { - extraLinkOptions = this->CurrentMakefile-> - GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS"); + extraLinkOptionsVar = "CMAKE_MODULE_LINKER_FLAGS"; + } + if(extraLinkOptionsVar.size()) + { + this->CurrentLocalGenerator + ->AddConfigVariableFlags(extraLinkOptions, + extraLinkOptionsVar.c_str(), + configName); } const char* linkFlagsProp = "LINK_FLAGS"; @@ -2331,8 +2329,39 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, { if(i->first.find("XCODE_ATTRIBUTE_") == 0) { - buildSettings->AddAttribute(i->first.substr(16).c_str(), - this->CreateString(i->second.GetValue())); + cmStdString attribute = i->first.substr(16); + // Handle [variant=<config>] condition explicitly here. + cmStdString::size_type beginVariant = + attribute.find("[variant="); + if (beginVariant != cmStdString::npos) + { + cmStdString::size_type endVariant = + attribute.find("]", beginVariant+9); + if (endVariant != cmStdString::npos) + { + // Compare the variant to the configuration. + cmStdString variant = + attribute.substr(beginVariant+9, endVariant-beginVariant-9); + if (variant == configName) + { + // The variant matches the configuration so use this + // attribute but drop the [variant=<config>] condition. + attribute.erase(beginVariant, endVariant-beginVariant+1); + } + else + { + // The variant does not match the configuration so + // do not use this attribute. + attribute.clear(); + } + } + } + + if (!attribute.empty()) + { + buildSettings->AddAttribute(attribute.c_str(), + this->CreateString(i->second.GetValue())); + } } } } diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 131a6e6..fb897b2 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -55,6 +55,7 @@ public: */ virtual std::string GenerateBuildCommand(const char* makeProgram, const char *projectName, + const char *projectDir, const char* additionalOptions, const char *targetName, const char* config, diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx index 0d5f67b..bb891d6 100644 --- a/Source/cmIncludeCommand.cxx +++ b/Source/cmIncludeCommand.cxx @@ -61,7 +61,7 @@ bool cmIncludeCommand noPolicyScope = true; } else if(i > 1) // compat.: in previous cmake versions the second - // parameter was ignore if it wasn't "OPTIONAL" + // parameter was ignored if it wasn't "OPTIONAL" { std::string errorText = "called with invalid argument: "; errorText += args[i]; diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx index ffb0e80..30c1743 100644 --- a/Source/cmIncludeDirectoryCommand.cxx +++ b/Source/cmIncludeDirectoryCommand.cxx @@ -116,13 +116,19 @@ void cmIncludeDirectoryCommand::GetIncludes(const std::string &arg, { std::string inc = arg.substr(lastPos,pos); this->NormalizeInclude(inc); - incs.push_back(inc); + if (!inc.empty()) + { + incs.push_back(inc); + } } lastPos = pos + 1; } std::string inc = arg.substr(lastPos); this->NormalizeInclude(inc); - incs.push_back(inc); + if (!inc.empty()) + { + incs.push_back(inc); + } } void cmIncludeDirectoryCommand::NormalizeInclude(std::string &inc) @@ -133,6 +139,11 @@ void cmIncludeDirectoryCommand::NormalizeInclude(std::string &inc) { inc.assign(inc, b, 1+e-b); // copy the remaining substring } + else + { + inc = ""; + return; + } if (!cmSystemTools::IsOff(inc.c_str())) { diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index ee5b9d8..d346f16 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -294,7 +294,7 @@ void cmLocalGenerator::GenerateTestFiles() << "# Build directory: " << this->Makefile->GetStartOutputDirectory() << std::endl << "# " << std::endl - << "# This file includes the relevent testing commands " + << "# This file includes the relevant testing commands " << "required for " << std::endl << "# testing this directory and lists subdirectories to " << "be tested as well." << std::endl; @@ -1084,8 +1084,6 @@ void cmLocalGenerator::ExpandRuleVariables(std::string& s, const RuleVariables& replaceValues) { - std::vector<std::string> enabledLanguages; - this->GlobalGenerator->GetEnabledLanguages(enabledLanguages); this->InsertRuleLauncher(s, replaceValues.CMTarget, replaceValues.RuleLauncher); std::string::size_type start = s.find('<'); @@ -2011,13 +2009,13 @@ void cmLocalGenerator::AddCMP0018Flags(std::string &flags, cmTarget* target, else { if (target->GetType() == cmTarget::OBJECT_LIBRARY) - { + { if (target->GetPropertyAsBool("POSITION_INDEPENDENT_CODE")) { this->AddPositionIndependentFlags(flags, lang, targetType); } return; - } + } if (target->GetLinkInterfaceDependentBoolProperty( "POSITION_INDEPENDENT_CODE", diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index d902f4e..294a539 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -302,7 +302,12 @@ void cmLocalNinjaGenerator::AppendCustomCommandLines(const cmCustomCommand *cc, wd = this->GetMakefile()->GetStartOutputDirectory(); cmOStringStream cdCmd; - cdCmd << "cd " << this->ConvertToOutputFormat(wd, SHELL); +#ifdef _WIN32 + std::string cdStr = "cd /D "; +#else + std::string cdStr = "cd "; +#endif + cdCmd << cdStr << this->ConvertToOutputFormat(wd, SHELL); cmdLines.push_back(cdCmd.str()); } for (unsigned i = 0; i != ccg.GetNumberOfCommands(); ++i) { diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 0f680f6..78a70f8 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1304,7 +1304,7 @@ cmLocalUnixMakefileGenerator3 std::string unmodified = s; unmodified += s2; // if there is no restriction on the length of make variables - // and there are no "." charactors in the string, then return the + // and there are no "." characters in the string, then return the // unmodified combination. if((!this->MakefileVariableSize && unmodified.find('.') == s.npos) && (!this->MakefileVariableSize && unmodified.find('+') == s.npos) @@ -1345,7 +1345,7 @@ cmLocalUnixMakefileGenerator3 return ret; } - // if the string is greater the 32 chars it is an invalid vairable name + // if the string is greater than 32 chars it is an invalid variable name // for borland make if(static_cast<int>(ret.size()) > this->MakefileVariableSize) { @@ -1353,8 +1353,8 @@ cmLocalUnixMakefileGenerator3 int size = keep + 3; std::string str1 = s; std::string str2 = s2; - // we must shorten the combined string by 4 charactors - // keep no more than 24 charactors from the second string + // we must shorten the combined string by 4 characters + // keep no more than 24 characters from the second string if(static_cast<int>(str2.size()) > keep) { str2 = str2.substr(0, keep); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 7d0bc67..58d28da 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -202,7 +202,7 @@ void cmLocalVisualStudio7Generator::WriteStampFiles() stampName += "/"; stampName += "generate.stamp"; std::ofstream stamp(stampName.c_str()); - stamp << "# CMake generation timestamp file this directory.\n"; + stamp << "# CMake generation timestamp file for this directory.\n"; // Create a helper file so CMake can determine when it is run // through the rule created by CreateVCProjBuildRule whether it @@ -443,12 +443,12 @@ cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[] = {"InlineFunctionExpansion", "Ob0", "no inlines", "0", 0}, {"InlineFunctionExpansion", "Ob1", "when inline keyword", "1", 0}, {"InlineFunctionExpansion", "Ob2", "any time you can inline", "2", 0}, - {"RuntimeLibrary", "MTd", "Multithreded debug", "1", 0}, - {"RuntimeLibrary", "MT", "Multithreded", "0", 0}, - {"RuntimeLibrary", "MDd", "Multithreded dll debug", "3", 0}, - {"RuntimeLibrary", "MD", "Multithreded dll", "2", 0}, - {"RuntimeLibrary", "MLd", "Sinble Thread debug", "5", 0}, - {"RuntimeLibrary", "ML", "Sinble Thread", "4", 0}, + {"RuntimeLibrary", "MTd", "Multithreaded debug", "1", 0}, + {"RuntimeLibrary", "MT", "Multithreaded", "0", 0}, + {"RuntimeLibrary", "MDd", "Multithreaded dll debug", "3", 0}, + {"RuntimeLibrary", "MD", "Multithreaded dll", "2", 0}, + {"RuntimeLibrary", "MLd", "Single Thread debug", "5", 0}, + {"RuntimeLibrary", "ML", "Single Thread", "4", 0}, {"StructMemberAlignment", "Zp16", "struct align 16 byte ", "5", 0}, {"StructMemberAlignment", "Zp1", "struct align 1 byte ", "1", 0}, {"StructMemberAlignment", "Zp2", "struct align 2 byte ", "2", 0}, @@ -476,6 +476,9 @@ cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[] = {"ForcedIncludeFiles", "FI", "Forced include files", "", cmVS7FlagTable::UserValueRequired | cmVS7FlagTable::SemicolonAppendable}, + {"AssemblerListingLocation", "Fa", "ASM List Location", "", + cmVS7FlagTable::UserValue}, + // boolean flags {"BufferSecurityCheck", "GS", "Buffer security check", "TRUE", 0}, {"BufferSecurityCheck", "GS-", "Turn off Buffer security check", "FALSE", 0}, @@ -740,6 +743,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, table, this->ExtraFlagTable); targetOptions.FixExceptionHandlingDefault(); + std::string asmLocation = std::string(configName) + "/"; + targetOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str()); targetOptions.Parse(flags.c_str()); targetOptions.Parse(defineFlags.c_str()); targetOptions.ParseFinish(); @@ -836,18 +841,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, fout << "\"\n"; targetOptions.OutputFlagMap(fout, "\t\t\t\t"); targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", "CXX"); - fout << "\t\t\t\tAssemblerListingLocation=\"" << configName << "\"\n"; fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n"; - if(targetBuilds) - { - // We need to specify a program database file name even for - // non-debug configurations because VS still creates .idb files. - fout << "\t\t\t\tProgramDataBaseFileName=\"" - << this->ConvertToXMLOutputPathSingle( - target.GetPDBDirectory(configName).c_str()) - << "/" - << target.GetPDBName(configName) << "\"\n"; - } fout << "/>\n"; // end of <Tool Name=VCCLCompilerTool tool = "VCCustomBuildTool"; if(this->FortranProject) diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 47a6d2e..606ec93 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -1436,7 +1436,7 @@ void cmMakefile::AddLinkDirectoryForTarget(const char *target, else { cmSystemTools::Error - ("Attempt to add link directories to non-existant target: ", + ("Attempt to add link directories to non-existent target: ", target, " for directory ", d); } } @@ -2086,7 +2086,7 @@ void cmMakefile::AddSourceGroup(const std::vector<std::string>& name, } else if(i==-1) { - // group does not exists nor belong to any existing group + // group does not exist nor belong to any existing group // add its first component this->SourceGroups.push_back(cmSourceGroup(name[0].c_str(), regex)); sg = this->GetSourceGroup(currentName); @@ -4043,7 +4043,7 @@ void cmMakefile::DefineProperties(cmake *cm) "\n" "This property only works for Visual Studio 7 and above; it is ignored " "on other generators. The property only applies when set on a directory " - "whose CMakeLists.txt conatins a project() command."); + "whose CMakeLists.txt contains a project() command."); cm->DefineProperty ("VS_GLOBAL_SECTION_POST_<section>", cmProperty::DIRECTORY, "Specify a postSolution global section in Visual Studio.", @@ -4059,7 +4059,7 @@ void cmMakefile::DefineProperties(cmake *cm) "\n" "This property only works for Visual Studio 7 and above; it is ignored " "on other generators. The property only applies when set on a directory " - "whose CMakeLists.txt conatins a project() command." + "whose CMakeLists.txt contains a project() command." "\n" "Note that CMake generates postSolution sections ExtensibilityGlobals " "and ExtensibilityAddIns by default. If you set the corresponding " diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index e5a6eab..1bdaf90 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -512,7 +512,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() const std::string objPath = GetTarget()->GetSupportDirectory(); vars["OBJECT_DIR"] = ConvertToNinjaPath(objPath.c_str()); EnsureDirectoryExists(objPath); - // ar.exe can't handle backslashes in rsp files (implictly used by gcc) + // ar.exe can't handle backslashes in rsp files (implicitly used by gcc) std::string& linkLibraries = vars["LINK_LIBRARIES"]; std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/'); } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 38305e2..532ee67 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -569,11 +569,9 @@ cmNinjaTargetGenerator EnsureParentDirectoryExists(objectFileName); std::string objectDir = cmSystemTools::GetFilenamePath(objectFileName); - objectDir = this->GetLocalGenerator()->Convert(objectDir.c_str(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL); - vars["OBJECT_DIR"] = objectDir; - + vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat( + ConvertToNinjaPath(objectDir.c_str()).c_str(), + cmLocalGenerator::SHELL); this->SetMsvcTargetPdbVariable(vars); diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 831e92e..32829a6 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -440,7 +440,8 @@ cmPolicies::cmPolicies() this->DefinePolicy( CMP0016, "CMP0016", - "target_link_libraries() reports error if only argument is not a target.", + "target_link_libraries() reports error if its only argument " + "is not a target.", "In CMake 2.8.2 and lower the target_link_libraries() command silently " "ignored if it was called with only one argument, and this argument " "wasn't a valid target. " @@ -452,7 +453,7 @@ cmPolicies::cmPolicies() "Prefer files from the CMake module directory when including from there.", "Starting with CMake 2.8.4, if a cmake-module shipped with CMake (i.e. " "located in the CMake module directory) calls include() or " - "find_package(), the files located in the the CMake module directory are " + "find_package(), the files located in the CMake module directory are " "preferred over the files in CMAKE_MODULE_PATH. " "This makes sure that the modules belonging to " "CMake always get those files included which they expect, and against " @@ -529,6 +530,20 @@ cmPolicies::cmPolicies() "The NEW behavior for this policy is to link executables to " "qtmain.lib automatically when they link to QtCore IMPORTED target.", 2,8,11,0, cmPolicies::WARN); + + this->DefinePolicy( + CMP0021, "CMP0021", + "Fatal error on relative paths in INCLUDE_DIRECTORIES target property.", + "CMake 2.8.10.2 and lower allowed the INCLUDE_DIRECTORIES target " + "property to contain relative paths. The base path for such relative " + "entries is not well defined. CMake 2.8.12 issues a FATAL_ERROR if the " + "INCLUDE_DIRECTORIES property contains a relative path." + "\n" + "The OLD behavior for this policy is not to warn about relative paths in " + "the INCLUDE_DIRECTORIES target property. " + "The NEW behavior for this policy is to issue a FATAL_ERROR if " + "INCLUDE_DIRECTORIES contains a relative path.", + 2,8,11,20130516, cmPolicies::WARN); } cmPolicies::~cmPolicies() @@ -770,7 +785,7 @@ std::string cmPolicies::GetRequiredPolicyError(cmPolicies::PolicyID id) { cmSystemTools::Error( "Request for error text for undefined policy!"); - return "Request for warning text for undefined policy!"; + return "Request for error text for undefined policy!"; } cmOStringStream error; diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index c11af07..a033e87 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -70,6 +70,8 @@ public: /// instead. CMP0019, ///< No variable re-expansion in include and link info CMP0020, ///< Automatically link Qt executables to qtmain target + CMP0021, ///< Fatal error on relative paths in INCLUDE_DIRECTORIES + /// target property /** \brief Always the last entry. * diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index a1fa31f..a468fa7 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -280,13 +280,9 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) _moc_incs += *incDirIt; } - const char* tmp = target->GetProperty("COMPILE_DEFINITIONS"); - std::string _moc_compile_defs; - if (tmp) - { - _moc_compile_defs = target->GetCompileDefinitions(0); - } - tmp = makefile->GetProperty("COMPILE_DEFINITIONS"); + std::string _moc_compile_defs = target->GetCompileDefinitions(0); + + const char* tmp = makefile->GetProperty("COMPILE_DEFINITIONS"); if (tmp) { _moc_compile_defs += ";"; @@ -696,7 +692,7 @@ void cmQtAutomoc::ParseCppFile(const std::string& absFilename, std::string ownMocHeaderFile; std::string::size_type matchOffset = 0; - // first a simply string check for "moc" is *much* faster than the regexp, + // first a simple string check for "moc" is *much* faster than the regexp, // and if the string search already fails, we don't have to try the // expensive regexp if ((strstr(contentsString.c_str(), "moc") != NULL) @@ -870,7 +866,7 @@ void cmQtAutomoc::StrictParseCppFile(const std::string& absFilename, bool dotMocIncluded = false; std::string::size_type matchOffset = 0; - // first a simply string check for "moc" is *much* faster than the regexp, + // first a simple string check for "moc" is *much* faster than the regexp, // and if the string search already fails, we don't have to try the // expensive regexp if ((strstr(contentsString.c_str(), "moc") != NULL) diff --git a/Source/cmSetTargetPropertiesCommand.h b/Source/cmSetTargetPropertiesCommand.h index 9dd7848..cf9c193 100644 --- a/Source/cmSetTargetPropertiesCommand.h +++ b/Source/cmSetTargetPropertiesCommand.h @@ -104,7 +104,7 @@ public: "are common values for this property." "\n" "For shared libraries VERSION and SOVERSION can be used to specify " - "the build version and api version respectively. When building or " + "the build version and API version respectively. When building or " "installing appropriate symlinks are created if the platform " "supports symlinks and the linker supports so-names. " "If only one of both is specified the missing is assumed to have " diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index 1d4b0c8..8bb7d96 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -483,7 +483,7 @@ void cmSourceFile::DefineProperties(cmake *cm) "the source file is. If it is not set the language is determined " "based on the file extension. Typical values are CXX C etc. Setting " "this property for a file means this file will be compiled. " - "Do not set this for header or files that should not be compiled."); + "Do not set this for headers or files that should not be compiled."); cm->DefineProperty ("LOCATION", cmProperty::SOURCE_FILE, @@ -551,7 +551,7 @@ void cmSourceFile::DefineProperties(cmake *cm) "Some packages can wrap source files into alternate languages " "to provide additional functionality. For example, C++ code " "can be wrapped into Java or Python etc using SWIG etc. " - "If WRAP_EXCLUDE is set to true (1 etc) that indicates then " + "If WRAP_EXCLUDE is set to true (1 etc) that indicates that " "this source file should not be wrapped."); } diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index e49edd8..1fbde01 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -93,6 +93,10 @@ bool cmStringCommand { return this->HandleTimestampCommand(args); } + else if(subCommand == "MAKE_C_IDENTIFIER") + { + return this->HandleMakeCIdentifierCommand(args); + } std::string e = "does not recognize sub-command "+subCommand; this->SetError(e.c_str()); @@ -755,6 +759,24 @@ bool cmStringCommand } //---------------------------------------------------------------------------- +bool cmStringCommand +::HandleMakeCIdentifierCommand(std::vector<std::string> const& args) +{ + if(args.size() != 3) + { + this->SetError("sub-command MAKE_C_IDENTIFIER requires two arguments."); + return false; + } + + const std::string& input = args[1]; + const std::string& variableName = args[2]; + + this->Makefile->AddDefinition(variableName.c_str(), + cmSystemTools::MakeCidentifier(input.c_str()).c_str()); + return true; +} + +//---------------------------------------------------------------------------- bool cmStringCommand::HandleStripCommand( std::vector<std::string> const& args) { diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h index 802e0b8..f584cfd 100644 --- a/Source/cmStringCommand.h +++ b/Source/cmStringCommand.h @@ -94,6 +94,7 @@ public: " [RANDOM_SEED <seed>] <output variable>)\n" " string(FIND <string> <substring> <output variable> [REVERSE])\n" " string(TIMESTAMP <output variable> [<format string>] [UTC])\n" + " string(MAKE_C_IDENTIFIER <input string> <output variable>)\n" "REGEX MATCH will match the regular expression once and store the " "match in the output variable.\n" "REGEX MATCHALL will match the regular expression as many times as " @@ -176,7 +177,9 @@ public: "and copied to the output as-is.\n" "If no explicit <format string> is given it will default to:\n" " %Y-%m-%dT%H:%M:%S for local time.\n" - " %Y-%m-%dT%H:%M:%SZ for UTC."; + " %Y-%m-%dT%H:%M:%SZ for UTC.\n" + "MAKE_C_IDENTIFIER will write a string which can be used as an " + "identifier in C."; } cmTypeMacro(cmStringCommand, cmCommand); @@ -200,6 +203,7 @@ protected: bool HandleRandomCommand(std::vector<std::string> const& args); bool HandleFindCommand(std::vector<std::string> const& args); bool HandleTimestampCommand(std::vector<std::string> const& args); + bool HandleMakeCIdentifierCommand(std::vector<std::string> const& args); class RegexReplacement { diff --git a/Source/cmSubdirCommand.cxx b/Source/cmSubdirCommand.cxx index 0cfe772..e497b46 100644 --- a/Source/cmSubdirCommand.cxx +++ b/Source/cmSubdirCommand.cxx @@ -64,7 +64,7 @@ bool cmSubdirCommand else { std::string error = "Incorrect SUBDIRS command. Directory: "; - error += *i + " does not exists."; + error += *i + " does not exist."; this->SetError(error.c_str()); res = false; } diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index d11e24d..f5be26b 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -56,7 +56,7 @@ public: typedef void (*ErrorCallback)(const char*, const char*, bool&, void*); /** - * Set the function used by GUI's to display error messages + * Set the function used by GUIs to display error messages * Function gets passed: message as a const char*, * title as a const char*, and a reference to bool that when * set to false, will disable furthur messages (cancel). diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index ea718ae..4f7fa87 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -142,7 +142,7 @@ public: std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries; std::vector<cmValueWithOrigin> LinkInterfaceIncludeDirectoriesEntries; - std::vector<IncludeDirectoriesEntry*> + std::map<std::string, std::vector<IncludeDirectoriesEntry*> > CachedLinkInterfaceIncludeDirectoriesEntries; std::map<std::string, std::string> CachedLinkInterfaceCompileDefinitions; @@ -165,9 +165,22 @@ void deleteAndClear( } //---------------------------------------------------------------------------- +void deleteAndClear( + std::map<std::string, + std::vector<cmTargetInternals::IncludeDirectoriesEntry*> > &entries) +{ + for (std::map<std::string, + std::vector<cmTargetInternals::IncludeDirectoriesEntry*> >::iterator + it = entries.begin(), end = entries.end(); it != end; ++it) + { + deleteAndClear(it->second); + } +} + +//---------------------------------------------------------------------------- cmTargetInternals::~cmTargetInternals() { - deleteAndClear(CachedLinkInterfaceIncludeDirectoriesEntries); + deleteAndClear(this->CachedLinkInterfaceIncludeDirectoriesEntries); } //---------------------------------------------------------------------------- @@ -178,6 +191,7 @@ cmTarget::cmTarget() this->PolicyStatusCMP0004 = cmPolicies::WARN; this->PolicyStatusCMP0008 = cmPolicies::WARN; this->PolicyStatusCMP0020 = cmPolicies::WARN; + this->PolicyStatusCMP0021 = cmPolicies::WARN; this->LinkLibrariesAnalyzed = false; this->HaveInstallRule = false; this->DLLPlatform = false; @@ -264,6 +278,7 @@ void cmTarget::DefineProperties(cmake *cm) "Contents of COMPILE_DEFINITIONS may use \"generator expressions\" with " "the syntax \"$<...>\". " CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS CM_DOCUMENT_COMPILE_DEFINITIONS_DISCLAIMER); cm->DefineProperty @@ -279,7 +294,7 @@ void cmTarget::DefineProperties(cmake *cm) "If not set here then it is set to target_EXPORTS by default " "(with some substitutions if the target is not a valid C " "identifier). This is useful for headers to know whether they are " - "being included from inside their library our outside to properly " + "being included from inside their library or outside to properly " "setup dllexport/dllimport decorations. "); cm->DefineProperty @@ -592,7 +607,8 @@ void cmTarget::DefineProperties(cmake *cm) "See also the include_directories command.\n" "Contents of INCLUDE_DIRECTORIES may use \"generator expressions\" with " "the syntax \"$<...>\". " - CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS); cm->DefineProperty ("INSTALL_NAME_DIR", cmProperty::TARGET, @@ -789,7 +805,8 @@ void cmTarget::DefineProperties(cmake *cm) "as $<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES> to use the " "include directories specified in the interface of 'foo'." "\n" - CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS); cm->DefineProperty ("INTERFACE_COMPILE_DEFINITIONS", cmProperty::TARGET, @@ -800,7 +817,8 @@ void cmTarget::DefineProperties(cmake *cm) "as $<TARGET_PROPERTY:foo,INTERFACE_COMPILE_DEFINITIONS> to use the " "compile definitions specified in the interface of 'foo'." "\n" - CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS); cm->DefineProperty ("LINK_INTERFACE_MULTIPLICITY", cmProperty::TARGET, @@ -854,6 +872,13 @@ void cmTarget::DefineProperties(cmake *cm) "OSX_ARCHITECTURES."); cm->DefineProperty + ("EXPORT_NAME", cmProperty::TARGET, + "Exported name for target files.", + "This sets the name for the IMPORTED target generated when it this " + "target is is exported. " + "If not set, the logical target name is used by default."); + + cm->DefineProperty ("OUTPUT_NAME", cmProperty::TARGET, "Output name for target files.", "This sets the base name for output files created for an executable or " @@ -873,9 +898,9 @@ void cmTarget::DefineProperties(cmake *cm) cm->DefineProperty ("PDB_NAME", cmProperty::TARGET, - "Output name for MS debug symbols .pdb file.", + "Output name for MS debug symbols .pdb file from linker.", "Set the base name for debug symbols file created for an " - "executable or library target. " + "executable or shared library target. " "If not set, the logical target name is used by default. " "\n" "This property is not implemented by the Visual Studio 6 generator."); @@ -1041,7 +1066,7 @@ void cmTarget::DefineProperties(cmake *cm) ("SOVERSION", cmProperty::TARGET, "What version number is this target.", "For shared libraries VERSION and SOVERSION can be used to specify " - "the build version and api version respectively. When building or " + "the build version and API version respectively. When building or " "installing appropriate symlinks are created if the platform " "supports symlinks and the linker supports so-names. " "If only one of both is specified the missing is assumed to have " @@ -1079,7 +1104,7 @@ void cmTarget::DefineProperties(cmake *cm) ("VERSION", cmProperty::TARGET, "What version number is this target.", "For shared libraries VERSION and SOVERSION can be used to specify " - "the build version and api version respectively. When building or " + "the build version and API version respectively. When building or " "installing appropriate symlinks are created if the platform " "supports symlinks and the linker supports so-names. " "If only one of both is specified the missing is assumed to have " @@ -1143,7 +1168,7 @@ void cmTarget::DefineProperties(cmake *cm) cm->DefineProperty ("MACOSX_FRAMEWORK_INFO_PLIST", cmProperty::TARGET, "Specify a custom Info.plist template for a Mac OS X Framework.", - "An library target with FRAMEWORK enabled will be built as a " + "A library target with FRAMEWORK enabled will be built as a " "framework on Mac OS X. " "By default its Info.plist file is created by configuring a template " "called MacOSXFrameworkInfo.plist.in located in the CMAKE_MODULE_PATH. " @@ -1243,7 +1268,7 @@ void cmTarget::DefineProperties(cmake *cm) cm->DefineProperty ("GENERATOR_FILE_NAME", cmProperty::TARGET, "Generator's file for this target.", - "An internal property used by some generators to record the name of " + "An internal property used by some generators to record the name of the " "project or dsp file associated with this target. Note that at configure " "time, this property is only set for targets created by " "include_external_msproject()."); @@ -1393,9 +1418,9 @@ void cmTarget::DefineProperties(cmake *cm) cm->DefineProperty ("PDB_OUTPUT_DIRECTORY", cmProperty::TARGET, - "Output directory for MS debug symbols .pdb files.", + "Output directory for MS debug symbols .pdb file from linker.", "This property specifies the directory into which the MS debug symbols " - "will be placed. " + "will be placed by the linker. " "This property is initialized by the value of the variable " "CMAKE_PDB_OUTPUT_DIRECTORY if it is set when a target is created." "\n" @@ -1566,6 +1591,8 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->Makefile->GetPolicyStatus(cmPolicies::CMP0008); this->PolicyStatusCMP0020 = this->Makefile->GetPolicyStatus(cmPolicies::CMP0020); + this->PolicyStatusCMP0021 = + this->Makefile->GetPolicyStatus(cmPolicies::CMP0021); } //---------------------------------------------------------------------------- @@ -2496,8 +2523,6 @@ cmTarget::AnalyzeLibDependencies( const cmMakefile& mf ) } } - typedef std::vector< std::string > LinkLine; - // The dependency map. DependencyMap dep_map; @@ -2724,6 +2749,27 @@ void cmTarget::SetProperty(const char* prop, const char* value) new cmTargetInternals::IncludeDirectoriesEntry(cge)); return; } + if(strcmp(prop,"EXPORT_NAME") == 0 && this->IsImported()) + { + cmOStringStream e; + e << "EXPORT_NAME property can't be set on imported targets (\"" + << this->Name << "\")\n"; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); + return; + } + if (strcmp(prop, "LINK_LIBRARIES") == 0) + { + this->Internal->LinkInterfaceIncludeDirectoriesEntries.clear(); + if (cmGeneratorExpression::IsValidTargetName(value) + || cmGeneratorExpression::Find(value) != std::string::npos) + { + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmValueWithOrigin entry(value, lfbt); + this->Internal->LinkInterfaceIncludeDirectoriesEntries.push_back(entry); + } + // Fall through + } this->Properties.SetProperty(prop, value, cmProperty::TARGET); this->MaybeInvalidatePropertyCache(prop); } @@ -2745,11 +2791,51 @@ void cmTarget::AppendProperty(const char* prop, const char* value, new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(value))); return; } + if(strcmp(prop,"EXPORT_NAME") == 0 && this->IsImported()) + { + cmOStringStream e; + e << "EXPORT_NAME property can't be set on imported targets (\"" + << this->Name << "\")\n"; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); + return; + } + if (strcmp(prop, "LINK_LIBRARIES") == 0) + { + if (cmGeneratorExpression::IsValidTargetName(value) + || cmGeneratorExpression::Find(value) != std::string::npos) + { + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmValueWithOrigin entry(value, lfbt); + this->Internal->LinkInterfaceIncludeDirectoriesEntries.push_back(entry); + } + // Fall through + } this->Properties.AppendProperty(prop, value, cmProperty::TARGET, asString); this->MaybeInvalidatePropertyCache(prop); } //---------------------------------------------------------------------------- +const char* cmTarget::GetExportName() +{ + const char *exportName = this->GetProperty("EXPORT_NAME"); + + if (exportName && *exportName) + { + if (!cmGeneratorExpression::IsValidTargetName(exportName)) + { + cmOStringStream e; + e << "EXPORT_NAME property \"" << exportName << "\" for \"" + << this->GetName() << "\": is not valid."; + cmSystemTools::Error(e.str().c_str()); + return ""; + } + return exportName; + } + return this->GetName(); +} + +//---------------------------------------------------------------------------- void cmTarget::AppendBuildInterfaceIncludes() { if(this->GetType() != cmTarget::SHARED_LIBRARY && @@ -2781,12 +2867,6 @@ void cmTarget::AppendBuildInterfaceIncludes() } //---------------------------------------------------------------------------- -void cmTarget::AppendTllInclude(const cmValueWithOrigin &entry) -{ - this->Internal->LinkInterfaceIncludeDirectoriesEntries.push_back(entry); -} - -//---------------------------------------------------------------------------- void cmTarget::InsertInclude(const cmValueWithOrigin &entry, bool before) { @@ -2862,14 +2942,41 @@ static void processIncludeDirectories(cmTarget *tgt, if (!cmSystemTools::FileIsFullPath(li->c_str())) { + cmOStringStream e; + bool noMessage = false; + cmake::MessageType messageType = cmake::FATAL_ERROR; if (!(*it)->TargetName.empty()) { - cmOStringStream e; e << "Target \"" << (*it)->TargetName << "\" contains relative " "path in its INTERFACE_INCLUDE_DIRECTORIES:\n" " \"" << *li << "\" "; - tgt->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, - e.str().c_str()); + } + else + { + switch(tgt->GetPolicyStatusCMP0021()) + { + case cmPolicies::WARN: + { + cmOStringStream w; + e << (mf->GetPolicies() + ->GetPolicyWarning(cmPolicies::CMP0021)) << "\n"; + messageType = cmake::AUTHOR_WARNING; + } + break; + case cmPolicies::OLD: + noMessage = true; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // Issue the fatal message. + break; + } + e << "Found relative path while evaluating include directories of " + "\"" << tgt->GetName() << "\":\n \"" << *li << "\"\n"; + } + if (!noMessage) + { + tgt->GetMakefile()->IssueMessage(messageType, e.str().c_str()); return; } } @@ -2957,25 +3064,33 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config) ge.Parse(it->Value); std::string result = cge->Evaluate(this->Makefile, config, false, this, 0, 0); - if (!cmGeneratorExpression::IsValidTargetName(result.c_str()) - || !this->Makefile->FindTargetToUse(result.c_str())) + if (!this->Makefile->FindTargetToUse(result.c_str())) { continue; } } + std::string includeGenex = "$<TARGET_PROPERTY:" + + it->Value + ",INTERFACE_INCLUDE_DIRECTORIES>"; + if (cmGeneratorExpression::Find(it->Value) != std::string::npos) + { + // Because it->Value is a generator expression, ensure that it + // evaluates to the non-empty string before being used in the + // TARGET_PROPERTY expression. + includeGenex = "$<$<BOOL:" + it->Value + ">:" + includeGenex + ">"; + } cmGeneratorExpression ge(it->Backtrace); cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse( - "$<TARGET_PROPERTY:" + - it->Value + ",INTERFACE_INCLUDE_DIRECTORIES>"); + includeGenex); - this->Internal->CachedLinkInterfaceIncludeDirectoriesEntries.push_back( + this->Internal + ->CachedLinkInterfaceIncludeDirectoriesEntries[configString].push_back( new cmTargetInternals::IncludeDirectoriesEntry(cge, it->Value)); } } processIncludeDirectories(this, - this->Internal->CachedLinkInterfaceIncludeDirectoriesEntries, + this->Internal->CachedLinkInterfaceIncludeDirectoriesEntries[configString], includes, uniqueIncludes, &dagChecker, @@ -2985,7 +3100,7 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config) if (!this->Makefile->IsGeneratingBuildSystem()) { deleteAndClear( - this->Internal->CachedLinkInterfaceIncludeDirectoriesEntries); + this->Internal->CachedLinkInterfaceIncludeDirectoriesEntries); } else { @@ -5371,7 +5486,6 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, ImportInfo& info, cmTarget *headTarget) { - (void)headTarget; // This method finds information about an imported target from its // properties. The "IMPORTED_" namespace is reserved for properties // defined by the project exporting the target. diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 9d25919..0bcc2a8 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -85,6 +85,7 @@ public: ///! Set/Get the name of the target const char* GetName() const {return this->Name.c_str();} + const char* GetExportName(); ///! Set the cmMakefile that owns this target void SetMakefile(cmMakefile *mf); @@ -106,6 +107,10 @@ public: cmPolicies::PolicyStatus GetPolicyStatusCMP0020() const { return this->PolicyStatusCMP0020; } + /** Get the status of policy CMP0021 when the target was created. */ + cmPolicies::PolicyStatus GetPolicyStatusCMP0021() const + { return this->PolicyStatusCMP0021; } + /** * Get the list of the custom commands for this target */ @@ -506,7 +511,6 @@ public: std::vector<std::string> GetIncludeDirectories(const char *config); void InsertInclude(const cmValueWithOrigin &entry, bool before = false); - void AppendTllInclude(const cmValueWithOrigin &entry); void AppendBuildInterfaceIncludes(); @@ -681,6 +685,7 @@ private: cmPolicies::PolicyStatus PolicyStatusCMP0004; cmPolicies::PolicyStatus PolicyStatusCMP0008; cmPolicies::PolicyStatus PolicyStatusCMP0020; + cmPolicies::PolicyStatus PolicyStatusCMP0021; // Internal representation details. friend class cmTargetInternals; diff --git a/Source/cmTargetCompileDefinitionsCommand.h b/Source/cmTargetCompileDefinitionsCommand.h index ec9b071..22d8fa8 100644 --- a/Source/cmTargetCompileDefinitionsCommand.h +++ b/Source/cmTargetCompileDefinitionsCommand.h @@ -70,6 +70,7 @@ public: "Arguments to target_compile_definitions may use \"generator " "expressions\" with the syntax \"$<...>\". " CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS ; } diff --git a/Source/cmTargetIncludeDirectoriesCommand.h b/Source/cmTargetIncludeDirectoriesCommand.h index e4bc9cf..4a1a4df 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.h +++ b/Source/cmTargetIncludeDirectoriesCommand.h @@ -75,6 +75,7 @@ public: "Arguments to target_include_directories may use \"generator " "expressions\" with the syntax \"$<...>\". " CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS ; } diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 3f652c9..b7b7691 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -259,14 +259,6 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib, // Handle normal case first. if(this->CurrentProcessingState != ProcessingLinkInterface) { - { - cmListFileBacktrace lfbt; - this->Makefile->GetBacktrace(lfbt); - cmValueWithOrigin entry(this->Target->GetDebugGeneratorExpressions(lib, - llt), - lfbt); - this->Target->AppendTllInclude(entry); - } this->Makefile ->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt); if (this->CurrentProcessingState != ProcessingPublicInterface) diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h index aaabdfa..c683016 100644 --- a/Source/cmTargetLinkLibrariesCommand.h +++ b/Source/cmTargetLinkLibrariesCommand.h @@ -97,14 +97,17 @@ public: "Calls to other signatures of this command may set the property " "making any libraries linked exclusively by this signature private." "\n" - "Target usage requirements are also consumed by this command. If the " - "<target> is linked to another target which has " - "a populated INTERFACE_INCLUDE_DIRECTORIES, the content of it is " - "appended to the INCLUDE_DIRECTORIES of <target>. Similarly, the " - "INTERFACE_COMPILE_DEFINITONS of a dependee are added to the " - "COMPILE_DEFINITONS of <target>, and the " - "INTERFACE_POSITION_INDEPENDENT_CODE property is used to determine the " - "POSITION_INDEPENDENT_CODE property of <target>." + "CMake will also propagate \"usage requirements\" from linked library " + "targets. " + "Usage requirements affect compilation of sources in the <target>. " + "They are specified by properties defined on linked targets. " + "During generation of the build system, CMake integrates " + "usage requirement property values with the corresponding " + "build properties for <target>:\n" + " INTERFACE_COMPILE_DEFINITONS: Appends to COMPILE_DEFINITONS\n" + " INTERFACE_INCLUDE_DIRECTORIES: Appends to INCLUDE_DIRECTORIES\n" + " INTERFACE_POSITION_INDEPENDENT_CODE: Sets POSITION_INDEPENDENT_CODE\n" + " or checked for consistency with existing value\n" "\n" " target_link_libraries(<target> LINK_INTERFACE_LIBRARIES\n" " [[debug|optimized|general] <lib>] ...)\n" diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx index 912ec76..0904431 100644 --- a/Source/cmTest.cxx +++ b/Source/cmTest.cxx @@ -135,7 +135,7 @@ void cmTest::DefineProperties(cmake *cm) "If the output matches this regular expression the test will fail.", "If set, if the output matches one of " "specified regular expressions, the test will fail." - "For example: PASS_REGULAR_EXPRESSION \"[^a-z]Error;ERROR;Failed\""); + "For example: FAIL_REGULAR_EXPRESSION \"[^a-z]Error;ERROR;Failed\""); cm->DefineProperty ("LABELS", cmProperty::TEST, diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 1cb9f23..88c4deb 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -291,6 +291,7 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteCustomCommands(); this->WriteAllSources(); this->WriteDotNetReferences(); + this->WriteWinRTReferences(); this->WriteProjectReferences(); this->WriteString( @@ -455,6 +456,12 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() this->WriteString("<WindowsAppContainer>true" "</WindowsAppContainer>\n", 2); } + + if(!this->GeneratorTarget->ResxSources.empty()) + { + this->WriteString("<CLRSupport>true</CLRSupport>\n", 2); + } + this->WriteString("</PropertyGroup>\n", 1); } } @@ -647,6 +654,23 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups); } + std::vector<cmSourceFile*> resxObjs = this->GeneratorTarget->ResxSources; + if(!resxObjs.empty()) + { + this->WriteString("<ItemGroup>\n", 1); + for(std::vector<cmSourceFile*>::iterator oi = resxObjs.begin(); + oi != resxObjs.end(); ++oi) + { + std::string obj = (*oi)->GetFullPath(); + this->WriteString("<EmbeddedResource Include=\"", 2); + this->ConvertToWindowsSlash(obj); + (*this->BuildFileStream ) << obj << "\">\n"; + this->WriteString("<Filter>Resource Files</Filter>\n", 3); + this->WriteString("</EmbeddedResource>\n", 2); + } + this->WriteString("</ItemGroup>\n", 1); + } + // Add object library contents as external objects. std::vector<std::string> objs; this->GeneratorTarget->UseObjectLibraries(objs); @@ -701,6 +725,23 @@ void cmVisualStudio10TargetGenerator::WriteGroups() << "</UniqueIdentifier>\n"; this->WriteString("</Filter>\n", 2); } + + if(!this->GeneratorTarget->ResxSources.empty()) + { + this->WriteString("<Filter Include=\"Resource Files\">\n", 2); + std::string guidName = "SG_Filter_Resource Files"; + this->GlobalGenerator->CreateGUID(guidName.c_str()); + this->WriteString("<UniqueIdentifier>", 3); + std::string guid = + this->GlobalGenerator->GetGUID(guidName.c_str()); + (*this->BuildFileStream) << "{" << guid << "}" + << "</UniqueIdentifier>\n"; + this->WriteString("<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;", 3); + (*this->BuildFileStream) << "gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;"; + (*this->BuildFileStream) << "mfcribbon-ms</Extensions>\n"; + this->WriteString("</Filter>\n", 2); + } + this->WriteString("</ItemGroup>\n", 1); this->WriteString("</Project>\n", 0); // restore stream pointer @@ -832,8 +873,20 @@ void cmVisualStudio10TargetGenerator::WriteSource( } this->ConvertToWindowsSlash(sourceFile); this->WriteString("<", 2); - (*this->BuildFileStream ) << tool << - " Include=\"" << sourceFile << "\"" << (end? end : " />\n"); + (*this->BuildFileStream ) << tool << " Include=\"" << sourceFile << "\""; + + if(sf->GetExtension() == "h" && + this->IsResxHeader(sf->GetFullPath())) + { + (*this->BuildFileStream ) << ">\n"; + this->WriteString("<FileType>CppForm</FileType>\n", 3); + this->WriteString("</ClInclude>\n", 2); + } + else + { + (*this->BuildFileStream ) << (end? end : " />\n"); + } + ToolSource toolSource = {sf, forceRelative}; this->Tools[tool].push_back(toolSource); } @@ -1218,6 +1271,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( std::string defineFlags = this->Target->GetMakefile()->GetDefineFlags(); clOptions.FixExceptionHandlingDefault(); clOptions.AddFlag("PrecompiledHeader", "NotUsing"); + std::string asmLocation = configName + "/"; + clOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str()); clOptions.Parse(flags.c_str()); clOptions.Parse(defineFlags.c_str()); clOptions.AddDefines(this->Target->GetCompileDefinitions( @@ -1260,18 +1315,7 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", "\n", "CXX"); - this->WriteString("<AssemblerListingLocation>", 3); - *this->BuildFileStream << configName - << "</AssemblerListingLocation>\n"; this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3); - if(this->Target->GetType() != cmTarget::OBJECT_LIBRARY) - { - this->WriteString("<ProgramDataBaseFileName>", 3); - *this->BuildFileStream << this->Target->GetPDBDirectory(configName.c_str()) - << "/" - << this->Target->GetPDBName(configName.c_str()) - << "</ProgramDataBaseFileName>\n"; - } this->WriteString("</ClCompile>\n", 2); } @@ -1579,6 +1623,21 @@ void cmVisualStudio10TargetGenerator:: WriteMidlOptions(std::string const& /*config*/, std::vector<std::string> const & includes) { + // This processes *any* of the .idl files specified in the project's file + // list (and passed as the item metadata %(Filename) expressing the rule + // input filename) into output files at the per-config *build* dir + // ($(IntDir)) each. + // + // IOW, this MIDL section is intended to provide a fully generic syntax + // content suitable for most cases (read: if you get errors, then it's quite + // probable that the error is on your side of the .idl setup). + // + // Also, note that the marked-as-generated _i.c file in the Visual Studio + // generator case needs to be referred to as $(IntDir)\foo_i.c at the + // project's file list, otherwise the compiler-side processing won't pick it + // up (for non-directory form, it ends up looking in project binary dir + // only). Perhaps there's something to be done to make this more automatic + // on the CMake side? this->WriteString("<Midl>\n", 2); this->OutputIncludes(includes); this->WriteString("<OutputDirectory>$(IntDir)</OutputDirectory>\n", 3); @@ -1718,3 +1777,12 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() } this->WriteString("</ItemGroup>\n", 1); } + +bool cmVisualStudio10TargetGenerator:: + IsResxHeader(const std::string& headerFile) +{ + std::set<std::string>::iterator it = + this->GeneratorTarget->ExpectedResxHeaders.find(headerFile); + + return it != this->GeneratorTarget->ExpectedResxHeaders.end(); +} diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 55a850a..73d5961 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -62,6 +62,7 @@ private: void WriteWinRTReferences(); void WritePathAndIncrementalLinkOptions(); void WriteItemDefinitionGroups(); + bool ComputeClOptions(); bool ComputeClOptions(std::string const& configName); void WriteClOptions(std::string const& config, @@ -91,7 +92,7 @@ private: std::vector<cmSourceGroup>& ); void AddMissingSourceGroups(std::set<cmSourceGroup*>& groupsUsed, const std::vector<cmSourceGroup>& allGroups); - + bool IsResxHeader(const std::string& headerFile); private: typedef cmVisualStudioGeneratorOptions Options; diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index 1df0d9e..1c1988a 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -6,6 +6,7 @@ inline std::string cmVisualStudio10GeneratorOptionsEscapeForXML(const char* s) { std::string ret = s; + cmSystemTools::ReplaceString(ret, ";", "%3B"); cmSystemTools::ReplaceString(ret, "&", "&"); cmSystemTools::ReplaceString(ret, "<", "<"); cmSystemTools::ReplaceString(ret, ">", ">"); @@ -228,7 +229,7 @@ cmVisualStudioGeneratorOptions } if(this->Version >= cmLocalVisualStudioGenerator::VS10) { - // if there are configuration specifc flags, then + // if there are configuration specific flags, then // use the configuration specific tag for PreprocessorDefinitions if(this->Configuration.size()) { diff --git a/Source/cmVisualStudioSlnData.cxx b/Source/cmVisualStudioSlnData.cxx new file mode 100644 index 0000000..82b4ee8 --- /dev/null +++ b/Source/cmVisualStudioSlnData.cxx @@ -0,0 +1,62 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2013 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmVisualStudioSlnData.h" + +//---------------------------------------------------------------------------- +const cmSlnProjectEntry* +cmSlnData::GetProjectByGUID(const std::string& projectGUID) const +{ + ProjectStorage::const_iterator it(ProjectsByGUID.find(projectGUID)); + if (it != ProjectsByGUID.end()) + return &it->second; + else + return NULL; +} + +//---------------------------------------------------------------------------- +const cmSlnProjectEntry* +cmSlnData::GetProjectByName(const std::string& projectName) const +{ + ProjectStringIndex::const_iterator it(ProjectNameIndex.find(projectName)); + if (it != ProjectNameIndex.end()) + return &it->second->second; + else + return NULL; +} + +//---------------------------------------------------------------------------- +std::vector<cmSlnProjectEntry> cmSlnData::GetProjects() const +{ + ProjectStringIndex::const_iterator it(this->ProjectNameIndex.begin()), + itEnd(this->ProjectNameIndex.end()); + std::vector<cmSlnProjectEntry> result; + for (; it != itEnd; ++it) + result.push_back(it->second->second); + return result; +} + +//---------------------------------------------------------------------------- +cmSlnProjectEntry* cmSlnData::AddProject( + const std::string& projectGUID, + const std::string& projectName, + const std::string& projectRelativePath) +{ + ProjectStorage::iterator it(ProjectsByGUID.find(projectGUID)); + if (it != ProjectsByGUID.end()) + return NULL; + it = ProjectsByGUID.insert( + ProjectStorage::value_type( + projectGUID, + cmSlnProjectEntry(projectGUID, projectName, projectRelativePath))).first; + ProjectNameIndex[projectName] = it; + return &it->second; +} diff --git a/Source/cmVisualStudioSlnData.h b/Source/cmVisualStudioSlnData.h new file mode 100644 index 0000000..ec128cf --- /dev/null +++ b/Source/cmVisualStudioSlnData.h @@ -0,0 +1,58 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2013 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmVisualStudioSlnData_h +#define cmVisualStudioSlnData_h + +#include "cmStandardIncludes.h" + +class cmSlnProjectEntry +{ +public: + cmSlnProjectEntry() {} + cmSlnProjectEntry(const std::string& guid, + const std::string& name, + const std::string& relativePath) + : Guid(guid), Name(name), RelativePath(relativePath) + {} + + std::string GetGUID() const { return Guid; } + std::string GetName() const { return Name; } + std::string GetRelativePath() const { return RelativePath; } + +private: + std::string Guid, Name, RelativePath; +}; + + +class cmSlnData +{ +public: + const cmSlnProjectEntry* + GetProjectByGUID(const std::string& projectGUID) const; + + const cmSlnProjectEntry* + GetProjectByName(const std::string& projectName) const; + + std::vector<cmSlnProjectEntry> GetProjects() const; + + cmSlnProjectEntry* AddProject(const std::string& projectGUID, + const std::string& projectName, + const std::string& projectRelativePath); + +private: + typedef std::map<std::string, cmSlnProjectEntry> ProjectStorage; + ProjectStorage ProjectsByGUID; + typedef std::map<std::string, ProjectStorage::iterator> ProjectStringIndex; + ProjectStringIndex ProjectNameIndex; +}; + +#endif diff --git a/Source/cmVisualStudioSlnParser.cxx b/Source/cmVisualStudioSlnParser.cxx new file mode 100644 index 0000000..bae5974 --- /dev/null +++ b/Source/cmVisualStudioSlnParser.cxx @@ -0,0 +1,712 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2013 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmVisualStudioSlnParser.h" + +#include "cmSystemTools.h" +#include "cmVisualStudioSlnData.h" + +#include <cassert> +#include <stack> + +//---------------------------------------------------------------------------- +namespace +{ + enum LineFormat + { + LineMultiValueTag, + LineSingleValueTag, + LineKeyValuePair, + LineVerbatim + }; +} + +//---------------------------------------------------------------------------- +class cmVisualStudioSlnParser::ParsedLine +{ +public: + bool IsComment() const; + bool IsKeyValuePair() const; + + const std::string& GetTag() const { return this->Tag; } + const std::string& GetArg() const { return this->Arg.first; } + std::string GetArgVerbatim() const; + size_t GetValueCount() const { return this->Values.size(); } + const std::string& GetValue(size_t idxValue) const; + std::string GetValueVerbatim(size_t idxValue) const; + + void SetTag(const std::string& tag) { this->Tag = tag; } + void SetArg(const std::string& arg) { this->Arg = StringData(arg, false); } + void SetQuotedArg(const std::string& arg) + { this->Arg = StringData(arg, true); } + void AddValue(const std::string& value) + { this->Values.push_back(StringData(value, false)); } + void AddQuotedValue(const std::string& value) + { this->Values.push_back(StringData(value, true)); } + + void CopyVerbatim(const std::string& line) { this->Tag = line; } + +private: + typedef std::pair<std::string, bool> StringData; + std::string Tag; + StringData Arg; + std::vector<StringData> Values; + static const std::string BadString; + static const std::string Quote; +}; + +//---------------------------------------------------------------------------- +const std::string cmVisualStudioSlnParser::ParsedLine::BadString; +const std::string cmVisualStudioSlnParser::ParsedLine::Quote("\""); + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::ParsedLine::IsComment() const +{ + assert(!this->Tag.empty()); + return (this->Tag[0]== '#'); +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::ParsedLine::IsKeyValuePair() const +{ + assert(!this->Tag.empty()); + return this->Arg.first.empty() && this->Values.size() == 1; +} + +//---------------------------------------------------------------------------- +std::string cmVisualStudioSlnParser::ParsedLine::GetArgVerbatim() const +{ + if (this->Arg.second) + return Quote + this->Arg.first + Quote; + else + return this->Arg.first; +} + +//---------------------------------------------------------------------------- +const std::string& +cmVisualStudioSlnParser::ParsedLine::GetValue(size_t idxValue) const +{ + if (idxValue < this->Values.size()) + return this->Values[idxValue].first; + else + return BadString; +} + +//---------------------------------------------------------------------------- +std::string +cmVisualStudioSlnParser::ParsedLine::GetValueVerbatim(size_t idxValue) const +{ + if (idxValue < this->Values.size()) + { + const StringData& data = this->Values[idxValue]; + if (data.second) + return Quote + data.first + Quote; + else + return data.first; + } + else + return BadString; +} + +//---------------------------------------------------------------------------- +class cmVisualStudioSlnParser::State +{ +public: + explicit State(DataGroupSet requestedData); + + size_t GetCurrentLine() const { return this->CurrentLine; } + bool ReadLine(std::istream& input, std::string& line); + + LineFormat NextLineFormat() const; + + bool Process(const cmVisualStudioSlnParser::ParsedLine& line, + cmSlnData& output, + cmVisualStudioSlnParser::ResultData& result); + + bool Finished(cmVisualStudioSlnParser::ResultData& result); + +private: + enum FileState + { + FileStateStart, + FileStateTopLevel, + FileStateProject, + FileStateProjectDependencies, + FileStateGlobal, + FileStateSolutionConfigurations, + FileStateProjectConfigurations, + FileStateSolutionFilters, + FileStateGlobalSection, + FileStateIgnore + }; + std::stack<FileState> Stack; + std::string EndIgnoreTag; + DataGroupSet RequestedData; + size_t CurrentLine; + + void IgnoreUntilTag(const std::string& endTag); +}; + +//---------------------------------------------------------------------------- +cmVisualStudioSlnParser::State::State(DataGroupSet requestedData) : + RequestedData(requestedData), + CurrentLine(0) +{ + if (this->RequestedData.test(DataGroupProjectDependenciesBit)) + this->RequestedData.set(DataGroupProjectsBit); + this->Stack.push(FileStateStart); +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::State::ReadLine(std::istream& input, + std::string& line) +{ + ++this->CurrentLine; + return !std::getline(input, line).fail(); +} + +//---------------------------------------------------------------------------- +LineFormat cmVisualStudioSlnParser::State::NextLineFormat() const +{ + switch (this->Stack.top()) + { + case FileStateStart: return LineVerbatim; + case FileStateTopLevel: return LineMultiValueTag; + case FileStateProject: return LineSingleValueTag; + case FileStateProjectDependencies: return LineKeyValuePair; + case FileStateGlobal: return LineSingleValueTag; + case FileStateSolutionConfigurations: return LineKeyValuePair; + case FileStateProjectConfigurations: return LineKeyValuePair; + case FileStateSolutionFilters: return LineKeyValuePair; + case FileStateGlobalSection: return LineKeyValuePair; + case FileStateIgnore: return LineVerbatim; + default: + assert(false); + return LineVerbatim; + } +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::State::Process( + const cmVisualStudioSlnParser::ParsedLine& line, + cmSlnData& output, cmVisualStudioSlnParser::ResultData& result) +{ + assert(!line.IsComment()); + switch (this->Stack.top()) + { + case FileStateStart: + if (!cmSystemTools::StringStartsWith( + line.GetTag().c_str(), "Microsoft Visual Studio Solution File")) + { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + this->Stack.pop(); + this->Stack.push(FileStateTopLevel); + break; + case FileStateTopLevel: + if (line.GetTag().compare("Project") == 0) + { + if (line.GetValueCount() != 3) + { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + if (this->RequestedData.test(DataGroupProjectsBit)) + { + if (!output.AddProject(line.GetValue(2), + line.GetValue(0), + line.GetValue(1))) + { + result.SetError(ResultErrorInputData, this->GetCurrentLine()); + return false; + } + this->Stack.push(FileStateProject); + } + else + this->IgnoreUntilTag("EndProject"); + } + else if (line.GetTag().compare("Global") == 0) + this->Stack.push(FileStateGlobal); + else + { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + break; + case FileStateProject: + if (line.GetTag().compare("EndProject") == 0) + this->Stack.pop(); + else if (line.GetTag().compare("ProjectSection") == 0) + { + if (line.GetArg().compare("ProjectDependencies") == 0 && + line.GetValue(0).compare("postProject") == 0) + { + if (this->RequestedData.test(DataGroupProjectDependenciesBit)) + this->Stack.push(FileStateProjectDependencies); + else + this->IgnoreUntilTag("EndProjectSection"); + } + else + this->IgnoreUntilTag("EndProjectSection"); + } + else + { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + break; + case FileStateProjectDependencies: + if (line.GetTag().compare("EndProjectSection") == 0) + this->Stack.pop(); + else if (line.IsKeyValuePair()) + // implement dependency storing here, once needed + ; + else + { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + break; + case FileStateGlobal: + if (line.GetTag().compare("EndGlobal") == 0) + this->Stack.pop(); + else if (line.GetTag().compare("GlobalSection") == 0) + { + if (line.GetArg().compare("SolutionConfigurationPlatforms") == 0 && + line.GetValue(0).compare("preSolution") == 0) + { + if (this->RequestedData.test(DataGroupSolutionConfigurationsBit)) + this->Stack.push(FileStateSolutionConfigurations); + else + this->IgnoreUntilTag("EndGlobalSection"); + } + else if (line.GetArg().compare("ProjectConfigurationPlatforms") == 0 && + line.GetValue(0).compare("postSolution") == 0) + { + if (this->RequestedData.test(DataGroupProjectConfigurationsBit)) + this->Stack.push(FileStateProjectConfigurations); + else + this->IgnoreUntilTag("EndGlobalSection"); + } + else if (line.GetArg().compare("NestedProjects") == 0 && + line.GetValue(0).compare("preSolution") == 0) + { + if (this->RequestedData.test(DataGroupSolutionFiltersBit)) + this->Stack.push(FileStateSolutionFilters); + else + this->IgnoreUntilTag("EndGlobalSection"); + } + else if (this->RequestedData.test(DataGroupGenericGlobalSectionsBit)) + this->Stack.push(FileStateGlobalSection); + else + this->IgnoreUntilTag("EndGlobalSection"); + } + else + { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + break; + case FileStateSolutionConfigurations: + if (line.GetTag().compare("EndGlobalSection") == 0) + this->Stack.pop(); + else if (line.IsKeyValuePair()) + // implement configuration storing here, once needed + ; + else + { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + break; + case FileStateProjectConfigurations: + if (line.GetTag().compare("EndGlobalSection") == 0) + this->Stack.pop(); + else if (line.IsKeyValuePair()) + // implement configuration storing here, once needed + ; + else + { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + break; + case FileStateSolutionFilters: + if (line.GetTag().compare("EndGlobalSection") == 0) + this->Stack.pop(); + else if (line.IsKeyValuePair()) + // implement filter storing here, once needed + ; + else + { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + break; + case FileStateGlobalSection: + if (line.GetTag().compare("EndGlobalSection") == 0) + this->Stack.pop(); + else if (line.IsKeyValuePair()) + // implement section storing here, once needed + ; + else + { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + break; + case FileStateIgnore: + if (line.GetTag() == this->EndIgnoreTag) + { + this->Stack.pop(); + this->EndIgnoreTag = ""; + } + break; + default: + result.SetError(ResultErrorBadInternalState, this->GetCurrentLine()); + return false; + } + return true; +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::State::Finished( + cmVisualStudioSlnParser::ResultData& result) +{ + if (this->Stack.top() != FileStateTopLevel) + { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + result.Result = ResultOK; + return true; +} + +//---------------------------------------------------------------------------- +void cmVisualStudioSlnParser::State::IgnoreUntilTag(const std::string& endTag) +{ + this->Stack.push(FileStateIgnore); + this->EndIgnoreTag = endTag; +} + +//---------------------------------------------------------------------------- +cmVisualStudioSlnParser::ResultData::ResultData() + : Result(ResultOK) + , ResultLine(0) +{} + +//---------------------------------------------------------------------------- +void cmVisualStudioSlnParser::ResultData::Clear() +{ + *this = ResultData(); +} + +//---------------------------------------------------------------------------- +void cmVisualStudioSlnParser::ResultData::SetError(ParseResult error, + size_t line) +{ + this->Result = error; + this->ResultLine = line; +} + +//---------------------------------------------------------------------------- +const cmVisualStudioSlnParser::DataGroupSet +cmVisualStudioSlnParser::DataGroupProjects( + 1 << cmVisualStudioSlnParser::DataGroupProjectsBit); + +const cmVisualStudioSlnParser::DataGroupSet +cmVisualStudioSlnParser::DataGroupProjectDependencies( + 1 << cmVisualStudioSlnParser::DataGroupProjectDependenciesBit); + +const cmVisualStudioSlnParser::DataGroupSet +cmVisualStudioSlnParser::DataGroupSolutionConfigurations( + 1 << cmVisualStudioSlnParser::DataGroupSolutionConfigurationsBit); + +const cmVisualStudioSlnParser::DataGroupSet +cmVisualStudioSlnParser::DataGroupProjectConfigurations( + 1 << cmVisualStudioSlnParser::DataGroupProjectConfigurationsBit); + +const cmVisualStudioSlnParser::DataGroupSet +cmVisualStudioSlnParser::DataGroupSolutionFilters( + 1 << cmVisualStudioSlnParser::DataGroupSolutionFiltersBit); + +const cmVisualStudioSlnParser::DataGroupSet +cmVisualStudioSlnParser::DataGroupGenericGlobalSections( + 1 << cmVisualStudioSlnParser::DataGroupGenericGlobalSectionsBit); + +const cmVisualStudioSlnParser::DataGroupSet +cmVisualStudioSlnParser::DataGroupAll(~0); + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::Parse(std::istream& input, + cmSlnData& output, + DataGroupSet dataGroups) +{ + this->LastResult.Clear(); + if (!this->IsDataGroupSetSupported(dataGroups)) + { + this->LastResult.SetError(ResultErrorUnsupportedDataGroup, 0); + return false; + } + State state(dataGroups); + return this->ParseImpl(input, output, state); +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::ParseFile(const std::string& file, + cmSlnData& output, + DataGroupSet dataGroups) +{ + this->LastResult.Clear(); + if (!this->IsDataGroupSetSupported(dataGroups)) + { + this->LastResult.SetError(ResultErrorUnsupportedDataGroup, 0); + return false; + } + std::ifstream f(file.c_str()); + if (!f) + { + this->LastResult.SetError(ResultErrorOpeningInput, 0); + return false; + } + State state(dataGroups); + return this->ParseImpl(f, output, state); +} + +//---------------------------------------------------------------------------- +cmVisualStudioSlnParser::ParseResult +cmVisualStudioSlnParser::GetParseResult() const +{ + return this->LastResult.Result; +} + +//---------------------------------------------------------------------------- +size_t cmVisualStudioSlnParser::GetParseResultLine() const +{ + return this->LastResult.ResultLine; +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::GetParseHadBOM() const +{ + return this->LastResult.HadBOM; +} + +//---------------------------------------------------------------------------- +bool +cmVisualStudioSlnParser::IsDataGroupSetSupported(DataGroupSet dataGroups) const +{ + return (dataGroups & DataGroupProjects) == dataGroups; + //only supporting DataGroupProjects for now +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::ParseImpl(std::istream& input, + cmSlnData& output, + State& state) +{ + std::string line; + // Does the .sln start with a Byte Order Mark? + if (!this->ParseBOM(input, line, state)) + return false; + do + { + line = cmSystemTools::TrimWhitespace(line); + if (line.empty()) + continue; + ParsedLine parsedLine; + switch (state.NextLineFormat()) + { + case LineMultiValueTag: + if (!this->ParseMultiValueTag(line, parsedLine, state)) + return false; + break; + case LineSingleValueTag: + if (!this->ParseSingleValueTag(line, parsedLine, state)) + return false; + break; + case LineKeyValuePair: + if (!this->ParseKeyValuePair(line, parsedLine, state)) + return false; + break; + case LineVerbatim: + parsedLine.CopyVerbatim(line); + break; + } + if (parsedLine.IsComment()) + continue; + if (!state.Process(parsedLine, output, this->LastResult)) + return false; + } + while (state.ReadLine(input, line)); + return state.Finished(this->LastResult); +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::ParseBOM(std::istream& input, + std::string& line, + State& state) +{ + char bom[4]; + if (!input.get(bom, 4)) + { + this->LastResult.SetError(ResultErrorReadingInput, 1); + return false; + } + this->LastResult.HadBOM = + (bom[0] == char(0xEF) && bom[1] == char(0xBB) && bom[2] == char(0xBF)); + if (!state.ReadLine(input, line)) + { + this->LastResult.SetError(ResultErrorReadingInput, 1); + return false; + } + if (!this->LastResult.HadBOM) + line = bom + line; // it wasn't a BOM, prepend it to first line + return true; +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::ParseMultiValueTag(const std::string& line, + ParsedLine& parsedLine, + State& state) +{ + size_t idxEqualSign = line.find('='); + const std::string& fullTag = line.substr(0, idxEqualSign); + if (!this->ParseTag(fullTag, parsedLine, state)) + return false; + if (idxEqualSign != line.npos) + { + size_t idxFieldStart = idxEqualSign + 1; + if (idxFieldStart < line.size()) + { + size_t idxParsing = idxFieldStart; + bool inQuotes = false; + for (;;) + { + idxParsing = line.find_first_of(",\"", idxParsing); + bool fieldOver = false; + if (idxParsing == line.npos) + { + fieldOver = true; + if (inQuotes) + { + this->LastResult.SetError(ResultErrorInputStructure, + state.GetCurrentLine()); + return false; + } + } + else if (line[idxParsing] == ',' && !inQuotes) + fieldOver = true; + else if (line[idxParsing] == '"') + inQuotes = !inQuotes; + if (fieldOver) + { + if (!this->ParseValue(line.substr(idxFieldStart, + idxParsing - idxFieldStart), + parsedLine)) + return false; + if (idxParsing == line.npos) + break; //end of last field + idxFieldStart = idxParsing + 1; + } + ++idxParsing; + } + } + } + return true; +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::ParseSingleValueTag(const std::string& line, + ParsedLine& parsedLine, + State& state) +{ + size_t idxEqualSign = line.find('='); + const std::string& fullTag = line.substr(0, idxEqualSign); + if (!this->ParseTag(fullTag, parsedLine, state)) + return false; + if (idxEqualSign != line.npos) + { + if (!this->ParseValue(line.substr(idxEqualSign + 1), parsedLine)) + return false; + } + return true; +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::ParseKeyValuePair(const std::string& line, + ParsedLine& parsedLine, + State& /*state*/) +{ + size_t idxEqualSign = line.find('='); + if (idxEqualSign == line.npos) + { + parsedLine.CopyVerbatim(line); + return true; + } + const std::string& key = line.substr(0, idxEqualSign); + parsedLine.SetTag(cmSystemTools::TrimWhitespace(key)); + const std::string& value = line.substr(idxEqualSign + 1); + parsedLine.AddValue(cmSystemTools::TrimWhitespace(value)); + return true; +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::ParseTag(const std::string& fullTag, + ParsedLine& parsedLine, + State& state) +{ + size_t idxLeftParen = fullTag.find('('); + if (idxLeftParen == fullTag.npos) + { + parsedLine.SetTag(cmSystemTools::TrimWhitespace(fullTag)); + return true; + } + parsedLine.SetTag( + cmSystemTools::TrimWhitespace(fullTag.substr(0, idxLeftParen))); + size_t idxRightParen = fullTag.rfind(')'); + if (idxRightParen == fullTag.npos) + { + this->LastResult.SetError(ResultErrorInputStructure, + state.GetCurrentLine()); + return false; + } + const std::string& arg = cmSystemTools::TrimWhitespace( + fullTag.substr(idxLeftParen + 1, idxRightParen - idxLeftParen - 1)); + if (arg[0] == '"') + { + if (arg[arg.size() - 1] != '"') + { + this->LastResult.SetError(ResultErrorInputStructure, + state.GetCurrentLine()); + return false; + } + parsedLine.SetQuotedArg(arg.substr(1, arg.size() - 2)); + } + else + parsedLine.SetArg(arg); + return true; +} + +//---------------------------------------------------------------------------- +bool cmVisualStudioSlnParser::ParseValue(const std::string& value, + ParsedLine& parsedLine) +{ + const std::string& trimmed = cmSystemTools::TrimWhitespace(value); + if (trimmed.empty()) + parsedLine.AddValue(trimmed); + else if (trimmed[0] == '"' && trimmed[trimmed.size() - 1] == '"') + parsedLine.AddQuotedValue(trimmed.substr(1, trimmed.size() - 2)); + else + parsedLine.AddValue(trimmed); + return true; +} diff --git a/Source/cmVisualStudioSlnParser.h b/Source/cmVisualStudioSlnParser.h new file mode 100644 index 0000000..bee70cc --- /dev/null +++ b/Source/cmVisualStudioSlnParser.h @@ -0,0 +1,118 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2013 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmVisualStudioSlnParser_h +#define cmVisualStudioSlnParser_h + +#include "cmStandardIncludes.h" + +#include <bitset> + + +class cmSlnData; + + +class cmVisualStudioSlnParser +{ +public: + enum ParseResult + { + ResultOK = 0, + + ResultInternalError = -1, + ResultExternalError = 1, + + ResultErrorOpeningInput = ResultExternalError, + ResultErrorReadingInput, + ResultErrorInputStructure, + ResultErrorInputData, + + ResultErrorBadInternalState = ResultInternalError, + ResultErrorUnsupportedDataGroup = ResultInternalError - 1 + }; + + enum DataGroup + { + DataGroupProjectsBit, + DataGroupProjectDependenciesBit, + DataGroupSolutionConfigurationsBit, + DataGroupProjectConfigurationsBit, + DataGroupSolutionFiltersBit, + DataGroupGenericGlobalSectionsBit, + DataGroupCount + }; + + typedef std::bitset<DataGroupCount> DataGroupSet; + + static const DataGroupSet DataGroupProjects; + static const DataGroupSet DataGroupProjectDependencies; + static const DataGroupSet DataGroupSolutionConfigurations; + static const DataGroupSet DataGroupProjectConfigurations; + static const DataGroupSet DataGroupSolutionFilters; + static const DataGroupSet DataGroupGenericGlobalSections; + static const DataGroupSet DataGroupAll; + + bool Parse(std::istream& input, + cmSlnData& output, + DataGroupSet dataGroups = DataGroupAll); + + bool ParseFile(const std::string& file, + cmSlnData& output, + DataGroupSet dataGroups = DataGroupAll); + + ParseResult GetParseResult() const; + + size_t GetParseResultLine() const; + + bool GetParseHadBOM() const; + +protected: + class State; + friend class State; + class ParsedLine; + + struct ResultData + { + ParseResult Result; + size_t ResultLine; + bool HadBOM; + + ResultData(); + void Clear(); + void SetError(ParseResult error, size_t line); + } LastResult; + + bool IsDataGroupSetSupported(DataGroupSet dataGroups) const; + + bool ParseImpl(std::istream& input, cmSlnData& output, State& state); + + bool ParseBOM(std::istream& input, std::string& line, State& state); + + bool ParseMultiValueTag(const std::string& line, + ParsedLine& parsedLine, + State& state); + + bool ParseSingleValueTag(const std::string& line, + ParsedLine& parsedLine, + State& state); + + bool ParseKeyValuePair(const std::string& line, + ParsedLine& parsedLine, + State& state); + + bool ParseTag(const std::string& fullTag, + ParsedLine& parsedLine, + State& state); + + bool ParseValue(const std::string& value, ParsedLine& parsedLine); +}; + +#endif diff --git a/Source/cmWin32ProcessExecution.cxx b/Source/cmWin32ProcessExecution.cxx index 5752ab6..1bdeffb 100644 --- a/Source/cmWin32ProcessExecution.cxx +++ b/Source/cmWin32ProcessExecution.cxx @@ -506,7 +506,7 @@ bool cmWin32ProcessExecution::PrivateOpen(const char *cmdstring, /* Create new output read handle and the input write handle. Set * the inheritance properties to FALSE. Otherwise, the child inherits - * the these handles; resulting in non-closeable handles to the pipes + * these handles; resulting in non-closeable handles to the pipes * being created. */ fSuccess = DuplicateHandle(GetCurrentProcess(), this->hChildStdinWr, GetCurrentProcess(), &this->hChildStdinWrDup, 0, diff --git a/Source/cmWin32ProcessExecution.h b/Source/cmWin32ProcessExecution.h index 98b6bda..2127ebd2 100644 --- a/Source/cmWin32ProcessExecution.h +++ b/Source/cmWin32ProcessExecution.h @@ -69,7 +69,7 @@ public: /** * Start the process in the directory path. Make sure that the * executable is either in the path or specify the full path. The - * argument verbose specifies wether or not to display output while + * argument verbose specifies whether or not to display output while * it is being generated. */ bool StartProcess(const char*, const char* path, bool verbose); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index e2f80d1..ae62edb 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -128,7 +128,7 @@ void cmNeedBackwardsCompatibility(const std::string& variable, "by CMake in versions prior to 1.6. To fix this you might need to set " "the cache value of CMAKE_BACKWARDS_COMPATIBILITY to 1.4 or less. If " "you are writing a CMakeLists file, (or have already set " - "CMAKE_BACKWARDS_COMPATABILITY to 1.4 or less) then you probably need " + "CMAKE_BACKWARDS_COMPATIBILITY to 1.4 or less) then you probably need " "to include a CMake module to test for the feature this variable " "defines."; cmSystemTools::Error(message.c_str()); @@ -2365,7 +2365,7 @@ int cmake::ActualConfigure() // EXECUTABLE_OUTPUT_PATH. They are now documented as old-style and // should no longer be used. Therefore we present them only if the // project requires compatibility with CMake 2.4. We detect this - // here by looking for the old CMAKE_BACKWARDS_COMPATABILITY + // here by looking for the old CMAKE_BACKWARDS_COMPATIBILITY // variable created when CMP0001 is not set to NEW. if(this->GetCacheManager()->GetCacheValue("CMAKE_BACKWARDS_COMPATIBILITY")) { @@ -4045,7 +4045,7 @@ static bool cmakeCheckStampFile(const char* stampName) // TODO: Teach cmGeneratedFileStream to use a random temp file (with // multiple tries in unlikely case of conflict) and use that here. std::ofstream stamp(stampTemp); - stamp << "# CMake generation timestamp file this directory.\n"; + stamp << "# CMake generation timestamp file for this directory.\n"; } if(cmSystemTools::RenameFile(stampTemp, stampName)) { @@ -4117,7 +4117,7 @@ int cmake::WindowsCEEnvironment(const char* version, const std::string& name) return -1; } -// For visual studio 2005 and newer manifest files need to be embeded into +// For visual studio 2005 and newer manifest files need to be embedded into // exe and dll's. This code does that in such a way that incremental linking // still works. int cmake::VisualStudioLink(std::vector<std::string>& args, int type) @@ -4173,7 +4173,7 @@ int cmake::VisualStudioLink(std::vector<std::string>& args, int type) { if(verbose) { - std::cout << "Visual Studio Incremental Link with embeded manifests\n"; + std::cout << "Visual Studio Incremental Link with embedded manifests\n"; } return cmake::VisualStudioLinkIncremental(expandedArgs, type, verbose); } diff --git a/Source/cmake.h b/Source/cmake.h index 63065a1..a50c1ed 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -35,7 +35,7 @@ class cmGeneratedFileStream; /** \brief Represents a cmake invocation. * * This class represents a cmake invocation. It is the top level class when - * running cmake. Most cmake based GUIS should primarily create an instance + * running cmake. Most cmake based GUIs should primarily create an instance * of this class and communicate with it. * * The basic process for a GUI is as follows: @@ -255,7 +255,7 @@ class cmake typedef void (*ProgressCallbackType) (const char*msg, float progress, void *); /** - * Set the function used by GUI's to receive progress updates + * Set the function used by GUIs to receive progress updates * Function gets passed: message as a const char*, a progress * amount ranging from 0 to 1.0 and client data. The progress * number provided may be negative in cases where a message is @@ -532,9 +532,9 @@ private: "CMakeCache.txt file, globbing expressions using * and ? are supported. "\ "The option may be repeated for as many cache entries as desired.\n" \ "Use with care, you can make your CMakeCache.txt non-working."}, \ - {"-G <generator-name>", "Specify a makefile generator.", \ + {"-G <generator-name>", "Specify a build system generator.", \ "CMake may support multiple native build systems on certain platforms. " \ - "A makefile generator is responsible for generating a particular build " \ + "A generator is responsible for generating a particular build " \ "system. Possible generator names are specified in the Generators " \ "section."},\ {"-T <toolset-name>", "Specify toolset name if supported by generator.", \ diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 4267841..77a5e43 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -86,8 +86,8 @@ static const char * cmDocumentationOptions[][3] = {"-L[A][H]", "List non-advanced cached variables.", "List cache variables will run CMake and list all the variables from the " "CMake cache that are not marked as INTERNAL or ADVANCED. This will " - "effectively display current CMake settings, which can be then changed " - "with -D option. Changing some of the variable may result in more " + "effectively display current CMake settings, which can then be changed " + "with -D option. Changing some of the variables may result in more " "variables being created. If A is specified, then it will display also " "advanced variables. If H is specified, it will also display help for " "each variable."}, @@ -152,7 +152,7 @@ static const char * cmDocumentationOptions[][3] = "format is determined depending on the filename suffix. Supported are man " "page, HTML, DocBook and plain text."}, {"--help-commands [file]", "Print help for all commands and exit.", - "Full documentation specific for all current command is displayed." + "Full documentation specific for all current commands is displayed." "If a file is specified, the documentation is written into and the output " "format is determined depending on the filename suffix. Supported are man " "page, HTML, DocBook and plain text."}, diff --git a/Source/cmakewizard.cxx b/Source/cmakewizard.cxx index 749f669..bac403a 100644 --- a/Source/cmakewizard.cxx +++ b/Source/cmakewizard.cxx @@ -28,7 +28,7 @@ void cmakewizard::AskUser(const char* key, printf("Current Value: %s\n", iter.GetValue()); printf("New Value (Enter to keep current value): "); char buffer[4096]; - if(!fgets(buffer, sizeof(buffer)-1, stdin)) + if(!fgets(buffer, static_cast<int>(sizeof(buffer) - 1), stdin)) { buffer[0] = 0; } @@ -67,16 +67,13 @@ bool cmakewizard::AskAdvanced() { printf("Would you like to see advanced options? [No]:"); char buffer[4096]; - if(!fgets(buffer, sizeof(buffer)-1, stdin)) + if(!fgets(buffer, static_cast<int>(sizeof(buffer) - 1), stdin)) { buffer[0] = 0; } - if(buffer[0]) + else if(buffer[0] == 'y' || buffer[0] == 'Y') { - if(buffer[0] == 'y' || buffer[0] == 'Y') - { - return true; - } + return true; } return false; } diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx index 04dab59..262d83b 100644 --- a/Source/cmcldeps.cxx +++ b/Source/cmcldeps.cxx @@ -225,7 +225,7 @@ static int process( const std::string& srcfilename, int main() { - // Use the Win32 api instead of argc/argv so we can avoid interpreting the + // Use the Win32 API instead of argc/argv so we can avoid interpreting the // rest of command line after the .d and .obj. Custom parsing seemed // preferable to the ugliness you get into in trying to re-escape quotes for // subprocesses, so by avoiding argc/argv, the subprocess is called with diff --git a/Source/ctest.cxx b/Source/ctest.cxx index 3e63183..e767a16 100644 --- a/Source/ctest.cxx +++ b/Source/ctest.cxx @@ -60,7 +60,7 @@ static const char * cmDocumentationOptions[][3] = "Test output is normally suppressed and only summary information is " "displayed. This option will show even more test output."}, {"--debug", "Displaying more verbose internals of CTest.", - "This feature will result in large number of output that is mostly " + "This feature will result in a large number of output that is mostly " "useful for debugging dashboard problems."}, {"--output-on-failure", "Output anything outputted by the test program " "if the test should fail. This option can also be enabled by setting " @@ -71,7 +71,8 @@ static const char * cmDocumentationOptions[][3] = {"-j <jobs>, --parallel <jobs>", "Run the tests in parallel using the" "given number of jobs.", "This option tells ctest to run the tests in parallel using given " - "number of jobs."}, + "number of jobs. This option can also be set by setting " + "the environment variable CTEST_PARALLEL_LEVEL."}, {"-Q,--quiet", "Make ctest quiet.", "This option will suppress all the output. The output log file will " "still be generated if the --output-log is specified. Options such " @@ -99,7 +100,7 @@ static const char * cmDocumentationOptions[][3] = "This option tells ctest to NOT run the tests whose labels match the " "given regular expression."}, {"-D <dashboard>, --dashboard <dashboard>", "Execute dashboard test", - "This option tells ctest to perform act as a Dart client and perform " + "This option tells ctest to act as a Dart client and perform " "a dashboard test. All tests are <Mode><Test>, where Mode can be " "Experimental, Nightly, and Continuous, and Test can be Start, Update, " "Configure, Build, Test, Coverage, and Submit."}, @@ -171,7 +172,7 @@ static const char * cmDocumentationOptions[][3] = "to this command line are the source and binary directories. By default " "this will run CMake on the Source/Bin directories specified unless " "--build-nocmake is specified. Both --build-makeprogram and " - "--build-generator MUST be provided to use --built-and-test. If " + "--build-generator MUST be provided to use --build-and-test. If " "--test-command is specified then that will be run after the build is " "complete. Other options that affect this mode are --build-target " "--build-nocmake, --build-run-dir, " diff --git a/Source/kwsys/CommandLineArguments.hxx.in b/Source/kwsys/CommandLineArguments.hxx.in index 68e9600..cbf6ee3 100644 --- a/Source/kwsys/CommandLineArguments.hxx.in +++ b/Source/kwsys/CommandLineArguments.hxx.in @@ -44,7 +44,7 @@ struct CommandLineArgumentsCallbackStructure; * * For the variable interface you associate variable with each argument. When * the argument is specified, the variable is set to the specified value casted - * to the apropriate type. For boolean (NO_ARGUMENT), the value is "1". + * to the appropriate type. For boolean (NO_ARGUMENT), the value is "1". * * Both interfaces can be used at the same time. * @@ -99,7 +99,7 @@ public: STRING_TYPE, // The variable is string (char*) STL_STRING_TYPE, // The variable is string (char*) VECTOR_INT_TYPE, // The variable is integer (int) - VECTOR_BOOL_TYPE, // The vairable is boolean (bool) + VECTOR_BOOL_TYPE, // The variable is boolean (bool) VECTOR_DOUBLE_TYPE, // The variable is float (double) VECTOR_STRING_TYPE, // The variable is string (char*) VECTOR_STL_STRING_TYPE, // The variable is string (char*) @@ -128,7 +128,7 @@ public: void ProcessArgument(const char* arg); /** - * This method will parse arguments and call apropriate methods. + * This method will parse arguments and call appropriate methods. */ int Parse(); @@ -144,7 +144,7 @@ public: /** * Add handler for argument which is going to set the variable to the * specified value. If the argument is specified, the option is casted to the - * apropriate type. + * appropriate type. */ void AddArgument(const char* argument, ArgumentTypeEnum type, bool* variable, const char* help); @@ -160,7 +160,7 @@ public: /** * Add handler for argument which is going to set the variable to the * specified value. If the argument is specified, the option is casted to the - * apropriate type. This will handle the multi argument values. + * appropriate type. This will handle the multi argument values. */ void AddArgument(const char* argument, ArgumentTypeEnum type, kwsys_stl::vector<bool>* variable, const char* help); diff --git a/Source/kwsys/SharedForward.h.in b/Source/kwsys/SharedForward.h.in index 8521099..8bbc74a 100644 --- a/Source/kwsys/SharedForward.h.in +++ b/Source/kwsys/SharedForward.h.in @@ -772,7 +772,7 @@ static int kwsys_shared_forward_get_settings(const char* self_path, const char** dir; for(dir = search_path; *dir; ++dir) { - /* Add seperator between path components. */ + /* Add separator between path components. */ if(dir != search_path) { strcat(ldpath, kwsys_shared_forward_path_sep); diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index 9e2a93d..9db1dee 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -1471,7 +1471,7 @@ int SystemInformationImplementation::GetFullyQualifiedDomainName( { char host[NI_MAXHOST]={'\0'}; - int addrlen + socklen_t addrlen = (fam==AF_INET?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6)); ierr=getnameinfo( @@ -3487,7 +3487,7 @@ bool SystemInformationImplementation::QueryLinuxMemory() bool have[6] = { false, false, false, false, false, false }; unsigned long value[6]; int count = 0; - while(fgets(buffer, sizeof(buffer), fd)) + while(fgets(buffer, static_cast<int>(sizeof(buffer)), fd)) { for(int i=0; i < 6; ++i) { diff --git a/Source/kwsys/SystemInformation.hxx.in b/Source/kwsys/SystemInformation.hxx.in index 8f4cb4e..f7c454e 100644 --- a/Source/kwsys/SystemInformation.hxx.in +++ b/Source/kwsys/SystemInformation.hxx.in @@ -117,8 +117,8 @@ public: // Get total system RAM in units of KiB available to this process. // This may differ from the host available if a per-process resource // limit is applied. per-process memory limits are applied on unix - // system via rlimit api. Resource limits that are not imposed via - // rlimit api may be reported to us via an application specified + // system via rlimit API. Resource limits that are not imposed via + // rlimit API may be reported to us via an application specified // environment variable. LongLong GetProcMemoryAvailable( const char *hostLimitEnvVarName=NULL, diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 22bf193..158217e 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -2741,15 +2741,24 @@ bool SystemTools::FileIsDirectory(const char* name) return false; } - // Remove any trailing slash from the name. - char buffer[KWSYS_SYSTEMTOOLS_MAXPATH]; + // Remove any trailing slash from the name except in a root component. + char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH]; + std::string string_buffer; size_t last = length-1; if(last > 0 && (name[last] == '/' || name[last] == '\\') - && strcmp(name, "/") !=0) + && strcmp(name, "/") !=0 && name[last-1] != ':') { - memcpy(buffer, name, last); - buffer[last] = 0; - name = buffer; + if(last < sizeof(local_buffer)) + { + memcpy(local_buffer, name, last); + local_buffer[last] = 0; + name = local_buffer; + } + else + { + string_buffer.append(name, last); + name = string_buffer.c_str(); + } } // Now check the file node type. @@ -4002,7 +4011,7 @@ void SystemTools::SplitProgramFromArgs(const char* path, args = dir.substr(spacePos, dir.size()-spacePos); return; } - // Now try and find the the program in the path + // Now try and find the program in the path findProg = SystemTools::FindProgram(tryProg.c_str(), e); if(findProg.size()) { diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index 9c56e96..e55d431 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -766,7 +766,7 @@ public: static kwsys_stl::string GetCurrentWorkingDirectory(bool collapse =true); /** - * Change directory the the directory specified + * Change directory to the directory specified */ static int ChangeDirectory(const char* dir); diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx index 61c1572..dd6d603 100644 --- a/Source/kwsys/testDynamicLoader.cxx +++ b/Source/kwsys/testDynamicLoader.cxx @@ -109,9 +109,9 @@ int testDynamicLoader(int argc, char *argv[]) // dlopen() on Syllable before 11/22/2007 doesn't return 0 on error #ifndef __SYLLABLE__ - // Make sure that inexistant lib is giving correct result + // Make sure that inexistent lib is giving correct result res += TestDynamicLoader("azerty_", "foo_bar",0,0,0); - // Make sure that random binary file cannnot be assimilated as dylib + // Make sure that random binary file cannot be assimilated as dylib res += TestDynamicLoader(TEST_SYSTEMTOOLS_BIN_FILE, "wp",0,0,0); #endif diff --git a/Source/kwsys/testIOS.cxx b/Source/kwsys/testIOS.cxx index 3b971e2..f0c7f1a 100644 --- a/Source/kwsys/testIOS.cxx +++ b/Source/kwsys/testIOS.cxx @@ -48,7 +48,7 @@ int testIOS(int, char*[]) return 1; } static const unsigned char array[] = { 0xff,0x4f,0xff,0x51,0x00,0x29,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x07,0x01,0x01,0xff,0x52,0x00,0x0c,0x00,0x00,0x00,0x01,0x00,0x05,0x04,0x04,0x00,0x01,0xff,0x5c,0x00,0x13,0x40,0x40,0x48,0x48,0x50,0x48,0x48,0x50,0x48,0x48,0x50,0x48,0x48,0x50,0x48,0x48,0x50,0xff,0x64,0x00,0x2c,0x00,0x00,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x49,0x54,0x4b,0x2f,0x47,0x44,0x43,0x4d,0x2f,0x4f,0x70,0x65,0x6e,0x4a,0x50,0x45,0x47,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x2e,0x30,0xff,0x90,0x00,0x0a,0x00,0x00,0x00,0x00,0x06,0x2c,0x00,0x01,0xff,0x93,0xcf,0xb0,0x18,0x08,0x7f,0xc6,0x99,0xbf,0xff,0xc0,0xf8,0xc1,0xc1,0xf3,0x05,0x81,0xf2,0x83,0x0a,0xa5,0xff,0x10,0x90,0xbf,0x2f,0xff,0x04,0xa8,0x7f,0xc0,0xf8,0xc4,0xc1,0xf3,0x09,0x81,0xf3,0x0c,0x19,0x34 }; - const unsigned int narray = sizeof(array); // 180 + const size_t narray = sizeof(array); // 180 kwsys_ios::stringstream strstr; strstr.write( (char*)array, narray ); //strstr.seekp( narray / 2 ); // set position of put pointer in mid string diff --git a/Source/kwsys/testSystemInformation.cxx b/Source/kwsys/testSystemInformation.cxx index 49a686c..738043f 100644 --- a/Source/kwsys/testSystemInformation.cxx +++ b/Source/kwsys/testSystemInformation.cxx @@ -88,9 +88,9 @@ int testSystemInformation(int, char*[]) printMethod3(info, GetHostMemoryUsed(), "KiB"); printMethod3(info, GetProcMemoryUsed(), "KiB"); - for (int i = 0; i <= 31; i++) + for (long int i = 0; i <= 31; i++) { - if (info.DoesCPUSupportFeature(1 << i)) + if (info.DoesCPUSupportFeature(static_cast<long int>(1) << i)) { kwsys_ios::cout << "CPU feature " << i << "\n"; } |