diff options
author | Brad King <brad.king@kitware.com> | 2013-06-28 18:29:54 -0400 |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2013-06-28 18:29:54 -0400 |
commit | 4e5cb398ae392079031ae6a880569349c29770a6 (patch) | |
tree | 55b13e53e2368e0425602fb8527936accc50ac9a /Source | |
parent | 78fdbbcb4130eedc2cb48ec9e67fad5c2beffb0e (diff) | |
parent | daaf6283f5c0e8b7ea7ee93f983ad56d4498788d (diff) | |
download | cmake-4e5cb398ae392079031ae6a880569349c29770a6.tar.gz |
Merge branch 'master' into vs12-generator
Resolve conflicts in Tests/Preprocess/CMakeLists.txt by keeping
the side from 'master'.
Diffstat (limited to 'Source')
157 files changed, 5389 insertions, 1357 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index f0519fe7c6..64fc53f447 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -11,7 +11,11 @@ #============================================================================= include(CheckIncludeFile) # Check if we can build support for ELF parsing. -CHECK_INCLUDE_FILE("elf.h" HAVE_ELF_H) +if(CMAKE_CXX_PLATFORM_ID MATCHES "OpenBSD") + CHECK_INCLUDE_FILES("stdint.h;elf_abi.h" HAVE_ELF_H) +else() + CHECK_INCLUDE_FILE("elf.h" HAVE_ELF_H) +endif() if(HAVE_ELF_H) set(CMAKE_USE_ELF_PARSER 1) else() @@ -113,7 +117,8 @@ endif() set(SRCS cmStandardIncludes.cxx cmArchiveWrite.cxx - cmBootstrapCommands.cxx + cmBootstrapCommands1.cxx + cmBootstrapCommands2.cxx cmCacheManager.cxx cmCacheManager.h cmCommands.cxx @@ -359,6 +364,10 @@ if (WIN32) cmLocalVisualStudio7Generator.h cmLocalVisualStudioGenerator.cxx cmLocalVisualStudioGenerator.h + cmVisualStudioSlnData.h + cmVisualStudioSlnData.cxx + cmVisualStudioSlnParser.h + cmVisualStudioSlnParser.cxx cmVisualStudioWCEPlatformParser.h cmVisualStudioWCEPlatformParser.cxx cmWin32ProcessExecution.cxx @@ -539,7 +548,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 6d793b4b1e..fa871b4be9 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 20130515) +set(CMake_VERSION_PATCH 11) +set(CMake_VERSION_TWEAK 20130628) #set(CMake_VERSION_RC 1) diff --git a/Source/CPack/cmCPackDocumentVariables.cxx b/Source/CPack/cmCPackDocumentVariables.cxx index 6a841fa8d4..1dfaaf990b 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 7cc1522697..3c685bd9d1 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 f4d38cef14..1f63185c1b 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 d6d39a98fb..db33cb68ee 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 453e32ce2b..2e2feb047c 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 80218ad38d..8baa673e79 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 1e81c893b0..0a8c1b3f04 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 5eabf3fbe1..ddd7e4545a 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 e7491bba35..0508448d92 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 000bc8503d..167b992c9b 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 f234722f37..b9611bf104 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 8fc4cd7b6b..59058a98ce 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 c0dde1c2c7..4d62f72633 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 259967580e..963c7d12e3 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 dc8ee3fbd3..98da249d5e 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 6006758c72..bae6a30a74 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/cmAddCompileOptionsCommand.cxx b/Source/cmAddCompileOptionsCommand.cxx new file mode 100644 index 0000000000..a6c3c005cf --- /dev/null +++ b/Source/cmAddCompileOptionsCommand.cxx @@ -0,0 +1,28 @@ +/*============================================================================ + 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 "cmAddCompileOptionsCommand.h" + +bool cmAddCompileOptionsCommand +::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) +{ + if(args.size() < 1 ) + { + return true; + } + + for(std::vector<std::string>::const_iterator i = args.begin(); + i != args.end(); ++i) + { + this->Makefile->AddCompileOption(i->c_str()); + } + return true; +} diff --git a/Source/cmAddCompileOptionsCommand.h b/Source/cmAddCompileOptionsCommand.h new file mode 100644 index 0000000000..45047957a2 --- /dev/null +++ b/Source/cmAddCompileOptionsCommand.h @@ -0,0 +1,72 @@ +/*============================================================================ + 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 cmAddCompileOptionsCommand_h +#define cmAddCompileOptionsCommand_h + +#include "cmCommand.h" +#include "cmDocumentGeneratorExpressions.h" + +class cmAddCompileOptionsCommand : public cmCommand +{ +public: + /** + * This is a virtual constructor for the command. + */ + virtual cmCommand* Clone() + { + return new cmAddCompileOptionsCommand; + } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + virtual bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus &status); + + /** + * The name of the command as specified in CMakeList.txt. + */ + virtual const char* GetName() const {return "add_compile_options";} + + /** + * Succinct documentation. + */ + virtual const char* GetTerseDocumentation() const + { + return "Adds options to the compilation of source files."; + } + + /** + * More documentation. + */ + virtual const char* GetFullDocumentation() const + { + return + " add_compile_options(<option> ...)\n" + "Adds options to the compiler command line for sources in the " + "current directory and below. This command can be used to add any " + "options, but alternative commands exist to add preprocessor " + "definitions or include directories. " + "See documentation of the directory and target COMPILE_OPTIONS " + "properties for details. " + "Arguments to add_compile_options may use \"generator " + "expressions\" with the syntax \"$<...>\". " + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS + ; + } + + cmTypeMacro(cmAddCompileOptionsCommand, cmCommand); +}; + +#endif diff --git a/Source/cmAddDefinitionsCommand.h b/Source/cmAddDefinitionsCommand.h index 7bb37674d2..ff2c4a038e 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 " @@ -73,8 +73,6 @@ public: } cmTypeMacro(cmAddDefinitionsCommand, cmCommand); -private: - bool ParseDefinition(std::string const& def); }; diff --git a/Source/cmAddSubDirectoryCommand.h b/Source/cmAddSubDirectoryCommand.h index fa322b0c4e..e7f907c3f1 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/cmBootstrapCommands1.cxx b/Source/cmBootstrapCommands1.cxx new file mode 100644 index 0000000000..9093579dc8 --- /dev/null +++ b/Source/cmBootstrapCommands1.cxx @@ -0,0 +1,91 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 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. +============================================================================*/ +// This file is used to compile all the commands +// that CMake knows about at compile time. +// This is sort of a boot strapping approach since you would +// like to have CMake to build CMake. +#include "cmCommands.h" +#include "cmAddCustomCommandCommand.cxx" +#include "cmAddCustomTargetCommand.cxx" +#include "cmAddDefinitionsCommand.cxx" +#include "cmAddDependenciesCommand.cxx" +#include "cmAddExecutableCommand.cxx" +#include "cmAddLibraryCommand.cxx" +#include "cmAddSubDirectoryCommand.cxx" +#include "cmAddTestCommand.cxx" +#include "cmBreakCommand.cxx" +#include "cmBuildCommand.cxx" +#include "cmCMakeMinimumRequired.cxx" +#include "cmCMakePolicyCommand.cxx" +#include "cmCommandArgumentsHelper.cxx" +#include "cmConfigureFileCommand.cxx" +#include "cmCoreTryCompile.cxx" +#include "cmCreateTestSourceList.cxx" +#include "cmDefinePropertyCommand.cxx" +#include "cmElseCommand.cxx" +#include "cmEnableLanguageCommand.cxx" +#include "cmEnableTestingCommand.cxx" +#include "cmEndForEachCommand.cxx" +#include "cmEndFunctionCommand.cxx" +#include "cmEndIfCommand.cxx" +#include "cmEndMacroCommand.cxx" +#include "cmEndWhileCommand.cxx" +#include "cmExecProgramCommand.cxx" +#include "cmExecuteProcessCommand.cxx" +#include "cmExternalMakefileProjectGenerator.cxx" +#include "cmFindBase.cxx" +#include "cmFindCommon.cxx" +#include "cmFileCommand.cxx" +#include "cmFindFileCommand.cxx" +#include "cmFindLibraryCommand.cxx" +#include "cmFindPackageCommand.cxx" +#include "cmFindPathCommand.cxx" +#include "cmFindProgramCommand.cxx" +#include "cmForEachCommand.cxx" +#include "cmFunctionCommand.cxx" + +void GetBootstrapCommands1(std::list<cmCommand*>& commands) +{ + commands.push_back(new cmAddCustomCommandCommand); + commands.push_back(new cmAddCustomTargetCommand); + commands.push_back(new cmAddDefinitionsCommand); + commands.push_back(new cmAddDependenciesCommand); + commands.push_back(new cmAddExecutableCommand); + commands.push_back(new cmAddLibraryCommand); + commands.push_back(new cmAddSubDirectoryCommand); + commands.push_back(new cmAddTestCommand); + commands.push_back(new cmBreakCommand); + commands.push_back(new cmBuildCommand); + commands.push_back(new cmCMakeMinimumRequired); + commands.push_back(new cmCMakePolicyCommand); + commands.push_back(new cmConfigureFileCommand); + commands.push_back(new cmCreateTestSourceList); + commands.push_back(new cmDefinePropertyCommand); + commands.push_back(new cmElseCommand); + commands.push_back(new cmEnableLanguageCommand); + commands.push_back(new cmEnableTestingCommand); + commands.push_back(new cmEndForEachCommand); + commands.push_back(new cmEndFunctionCommand); + commands.push_back(new cmEndIfCommand); + commands.push_back(new cmEndMacroCommand); + commands.push_back(new cmEndWhileCommand); + commands.push_back(new cmExecProgramCommand); + commands.push_back(new cmExecuteProcessCommand); + commands.push_back(new cmFileCommand); + commands.push_back(new cmFindFileCommand); + commands.push_back(new cmFindLibraryCommand); + commands.push_back(new cmFindPackageCommand); + commands.push_back(new cmFindPathCommand); + commands.push_back(new cmFindProgramCommand); + commands.push_back(new cmForEachCommand); + commands.push_back(new cmFunctionCommand); +} diff --git a/Source/cmBootstrapCommands.cxx b/Source/cmBootstrapCommands2.cxx index e3a2ad4e52..be72526bab 100644 --- a/Source/cmBootstrapCommands.cxx +++ b/Source/cmBootstrapCommands2.cxx @@ -14,44 +14,7 @@ // This is sort of a boot strapping approach since you would // like to have CMake to build CMake. #include "cmCommands.h" -#include "cmAddCustomCommandCommand.cxx" -#include "cmAddCustomTargetCommand.cxx" -#include "cmAddDefinitionsCommand.cxx" -#include "cmAddDependenciesCommand.cxx" -#include "cmAddExecutableCommand.cxx" -#include "cmAddLibraryCommand.cxx" -#include "cmAddSubDirectoryCommand.cxx" -#include "cmAddTestCommand.cxx" -#include "cmBreakCommand.cxx" -#include "cmBuildCommand.cxx" -#include "cmCMakeMinimumRequired.cxx" -#include "cmCMakePolicyCommand.cxx" -#include "cmCommandArgumentsHelper.cxx" -#include "cmConfigureFileCommand.cxx" -#include "cmCoreTryCompile.cxx" -#include "cmCreateTestSourceList.cxx" -#include "cmDefinePropertyCommand.cxx" -#include "cmElseCommand.cxx" -#include "cmEnableLanguageCommand.cxx" -#include "cmEnableTestingCommand.cxx" -#include "cmEndForEachCommand.cxx" -#include "cmEndFunctionCommand.cxx" -#include "cmEndIfCommand.cxx" -#include "cmEndMacroCommand.cxx" -#include "cmEndWhileCommand.cxx" -#include "cmExecProgramCommand.cxx" -#include "cmExecuteProcessCommand.cxx" -#include "cmExternalMakefileProjectGenerator.cxx" -#include "cmFindBase.cxx" -#include "cmFindCommon.cxx" -#include "cmFileCommand.cxx" -#include "cmFindFileCommand.cxx" -#include "cmFindLibraryCommand.cxx" -#include "cmFindPackageCommand.cxx" -#include "cmFindPathCommand.cxx" -#include "cmFindProgramCommand.cxx" -#include "cmForEachCommand.cxx" -#include "cmFunctionCommand.cxx" +#include "cmGeneratorExpressionEvaluationFile.cxx" #include "cmGetCMakePropertyCommand.cxx" #include "cmGetDirectoryPropertyCommand.cxx" #include "cmGetFilenameComponentCommand.cxx" @@ -95,41 +58,8 @@ #include "cmUnsetCommand.cxx" #include "cmWhileCommand.cxx" -void GetBootstrapCommands(std::list<cmCommand*>& commands) +void GetBootstrapCommands2(std::list<cmCommand*>& commands) { - commands.push_back(new cmAddCustomCommandCommand); - commands.push_back(new cmAddCustomTargetCommand); - commands.push_back(new cmAddDefinitionsCommand); - commands.push_back(new cmAddDependenciesCommand); - commands.push_back(new cmAddExecutableCommand); - commands.push_back(new cmAddLibraryCommand); - commands.push_back(new cmAddSubDirectoryCommand); - commands.push_back(new cmAddTestCommand); - commands.push_back(new cmBreakCommand); - commands.push_back(new cmBuildCommand); - commands.push_back(new cmCMakeMinimumRequired); - commands.push_back(new cmCMakePolicyCommand); - commands.push_back(new cmConfigureFileCommand); - commands.push_back(new cmCreateTestSourceList); - commands.push_back(new cmDefinePropertyCommand); - commands.push_back(new cmElseCommand); - commands.push_back(new cmEnableLanguageCommand); - commands.push_back(new cmEnableTestingCommand); - commands.push_back(new cmEndForEachCommand); - commands.push_back(new cmEndFunctionCommand); - commands.push_back(new cmEndIfCommand); - commands.push_back(new cmEndMacroCommand); - commands.push_back(new cmEndWhileCommand); - commands.push_back(new cmExecProgramCommand); - commands.push_back(new cmExecuteProcessCommand); - commands.push_back(new cmFileCommand); - commands.push_back(new cmFindFileCommand); - commands.push_back(new cmFindLibraryCommand); - commands.push_back(new cmFindPackageCommand); - commands.push_back(new cmFindPathCommand); - commands.push_back(new cmFindProgramCommand); - commands.push_back(new cmForEachCommand); - commands.push_back(new cmFunctionCommand); commands.push_back(new cmGetCMakePropertyCommand); commands.push_back(new cmGetDirectoryPropertyCommand); commands.push_back(new cmGetFilenameComponentCommand); diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx index 91d55a5a28..b6e2569a5a 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/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx new file mode 100644 index 0000000000..62f238369e --- /dev/null +++ b/Source/cmCMakeHostSystemInformationCommand.cxx @@ -0,0 +1,126 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 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 "cmCMakeHostSystemInformationCommand.h" + +#include <cmsys/ios/sstream> + +// cmCMakeHostSystemInformation +bool cmCMakeHostSystemInformationCommand +::InitialPass(std::vector<std::string> const &args, cmExecutionStatus &) +{ + size_t current_index = 0; + + if(args.size() < (current_index + 2) || args[current_index] != "RESULT") + { + this->SetError("missing RESULT specification."); + return false; + } + + std::string variable = args[current_index + 1]; + current_index += 2; + + if(args.size() < (current_index + 2) || args[current_index] != "QUERY") + { + this->SetError("missing QUERY specification"); + return false; + } + + cmsys::SystemInformation info; + info.RunCPUCheck(); + info.RunOSCheck(); + info.RunMemoryCheck(); + + std::string result_list; + for(size_t i = current_index + 1; i < args.size(); ++i) + { + std::string key = args[i]; + if(i != current_index + 1) + { + result_list += ";"; + } + std::string value; + if(!this->GetValue(info, key, value)) return false; + + result_list += value; + } + + this->Makefile->AddDefinition(variable.c_str(), result_list.c_str()); + + return true; +} + +bool cmCMakeHostSystemInformationCommand +::GetValue(cmsys::SystemInformation &info, + std::string const& key, std::string &value) +{ + if(key == "NUMBER_OF_LOGICAL_CORES") + { + value = this->ValueToString(info.GetNumberOfLogicalCPU()); + } + else if(key == "NUMBER_OF_PHYSICAL_CORES") + { + value = this->ValueToString(info.GetNumberOfPhysicalCPU()); + } + else if(key == "HOSTNAME") + { + value = this->ValueToString(info.GetHostname()); + } + else if(key == "FQDN") + { + value = this->ValueToString(info.GetFullyQualifiedDomainName()); + } + else if(key == "TOTAL_VIRTUAL_MEMORY") + { + value = this->ValueToString(info.GetTotalVirtualMemory()); + } + else if(key == "AVAILABLE_VIRTUAL_MEMORY") + { + value = this->ValueToString(info.GetAvailableVirtualMemory()); + } + else if(key == "TOTAL_PHYSICAL_MEMORY") + { + value = this->ValueToString(info.GetTotalPhysicalMemory()); + } + else if(key == "AVAILABLE_PHYSICAL_MEMORY") + { + value = this->ValueToString(info.GetAvailablePhysicalMemory()); + } + else + { + std::string e = "does not recognize <key> " + key; + this->SetError(e.c_str()); + return false; + } + + return true; +} + +std::string cmCMakeHostSystemInformationCommand +::ValueToString(size_t value) const +{ + cmsys_ios::stringstream tmp; + tmp << value; + return tmp.str(); +} + +std::string cmCMakeHostSystemInformationCommand +::ValueToString(const char *value) const +{ + std::string safe_string = value ? value : ""; + return safe_string; +} + +std::string cmCMakeHostSystemInformationCommand +::ValueToString(std::string const& value) const +{ + return value; +} diff --git a/Source/cmCMakeHostSystemInformationCommand.h b/Source/cmCMakeHostSystemInformationCommand.h new file mode 100644 index 0000000000..d1b8700ffb --- /dev/null +++ b/Source/cmCMakeHostSystemInformationCommand.h @@ -0,0 +1,102 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 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 cmCMakeHostSystemInformationCommand_h +#define cmCMakeHostSystemInformationCommand_h + +#include "cmCommand.h" + +#include <cmsys/SystemInformation.hxx> + +/** \class cmCMakeHostSystemInformationCommand + * \brief Query host system specific information + * + * cmCMakeHostSystemInformationCommand queries system information of + * the sytem on which CMake runs. + */ +class cmCMakeHostSystemInformationCommand : public cmCommand +{ +public: + /** + * This is a virtual constructor for the command. + */ + virtual cmCommand* Clone() + { + return new cmCMakeHostSystemInformationCommand; + } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + virtual bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus &status); + + /** + * This determines if the command is invoked when in script mode. + */ + virtual bool IsScriptable() const { return true; } + + /** + * The name of the command as specified in CMakeList.txt. + */ + virtual const char* GetName() const + { + return "cmake_host_system_information"; + } + + /** + * Succinct documentation. + */ + virtual const char* GetTerseDocumentation() const + { + return "Query host system specific information."; + } + + /** + * More documentation. + */ + virtual const char* GetFullDocumentation() const + { + return + " cmake_host_system_information(RESULT <variable> QUERY <key> ...)\n" + "Queries system information of the host system on which cmake runs. " + "One or more <key> can be provided to " + "select the information to be queried. " + "The list of queried values is stored in <variable>.\n" + "<key> can be one of the following values:\n" + " NUMBER_OF_LOGICAL_CORES = Number of logical cores.\n" + " NUMBER_OF_PHYSICAL_CORES = Number of physical cores.\n" + " HOSTNAME = Hostname.\n" + " FQDN = Fully qualified domain name.\n" + " TOTAL_VIRTUAL_MEMORY = " + "Total virtual memory in megabytes.\n" + " AVAILABLE_VIRTUAL_MEMORY = " + "Available virtual memory in megabytes.\n" + " TOTAL_PHYSICAL_MEMORY = " + "Total physical memory in megabytes.\n" + " AVAILABLE_PHYSICAL_MEMORY = " + "Available physical memory in megabytes.\n" + ; + } + + cmTypeMacro(cmCMakeHostSystemInformationCommand, cmCommand); + +private: + bool GetValue(cmsys::SystemInformation &info, + std::string const& key, std::string &value); + + std::string ValueToString(size_t value) const; + std::string ValueToString(const char *value) const; + std::string ValueToString(std::string const& value) const; +}; + +#endif diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 322a6a26f1..69ffb97ffe 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 587a6db51a..5dd35ce418 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 3d5b24b84e..ed09545cb6 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"; @@ -750,6 +750,10 @@ void cmCacheManager::AddCacheEntry(const char* key, } e.SetProperty("HELPSTRING", helpString? helpString : "(This variable does not exist and should not be used)"); + if (this->Cache[key].Value == e.Value) + { + this->CMakeInstance->UnwatchUnusedCli(key); + } this->Cache[key] = e; } diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h index 4a5ee450fb..a5e5eeeff0 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/cmCommands.cxx b/Source/cmCommands.cxx index 227b226787..1e2a85cfb1 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -11,8 +11,10 @@ ============================================================================*/ #include "cmCommands.h" #if defined(CMAKE_BUILD_WITH_CMAKE) +#include "cmAddCompileOptionsCommand.cxx" #include "cmAuxSourceDirectoryCommand.cxx" #include "cmBuildNameCommand.cxx" +#include "cmCMakeHostSystemInformationCommand.cxx" #include "cmElseIfCommand.cxx" #include "cmExportCommand.cxx" #include "cmExportLibraryDependencies.cxx" @@ -29,6 +31,7 @@ #include "cmSourceGroupCommand.cxx" #include "cmSubdirDependsCommand.cxx" #include "cmTargetCompileDefinitionsCommand.cxx" +#include "cmTargetCompileOptionsCommand.cxx" #include "cmTargetIncludeDirectoriesCommand.cxx" #include "cmTargetPropCommandBase.cxx" #include "cmUseMangledMesaCommand.cxx" @@ -51,8 +54,10 @@ void GetPredefinedCommands(std::list<cmCommand*>& ) { #if defined(CMAKE_BUILD_WITH_CMAKE) + commands.push_back(new cmAddCompileOptionsCommand); commands.push_back(new cmAuxSourceDirectoryCommand); commands.push_back(new cmBuildNameCommand); + commands.push_back(new cmCMakeHostSystemInformationCommand); commands.push_back(new cmElseIfCommand); commands.push_back(new cmExportCommand); commands.push_back(new cmExportLibraryDependenciesCommand); @@ -71,6 +76,7 @@ void GetPredefinedCommands(std::list<cmCommand*>& commands.push_back(new cmSubdirDependsCommand); commands.push_back(new cmTargetIncludeDirectoriesCommand); commands.push_back(new cmTargetCompileDefinitionsCommand); + commands.push_back(new cmTargetCompileOptionsCommand); commands.push_back(new cmUseMangledMesaCommand); commands.push_back(new cmUtilitySourceCommand); commands.push_back(new cmVariableRequiresCommand); diff --git a/Source/cmCommands.h b/Source/cmCommands.h index 096fc2006c..c56673fed5 100644 --- a/Source/cmCommands.h +++ b/Source/cmCommands.h @@ -16,12 +16,13 @@ class cmCommand; /** * Global function to return all compiled in commands. - * To add a new command edit cmCommands.cxx or cmBootstrapCommands.cxx + * To add a new command edit cmCommands.cxx or cmBootstrapCommands[12].cxx * and add your command. * It is up to the caller to delete the commands created by this * call. */ -void GetBootstrapCommands(std::list<cmCommand*>& commands); +void GetBootstrapCommands1(std::list<cmCommand*>& commands); +void GetBootstrapCommands2(std::list<cmCommand*>& commands); void GetPredefinedCommands(std::list<cmCommand*>& commands); diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 896b50aa5a..0ba01390d0 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -499,7 +499,7 @@ bool cmComputeLinkInformation::Compute() if(!this->LinkLanguage) { cmSystemTools:: - Error("CMake can not determine linker language for target:", + Error("CMake can not determine linker language for target: ", this->Target->GetName()); return false; } @@ -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; @@ -1724,6 +1730,17 @@ void cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath, cmTarget* target) { + // Ignore targets on Apple where install_name is not @rpath. + // The dependenty library can be found with other means such as + // @loader_path or full paths. + if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) + { + if(!target->HasMacOSXRpath(this->Config)) + { + return; + } + } + // Libraries with unknown type must be handled using just the file // on disk. if(target->GetType() == cmTarget::UNKNOWN_LIBRARY) @@ -1756,25 +1773,60 @@ void cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath) { // Get the name of the library from the file name. + bool is_shared_library = false; std::string file = cmSystemTools::GetFilenameName(fullPath); - if(!this->ExtractSharedLibraryName.find(file.c_str())) + + if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) + { + // Check that @rpath is part of the install name. + // If it isn't, return. + std::string soname; + if(!cmSystemTools::GuessLibraryInstallName(fullPath, soname)) + { + return; + } + + if(soname.find("@rpath") == std::string::npos) + { + return; + } + } + + is_shared_library = this->ExtractSharedLibraryName.find(file.c_str()); + + if(!is_shared_library) { // On some platforms (AIX) a shared library may look static. if(this->ArchivesMayBeShared) { - if(!this->ExtractStaticLibraryName.find(file.c_str())) + if(this->ExtractStaticLibraryName.find(file.c_str())) { - // This is not the name of a shared library or archive. - return; + // This is the name of a shared library or archive. + is_shared_library = true; } } - else + } + + // It could be an Apple framework + if(!is_shared_library) + { + if(fullPath.find(".framework") != std::string::npos) { - // This is not the name of a shared library. - return; + cmsys::RegularExpression splitFramework; + splitFramework.compile("^(.*)/(.*).framework/.*/(.*)$"); + if(splitFramework.find(fullPath) && + (splitFramework.match(2) == splitFramework.match(3))) + { + is_shared_library = true; + } } } + if(!is_shared_library) + { + return; + } + // Include this library in the runtime path ordering. this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath); if(this->LinkWithRuntimePath) @@ -1832,6 +1884,8 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, } if(use_build_rpath || use_link_rpath) { + std::string rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT"); + cmSystemTools::ConvertToUnixSlashes(rootPath); std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath(); for(std::vector<std::string>::const_iterator ri = rdirs.begin(); ri != rdirs.end(); ++ri) @@ -1855,9 +1909,14 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, !cmSystemTools::IsSubDirectory(ri->c_str(), topSourceDir) && !cmSystemTools::IsSubDirectory(ri->c_str(), topBinaryDir)) { - if(emitted.insert(*ri).second) + std::string d = *ri; + if (d.find(rootPath) == 0) + { + d = d.substr(rootPath.size()); + } + if(emitted.insert(d).second) { - runtimeDirs.push_back(*ri); + runtimeDirs.push_back(d); } } } diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 1a76922a55..e6ee871858 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 9f38b2529b..860417fc96 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -23,150 +23,144 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) this->BinaryDirectory = argv[1].c_str(); this->OutputFile = ""; // which signature were we called with ? - this->SrcFileSignature = false; - unsigned int i; + this->SrcFileSignature = true; const char* sourceDirectory = argv[2].c_str(); const char* projectName = 0; const char* targetName = 0; - char targetNameBuf[64]; - int extraArgs = 0; - - // look for CMAKE_FLAGS and store them std::vector<std::string> cmakeFlags; - for (i = 3; i < argv.size(); ++i) - { - if (argv[i] == "CMAKE_FLAGS") - { - // CMAKE_FLAGS is the first argument because we need an argv[0] that - // is not used, so it matches regular command line parsing which has - // the program name as arg 0 - for (; i < argv.size() && argv[i] != "COMPILE_DEFINITIONS" && - argv[i] != "OUTPUT_VARIABLE" && - argv[i] != "LINK_LIBRARIES"; - ++i) - { - extraArgs++; - cmakeFlags.push_back(argv[i]); - } - break; - } - } - - // look for OUTPUT_VARIABLE and store them + std::vector<std::string> compileDefs; std::string outputVariable; - for (i = 3; i < argv.size(); ++i) + std::string copyFile; + std::vector<cmTarget*> targets; + std::string libsToLink = " "; + bool useOldLinkLibs = true; + char targetNameBuf[64]; + bool didOutputVariable = false; + bool didCopyFile = false; + bool useSources = argv[2] == "SOURCES"; + std::vector<std::string> sources; + + enum Doing { DoingNone, DoingCMakeFlags, DoingCompileDefinitions, + DoingLinkLibraries, DoingOutputVariable, DoingCopyFile, + DoingSources }; + Doing doing = useSources? DoingSources : DoingNone; + for(size_t i=3; i < argv.size(); ++i) { - if (argv[i] == "OUTPUT_VARIABLE") + if(argv[i] == "CMAKE_FLAGS") { - if ( argv.size() <= (i+1) ) - { - this->Makefile->IssueMessage(cmake::FATAL_ERROR, - "OUTPUT_VARIABLE specified but there is no variable"); - return -1; - } - extraArgs += 2; - outputVariable = argv[i+1]; - break; + doing = DoingCMakeFlags; + // CMAKE_FLAGS is the first argument because we need an argv[0] that + // is not used, so it matches regular command line parsing which has + // the program name as arg 0 + cmakeFlags.push_back(argv[i]); } - } - - // look for COMPILE_DEFINITIONS and store them - std::vector<std::string> compileFlags; - for (i = 3; i < argv.size(); ++i) - { - if (argv[i] == "COMPILE_DEFINITIONS") + else if(argv[i] == "COMPILE_DEFINITIONS") { - extraArgs++; - for (i = i + 1; i < argv.size() && argv[i] != "CMAKE_FLAGS" && - argv[i] != "OUTPUT_VARIABLE" && - argv[i] != "LINK_LIBRARIES"; - ++i) - { - extraArgs++; - compileFlags.push_back(argv[i]); - } - break; + doing = DoingCompileDefinitions; } - } - - std::vector<cmTarget*> targets; - std::string libsToLink = " "; - bool useOldLinkLibs = true; - for (i = 3; i < argv.size(); ++i) - { - if (argv[i] == "LINK_LIBRARIES") + else if(argv[i] == "LINK_LIBRARIES") { - if ( argv.size() <= (i+1) ) - { - this->Makefile->IssueMessage(cmake::FATAL_ERROR, - "LINK_LIBRARIES specified but there is no content"); - return -1; - } - extraArgs++; - ++i; + doing = DoingLinkLibraries; useOldLinkLibs = false; - for ( ; i < argv.size() && argv[i] != "CMAKE_FLAGS" - && argv[i] != "COMPILE_DEFINITIONS" && argv[i] != "OUTPUT_VARIABLE"; - ++i) + } + else if(argv[i] == "OUTPUT_VARIABLE") + { + doing = DoingOutputVariable; + didOutputVariable = true; + } + else if(argv[i] == "COPY_FILE") + { + doing = DoingCopyFile; + didCopyFile = true; + } + else if(doing == DoingCMakeFlags) + { + cmakeFlags.push_back(argv[i]); + } + else if(doing == DoingCompileDefinitions) + { + compileDefs.push_back(argv[i]); + } + else if(doing == DoingLinkLibraries) + { + libsToLink += "\"" + cmSystemTools::TrimWhitespace(argv[i]) + "\" "; + if(cmTarget *tgt = this->Makefile->FindTargetToUse(argv[i].c_str())) { - extraArgs++; - libsToLink += argv[i] + " "; - cmTarget *tgt = this->Makefile->FindTargetToUse(argv[i].c_str()); - if (!tgt) - { - continue; - } switch(tgt->GetType()) - { - case cmTarget::SHARED_LIBRARY: - case cmTarget::STATIC_LIBRARY: - case cmTarget::UNKNOWN_LIBRARY: - break; - case cmTarget::EXECUTABLE: - if (tgt->IsExecutableWithExports()) - { + { + case cmTarget::SHARED_LIBRARY: + case cmTarget::STATIC_LIBRARY: + case cmTarget::UNKNOWN_LIBRARY: break; - } - default: - this->Makefile->IssueMessage(cmake::FATAL_ERROR, - "Only libraries may be used as try_compile IMPORTED " - "LINK_LIBRARIES. Got " + std::string(tgt->GetName()) + " of " - "type " + tgt->GetTargetTypeName(tgt->GetType()) + "."); - return -1; - } - if (!tgt->IsImported()) + case cmTarget::EXECUTABLE: + if (tgt->IsExecutableWithExports()) + { + break; + } + default: + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "Only libraries may be used as try_compile IMPORTED " + "LINK_LIBRARIES. Got " + std::string(tgt->GetName()) + " of " + "type " + tgt->GetTargetTypeName(tgt->GetType()) + "."); + return -1; + } + if (tgt->IsImported()) { - continue; + targets.push_back(tgt); } - targets.push_back(tgt); } - break; + } + else if(doing == DoingOutputVariable) + { + outputVariable = argv[i].c_str(); + doing = DoingNone; + } + else if(doing == DoingCopyFile) + { + copyFile = argv[i].c_str(); + doing = DoingNone; + } + else if(doing == DoingSources) + { + sources.push_back(argv[i]); + } + else if(i == 3) + { + this->SrcFileSignature = false; + projectName = argv[i].c_str(); + } + else if(i == 4 && !this->SrcFileSignature) + { + targetName = argv[i].c_str(); + } + else + { + cmOStringStream m; + m << "try_compile given unknown argument \"" << argv[i] << "\"."; + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str()); } } - // look for COPY_FILE - std::string copyFile; - for (i = 3; i < argv.size(); ++i) + if(didCopyFile && copyFile.empty()) { - if (argv[i] == "COPY_FILE") - { - if ( argv.size() <= (i+1) ) - { - this->Makefile->IssueMessage(cmake::FATAL_ERROR, - "COPY_FILE specified but there is no variable"); - return -1; - } - extraArgs += 2; - copyFile = argv[i+1]; - break; - } + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "COPY_FILE must be followed by a file path"); + return -1; } - // do we have a srcfile signature - if (argv.size() - extraArgs == 3) + if(didOutputVariable && outputVariable.empty()) { - this->SrcFileSignature = true; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "OUTPUT_VARIABLE must be followed by a variable name"); + return -1; + } + + if(useSources && sources.empty()) + { + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "SOURCES must be followed by at least one source file"); + return -1; } // compute the binary dir when TRY_COMPILE is called with a src file @@ -179,10 +173,10 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) else { // only valid for srcfile signatures - if (compileFlags.size()) + if (compileDefs.size()) { this->Makefile->IssueMessage(cmake::FATAL_ERROR, - "COMPILE_FLAGS specified on a srcdir type TRY_COMPILE"); + "COMPILE_DEFINITIONS specified on a srcdir type TRY_COMPILE"); return -1; } if (copyFile.size()) @@ -213,6 +207,44 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) std::string ccFile = this->BinaryDirectory + "/CMakeCache.txt"; cmSystemTools::RemoveFile(ccFile.c_str()); + // Choose sources. + if(!useSources) + { + sources.push_back(argv[2]); + } + + // Detect languages to enable. + cmGlobalGenerator* gg = + this->Makefile->GetCMakeInstance()->GetGlobalGenerator(); + std::set<std::string> testLangs; + for(std::vector<std::string>::iterator si = sources.begin(); + si != sources.end(); ++si) + { + std::string ext = cmSystemTools::GetFilenameLastExtension(*si); + if(const char* lang = gg->GetLanguageFromExtension(ext.c_str())) + { + testLangs.insert(lang); + } + else + { + cmOStringStream err; + err << "Unknown extension \"" << ext << "\" for file\n" + << " " << *si << "\n" + << "try_compile() works only for enabled languages. " + << "Currently these are:\n "; + std::vector<std::string> langs; + gg->GetEnabledLanguages(langs); + for(std::vector<std::string>::iterator l = langs.begin(); + l != langs.end(); ++l) + { + err << " " << *l; + } + err << "\nSee project() command to enable other languages."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, err.str()); + return -1; + } + } + // we need to create a directory and CMakeLists file etc... // first create the directories sourceDirectory = this->BinaryDirectory.c_str(); @@ -229,10 +261,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) return -1; } - std::string source = argv[2]; - std::string ext = cmSystemTools::GetFilenameLastExtension(source); - const char* lang =(this->Makefile->GetCMakeInstance()->GetGlobalGenerator() - ->GetLanguageFromExtension(ext.c_str())); const char* def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH"); fprintf(fout, "cmake_minimum_required(VERSION %u.%u.%u.%u)\n", cmVersion::GetMajorVersion(), cmVersion::GetMinorVersion(), @@ -242,67 +270,49 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) fprintf(fout, "SET(CMAKE_MODULE_PATH %s)\n", def); } - const char* rulesOverrideBase = "CMAKE_USER_MAKE_RULES_OVERRIDE"; - std::string rulesOverrideLang = - rulesOverrideBase + (lang ? std::string("_") + lang : std::string("")); - if(const char* rulesOverridePath = - this->Makefile->GetDefinition(rulesOverrideLang.c_str())) - { - fprintf(fout, "SET(%s \"%s\")\n", - rulesOverrideLang.c_str(), rulesOverridePath); - } - else if(const char* rulesOverridePath2 = - this->Makefile->GetDefinition(rulesOverrideBase)) - { - fprintf(fout, "SET(%s \"%s\")\n", - rulesOverrideBase, rulesOverridePath2); - } - - if(lang) + std::string projectLangs; + for(std::set<std::string>::iterator li = testLangs.begin(); + li != testLangs.end(); ++li) { - fprintf(fout, "PROJECT(CMAKE_TRY_COMPILE %s)\n", lang); - } - else - { - fclose(fout); - cmOStringStream err; - err << "Unknown extension \"" << ext << "\" for file\n" - << " " << source << "\n" - << "try_compile() works only for enabled languages. " - << "Currently these are:\n "; - std::vector<std::string> langs; - this->Makefile->GetCMakeInstance()->GetGlobalGenerator()-> - GetEnabledLanguages(langs); - for(std::vector<std::string>::iterator l = langs.begin(); - l != langs.end(); ++l) + projectLangs += " " + *li; + std::string rulesOverrideBase = "CMAKE_USER_MAKE_RULES_OVERRIDE"; + std::string rulesOverrideLang = rulesOverrideBase + "_" + *li; + if(const char* rulesOverridePath = + this->Makefile->GetDefinition(rulesOverrideLang.c_str())) { - err << " " << *l; + fprintf(fout, "SET(%s \"%s\")\n", + rulesOverrideLang.c_str(), rulesOverridePath); + } + else if(const char* rulesOverridePath2 = + this->Makefile->GetDefinition(rulesOverrideBase.c_str())) + { + fprintf(fout, "SET(%s \"%s\")\n", + rulesOverrideBase.c_str(), rulesOverridePath2); } - err << "\nSee project() command to enable other languages."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, err.str()); - return -1; } - std::string langFlags = "CMAKE_"; - langFlags += lang; - langFlags += "_FLAGS"; + fprintf(fout, "PROJECT(CMAKE_TRY_COMPILE%s)\n", projectLangs.c_str()); fprintf(fout, "SET(CMAKE_VERBOSE_MAKEFILE 1)\n"); - fprintf(fout, "SET(CMAKE_%s_FLAGS \"", lang); - const char* flags = this->Makefile->GetDefinition(langFlags.c_str()); - if(flags) + for(std::set<std::string>::iterator li = testLangs.begin(); + li != testLangs.end(); ++li) { - fprintf(fout, " %s ", flags); + fprintf(fout, "SET(CMAKE_%s_FLAGS \"", li->c_str()); + std::string langFlags = "CMAKE_" + *li + "_FLAGS"; + if(const char* flags = this->Makefile->GetDefinition(langFlags.c_str())) + { + fprintf(fout, " %s ", flags); + } + fprintf(fout, " ${COMPILE_DEFINITIONS}\")\n"); } - fprintf(fout, " ${COMPILE_DEFINITIONS}\")\n"); fprintf(fout, "INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES})\n"); fprintf(fout, "SET(CMAKE_SUPPRESS_REGENERATION 1)\n"); fprintf(fout, "LINK_DIRECTORIES(${LINK_DIRECTORIES})\n"); // handle any compile flags we need to pass on - if (compileFlags.size()) + if (compileDefs.size()) { fprintf(fout, "ADD_DEFINITIONS( "); - for (i = 0; i < compileFlags.size(); ++i) + for (size_t i = 0; i < compileDefs.size(); ++i) { - fprintf(fout,"%s ",compileFlags[i].c_str()); + fprintf(fout,"%s ",compileDefs[i].c_str()); } fprintf(fout, ")\n"); } @@ -377,7 +387,19 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) fprintf(fout, "SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n", this->BinaryDirectory.c_str()); /* Create the actual executable. */ - fprintf(fout, "ADD_EXECUTABLE(%s \"%s\")\n", targetName, source.c_str()); + fprintf(fout, "ADD_EXECUTABLE(%s", targetName); + for(std::vector<std::string>::iterator si = sources.begin(); + si != sources.end(); ++si) + { + fprintf(fout, " \"%s\"", si->c_str()); + + // Add dependencies on any non-temporary sources. + if(si->find("CMakeTmp") == si->npos) + { + this->Makefile->AddCMakeDependFile(*si); + } + } + fprintf(fout, ")\n"); if (useOldLinkLibs) { fprintf(fout, @@ -391,22 +413,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) } fclose(fout); projectName = "CMAKE_TRY_COMPILE"; - // if the source is not in CMakeTmp - if(source.find("CMakeTmp") == source.npos) - { - this->Makefile->AddCMakeDependFile(source.c_str()); - } - - } - // else the srcdir bindir project target signature - else - { - projectName = argv[3].c_str(); - - if (argv.size() - extraArgs == 5) - { - targetName = argv[4].c_str(); - } } bool erroroc = cmSystemTools::GetErrorOccuredFlag(); diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index a1505bd658..a4f6ac4b47 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -54,8 +54,8 @@ std::string cmCryptoHash::HashFile(const char* file) this->Initialize(); // Should be efficient enough on most system: - const int bufferSize = 4096; - char buffer[bufferSize]; + cm_sha2_uint64_t buffer[512]; + char* buffer_c = reinterpret_cast<char*>(buffer); unsigned char const* buffer_uc = reinterpret_cast<unsigned char const*>(buffer); // This copy loop is very sensitive on certain platforms with @@ -65,7 +65,7 @@ std::string cmCryptoHash::HashFile(const char* file) // error occurred. Therefore, the loop should be safe everywhere. while(fin) { - fin.read(buffer, bufferSize); + fin.read(buffer_c, sizeof(buffer)); if(int gcount = static_cast<int>(fin.gcount())) { this->Append(buffer_uc, gcount); diff --git a/Source/cmDocumentCompileDefinitions.h b/Source/cmDocumentCompileDefinitions.h index ef3b3e7155..d15bd6dcad 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 6cc3f25aea..7358a36506 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 " \ @@ -38,6 +40,20 @@ "is exported using export(), or when the target is used by another " \ "target in the same buildsystem. Expands to the empty string " \ "otherwise.\n" \ + " $<C_COMPILER_ID> = The CMake-id of the C compiler " \ + "used.\n" \ + " $<C_COMPILER_ID:comp> = '1' if the CMake-id of the C " \ + "compiler matches comp, otherwise '0'.\n" \ + " $<CXX_COMPILER_ID> = The CMake-id of the CXX compiler " \ + "used.\n" \ + " $<CXX_COMPILER_ID:comp> = '1' if the CMake-id of the CXX " \ + "compiler matches comp, otherwise '0'.\n" \ + " $<VERSION_GREATER:v1,v2> = '1' if v1 is a version greater than " \ + "v2, else '0'.\n" \ + " $<VERSION_LESS:v1,v2> = '1' if v1 is a version less than v2, " \ + "else '0'.\n" \ + " $<VERSION_EQUAL:v1,v2> = '1' if v1 is the same version as v2, " \ + "else '0'.\n" \ " $<TARGET_FILE:tgt> = main file (.exe, .so.1.2, .a)\n" \ " $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n" \ " $<TARGET_SONAME_FILE:tgt> = file with soname (.so.3)\n" \ @@ -72,4 +88,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 61f9f5a25e..0a78ccffb2 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>." @@ -344,11 +345,12 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_PARENT_LIST_FILE", cmProperty::VARIABLE, - "Full path to the parent listfile of the one currently being processed.", - "As CMake processes the listfiles in your project this " - "variable will always be set to the listfile that included " - "or somehow invoked the one currently being " - "processed. See also CMAKE_CURRENT_LIST_FILE.",false, + "Full path to the CMake file that included the current one.", + "While processing a CMake file loaded by include() or find_package() " + "this variable contains the full path to the file including it. " + "The top of the include stack is always the CMakeLists.txt for the " + "current directory. " + "See also CMAKE_CURRENT_LIST_FILE.",false, "Variables that Provide Information"); cm->DefineProperty @@ -452,8 +454,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 +470,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 +485,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 +500,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"); @@ -556,6 +561,16 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "Variables That Change Behavior"); cm->DefineProperty + ("CMAKE_SYSROOT", cmProperty::VARIABLE, + "Path to pass to the compiler in the --sysroot flag.", + "The CMAKE_SYSROOT content is passed to the compiler in the --sysroot " + "flag, if supported. The path is also stripped from the RPATH if " + "necessary on installation. The CMAKE_SYSROOT is also used to prefix " + "paths searched by the find_* commands.", + false, + "Variables That Change Behavior"); + + cm->DefineProperty ("CMAKE_FIND_LIBRARY_PREFIXES", cmProperty::VARIABLE, "Prefixes to prepend when looking for libraries.", "This specifies what prefixes to add to library names when " @@ -577,26 +592,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 +642,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 +653,15 @@ 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." + "\n" + "The installation prefix is also added to CMAKE_SYSTEM_PREFIX_PATH " + "so that find_package, find_program, find_library, find_path, and " + "find_file will search the prefix for other software." ,false, "Variables That Change Behavior"); @@ -709,7 +739,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "adds /bin to each of the directories in the path, FIND_LIBRARY() " "appends /lib to each of the directories, and FIND_PATH() and " "FIND_FILE() append /include . By default this contains the standard " - "directories for the current system. It is NOT intended " + "directories for the current system and the CMAKE_INSTALL_PREFIX. " + "It is NOT intended " "to be modified by the project, use CMAKE_PREFIX_PATH for this. See also " "CMAKE_SYSTEM_INCLUDE_PATH, CMAKE_SYSTEM_LIBRARY_PATH, " "CMAKE_SYSTEM_PROGRAM_PATH, and CMAKE_SYSTEM_IGNORE_PATH.", false, @@ -792,7 +823,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 +919,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 +929,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 +940,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 +971,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 +1030,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 @@ -1111,8 +1144,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"); @@ -1126,7 +1159,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 @@ -1147,6 +1181,14 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "The value must be an integer no less than 128.",false, "Variables That Describe the System"); + cm->DefineProperty + ("ENV", cmProperty::VARIABLE, + "Access environment variables.", + "Use the syntax $ENV{VAR} to read environment variable VAR. " + "See also the set() command to set ENV{VAR}." + ,false, + "Variables That Describe the System"); + // Variables that affect the building of object files and // targets. // @@ -1199,7 +1241,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.", @@ -1253,7 +1295,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.", @@ -1359,44 +1401,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. " @@ -1592,7 +1637,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 @@ -1728,8 +1774,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 @@ -1743,7 +1790,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 debde3be9a..4edacbb1a7 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/cmELF.cxx b/Source/cmELF.cxx index 1158fc0c01..30de9a8a68 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -19,7 +19,12 @@ #include <cmsys/CPU.h> // Include the ELF format information system header. -#include <elf.h> +#if defined(__OpenBSD__) +# include <stdint.h> +# include <elf_abi.h> +#else +# include <elf.h> +#endif #if defined(__sun) # include <sys/link.h> // For dynamic section information #endif diff --git a/Source/cmEnableLanguageCommand.h b/Source/cmEnableLanguageCommand.h index ee963f9201..747448b3ee 100644 --- a/Source/cmEnableLanguageCommand.h +++ b/Source/cmEnableLanguageCommand.h @@ -59,18 +59,21 @@ public: virtual const char* GetFullDocumentation() const { return - " enable_language(languageName [OPTIONAL] )\n" + " enable_language(<lang> [OPTIONAL] )\n" "This command enables support for the named language in CMake. " "This is the same as the project command but does not create " "any of the extra variables that are created by the project command. " "Example languages are CXX, C, Fortran. " - "If OPTIONAL is used, use the CMAKE_<languageName>_COMPILER_WORKS " - "variable to check whether the language has been enabled successfully." "\n" - "This command must be called on file scope (not inside a function) and " - "the language enabled can only be used in the calling project or its " - "subdirectories added by add_subdirectory(). Also note that at present, " - "the OPTIONAL argument does not work."; + "This command must be called in file scope, not in a function call. " + "Furthermore, it must be called in the highest directory common to " + "all targets using the named language directly for compiling sources " + "or indirectly through link dependencies. " + "It is simplest to enable all needed languages in the top-level " + "directory of a project." + "\n" + "The OPTIONAL keyword is a placeholder for future implementation " + "and does not currently work."; } cmTypeMacro(cmEnableLanguageCommand, cmCommand); diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 7147f86be8..326663c32d 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) @@ -72,6 +72,9 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", te, cmGeneratorExpression::BuildInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", te, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", te, properties); this->PopulateCompatibleInterfaceProperties(te, properties); @@ -143,7 +146,7 @@ cmExportBuildFileGenerator std::string prop = "IMPORTED_LOCATION"; prop += suffix; std::string value; - if(target->IsFrameworkOnApple() || target->IsAppBundleOnApple()) + if(target->IsAppBundleOnApple()) { value = target->GetFullPath(config, false); } @@ -189,7 +192,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(); } //---------------------------------------------------------------------------- @@ -211,3 +214,19 @@ cmExportBuildFileGenerator << "consider using the APPEND option with multiple separate calls."; this->ExportCommand->ErrorMessage = e.str(); } + +std::string +cmExportBuildFileGenerator::InstallNameDir(cmTarget* target, + const std::string& config) +{ + std::string install_name_dir; + + cmMakefile* mf = target->GetMakefile(); + if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) + { + install_name_dir = + target->GetInstallNameDirForBuildTree(config.c_str()); + } + + return install_name_dir; +} diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 5e1be16480..3ffdf8b133 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -61,6 +61,8 @@ protected: cmTarget* target, ImportPropertyMap& properties); + std::string InstallNameDir(cmTarget* target, const std::string& config); + std::vector<cmTarget*> const* Exports; cmExportCommand* ExportCommand; }; diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 1cc17545ad..ffa8b51152 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 27ec56bebd..6bef017027 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 { @@ -624,8 +624,12 @@ cmExportFileGenerator std::string value; if(target->HasSOName(config)) { + if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) + { + value = this->InstallNameDir(target, config); + } prop = "IMPORTED_SONAME"; - value = target->GetSOName(config); + value += target->GetSOName(config); } else { @@ -772,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"; @@ -835,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 \"" @@ -954,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/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 9f958a2344..ed2d93b8c5 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -159,6 +159,9 @@ private: std::vector<std::string> &missingTargets); virtual void ReplaceInstallPrefix(std::string &input); + + virtual std::string InstallNameDir(cmTarget* target, + const std::string& config) = 0; }; #endif diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index ad12b5a13c..a966b16051 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) @@ -130,6 +130,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) te, cmGeneratorExpression::InstallInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", + te, + cmGeneratorExpression::InstallInterface, + properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", te, properties); this->PopulateCompatibleInterfaceProperties(te, properties); @@ -351,27 +355,7 @@ cmExportInstallFileGenerator prop += suffix; // Append the installed file name. - if(target->IsFrameworkOnApple()) - { - value += itgen->GetInstallFilename(target, config); - value += ".framework/"; - value += itgen->GetInstallFilename(target, config); - } - else if(target->IsCFBundleOnApple()) - { - const char *ext = target->GetProperty("BUNDLE_EXTENSION"); - if (!ext) - { - ext = "bundle"; - } - - value += itgen->GetInstallFilename(target, config); - value += "."; - value += ext; - value += "/"; - value += itgen->GetInstallFilename(target, config); - } - else if(target->IsAppBundleOnApple()) + if(target->IsAppBundleOnApple()) { value += itgen->GetInstallFilename(target, config); value += ".app/Contents/MacOS/"; @@ -395,13 +379,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); } @@ -496,3 +481,19 @@ cmExportInstallFileGenerator } cmSystemTools::Error(e.str().c_str()); } + +std::string +cmExportInstallFileGenerator::InstallNameDir(cmTarget* target, + const std::string&) +{ + std::string install_name_dir; + + cmMakefile* mf = target->GetMakefile(); + if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) + { + install_name_dir = + target->GetInstallNameDirForInstallTree(); + } + + return install_name_dir; +} diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index 20dd57ad1a..7c634a4d8e 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -85,6 +85,8 @@ protected: void ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen); + std::string InstallNameDir(cmTarget* target, const std::string& config); + cmInstallExportGenerator* IEGen; std::string ImportPrefix; diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index 75f2651ba7..e7b185a57f 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -31,8 +31,10 @@ bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os) ImportPropertyMap properties; - this->FindTargets("INTERFACE_INCLUDE_DIRECTORIES", te, emittedDeps); - this->FindTargets("INTERFACE_COMPILE_DEFINITIONS", te, emittedDeps); +#define FIND_TARGETS(PROPERTY) \ + this->FindTargets(#PROPERTY, te, emittedDeps); + + CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(FIND_TARGETS) this->PopulateProperties(te, properties, emittedDeps); @@ -112,3 +114,18 @@ cmExportTryCompileFileGenerator::PopulateProperties(cmTarget* target, } } } +std::string +cmExportTryCompileFileGenerator::InstallNameDir(cmTarget* target, + const std::string& config) +{ + std::string install_name_dir; + + cmMakefile* mf = target->GetMakefile(); + if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) + { + install_name_dir = + target->GetInstallNameDirForBuildTree(config.c_str()); + } + + return install_name_dir; +} diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h index ed393abf40..91b4a6153b 100644 --- a/Source/cmExportTryCompileFileGenerator.h +++ b/Source/cmExportTryCompileFileGenerator.h @@ -43,6 +43,8 @@ protected: ImportPropertyMap& properties, std::set<cmTarget*> &emitted); + std::string InstallNameDir(cmTarget* target, + const std::string& config); private: std::string FindTargets(const char *prop, cmTarget *tgt, std::set<cmTarget*> &emitted); diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 97ab0863ca..d80e775bf3 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;" @@ -540,12 +554,15 @@ void cmExtraEclipseCDT4Generator::CreateLinksForTargets( fileIt != sFiles.end(); ++fileIt) { - std::string linkName4 = linkName3; - linkName4 += "/"; - linkName4 += - cmSystemTools::GetFilenameName((*fileIt)->GetFullPath()); - this->AppendLinkedResource(fout, linkName4, - (*fileIt)->GetFullPath(), LinkToFile); + std::string fullPath = (*fileIt)->GetFullPath(); + if (!cmSystemTools::FileIsDirectory(fullPath.c_str())) + { + std::string linkName4 = linkName3; + linkName4 += "/"; + linkName4 += cmSystemTools::GetFilenameName(fullPath); + this->AppendLinkedResource(fout, linkName4, + fullPath, LinkToFile); + } } } } diff --git a/Source/cmExtraEclipseCDT4Generator.h b/Source/cmExtraEclipseCDT4Generator.h index 31ad68da9b..b31cce74c5 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 e4802d59eb..012013c389 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -429,35 +429,10 @@ cmExtraSublimeTextGenerator::ComputeFlagsForObject(cmSourceFile* source, lg->AppendFlags(flags, makefile->GetDefineFlags()); // Add target-specific flags. - if(target->GetProperty("COMPILE_FLAGS")) - { - std::string langIncludeExpr = "CMAKE_"; - langIncludeExpr += language; - langIncludeExpr += "_FLAG_REGEX"; - const char* regex = makefile->GetDefinition(langIncludeExpr.c_str()); - if(regex) - { - cmsys::RegularExpression r(regex); - std::vector<std::string> args; - cmSystemTools:: - ParseWindowsCommandLine(target->GetProperty("COMPILE_FLAGS"), args); - for(std::vector<std::string>::iterator i = args.begin(); - i != args.end(); ++i) - { - if(r.find(i->c_str())) - { - lg->AppendFlags(flags, i->c_str()); - } - } - } - else - { - lg->AppendFlags(flags, target->GetProperty("COMPILE_FLAGS")); - } - } + lg->AddCompileOptions(flags, target, config, language); // 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 018ce7ecd2..e72e75668c 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 5973fa7324..586fee2ad4 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/cmFindCommon.cxx b/Source/cmFindCommon.cxx index b44864e134..5daa47d6fd 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -62,10 +62,15 @@ void cmFindCommon::GenerateDocumentation() "The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more " "directories to be prepended to all other search directories. " "This effectively \"re-roots\" the entire search under given locations. " - "By default it is empty. It is especially useful when " + "By default it is empty. " + "The variable CMAKE_SYSROOT can also be used to specify exactly one " + "directory to use as a prefix. Setting CMAKE_SYSROOT also has other " + "effects. See the documentation for that variable for more. " + "These are especially useful when " "cross-compiling to point to the root directory of the " "target environment and CMake will search there too. By default at first " - "the directories listed in CMAKE_FIND_ROOT_PATH and then the non-rooted " + "the CMAKE_SYSROOT directory is searched, then the directories listed in " + "CMAKE_FIND_ROOT_PATH and then the non-rooted " "directories will be searched. " "The default behavior can be adjusted by setting " "CMAKE_FIND_ROOT_PATH_MODE_XXX. This behavior can be manually " @@ -187,16 +192,27 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths) { return; } + const char* sysroot = + this->Makefile->GetDefinition("CMAKE_SYSROOT"); const char* rootPath = this->Makefile->GetDefinition("CMAKE_FIND_ROOT_PATH"); - if((rootPath == 0) || (strlen(rootPath) == 0)) + const bool noSysroot = !sysroot || !*sysroot; + const bool noRootPath = !rootPath || !*rootPath; + if(noSysroot && noRootPath) { return; } // Construct the list of path roots with no trailing slashes. std::vector<std::string> roots; - cmSystemTools::ExpandListArgument(rootPath, roots); + if (sysroot) + { + roots.push_back(sysroot); + } + if (rootPath) + { + cmSystemTools::ExpandListArgument(rootPath, roots); + } for(std::vector<std::string>::iterator ri = roots.begin(); ri != roots.end(); ++ri) { diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 10b47b9e09..a126cd1102 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/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index 5cb50b9b81..5b79e35310 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -33,8 +33,13 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( } this->CheckResult = this->checkGraph(); - if (CheckResult == DAG && (top->EvaluatingIncludeDirectories() - || top->EvaluatingCompileDefinitions())) +#define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) \ + top->METHOD () || + + if (CheckResult == DAG && ( + CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(TEST_TRANSITIVE_PROPERTY_METHOD) + false) + ) { std::map<cmStdString, std::set<cmStdString> >::const_iterator it = top->Seen.find(target); @@ -134,7 +139,7 @@ cmGeneratorExpressionDAGChecker::checkGraph() const } //---------------------------------------------------------------------------- -bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries() +bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(const char *tgt) { const cmGeneratorExpressionDAGChecker *top = this; const cmGeneratorExpressionDAGChecker *parent = this->Parent; @@ -145,6 +150,12 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries() } const char *prop = top->Property.c_str(); + + if (tgt) + { + return top->Target == tgt && strcmp(prop, "LINK_LIBRARIES") == 0; + } + return (strcmp(prop, "LINK_LIBRARIES") == 0 || strcmp(prop, "LINK_INTERFACE_LIBRARIES") == 0 || strcmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES") == 0 @@ -168,3 +179,11 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingCompileDefinitions() const || strcmp(prop, "INTERFACE_COMPILE_DEFINITIONS") == 0 || strncmp(prop, "COMPILE_DEFINITIONS_", 20) == 0); } + +//---------------------------------------------------------------------------- +bool cmGeneratorExpressionDAGChecker::EvaluatingCompileOptions() const +{ + const char *prop = this->Property.c_str(); + return (strcmp(prop, "COMPILE_OPTIONS") == 0 + || strcmp(prop, "INTERFACE_COMPILE_OPTIONS") == 0 ); +} diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index 62a5cdf38b..95d466ae3b 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -16,6 +16,16 @@ #include "cmGeneratorExpressionEvaluator.h" +#define CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(F) \ + F(EvaluatingIncludeDirectories) \ + F(EvaluatingCompileDefinitions) \ + F(EvaluatingCompileOptions) + +#define CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(F) \ + F(INTERFACE_INCLUDE_DIRECTORIES) \ + F(INTERFACE_COMPILE_DEFINITIONS) \ + F(INTERFACE_COMPILE_OPTIONS) + //---------------------------------------------------------------------------- struct cmGeneratorExpressionDAGChecker { @@ -37,9 +47,12 @@ struct cmGeneratorExpressionDAGChecker void reportError(cmGeneratorExpressionContext *context, const std::string &expr); - bool EvaluatingLinkLibraries(); - bool EvaluatingIncludeDirectories() const; - bool EvaluatingCompileDefinitions() const; + bool EvaluatingLinkLibraries(const char *tgt = 0); + +#define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) \ + bool METHOD () const; + +CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(DECLARE_TRANSITIVE_PROPERTY_METHOD) private: Result checkGraph() const; diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx new file mode 100644 index 0000000000..cab99ed046 --- /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 0000000000..20ee5cb2da --- /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 6618e83e28..037ef31d75 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, \ @@ -243,6 +247,155 @@ static const struct SemicolonNode : public cmGeneratorExpressionNode } semicolonNode; //---------------------------------------------------------------------------- +struct CompilerIdNode : public cmGeneratorExpressionNode +{ + CompilerIdNode() {} + + virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; } + + std::string EvaluateWithLanguage(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *, + const std::string &lang) const + { + const char *compilerId = context->Makefile ? + context->Makefile->GetSafeDefinition(( + "CMAKE_" + lang + "_COMPILER_ID").c_str()) : ""; + if (parameters.size() == 0) + { + return compilerId ? compilerId : ""; + } + cmsys::RegularExpression compilerIdValidator; + compilerIdValidator.compile("^[A-Za-z0-9_]*$"); + if (!compilerIdValidator.find(parameters.begin()->c_str())) + { + reportError(context, content->GetOriginalExpression(), + "Expression syntax not recognized."); + return std::string(); + } + if (!compilerId) + { + return parameters.front().empty() ? "1" : "0"; + } + + if (cmsysString_strcasecmp(parameters.begin()->c_str(), compilerId) == 0) + { + return "1"; + } + return "0"; + } +}; + +//---------------------------------------------------------------------------- +static const struct CCompilerIdNode : public CompilerIdNode +{ + CCompilerIdNode() {} + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *dagChecker) const + { + if (parameters.size() != 0 && parameters.size() != 1) + { + reportError(context, content->GetOriginalExpression(), + "$<C_COMPILER_ID> expression requires one or two parameters"); + return std::string(); + } + if (!context->HeadTarget) + { + reportError(context, content->GetOriginalExpression(), + "$<C_COMPILER_ID> may only be used with targets. It may not " + "be used with add_custom_command."); + } + return this->EvaluateWithLanguage(parameters, context, content, + dagChecker, "C"); + } +} cCompilerIdNode; + +//---------------------------------------------------------------------------- +static const struct CXXCompilerIdNode : public CompilerIdNode +{ + CXXCompilerIdNode() {} + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *dagChecker) const + { + if (parameters.size() != 0 && parameters.size() != 1) + { + reportError(context, content->GetOriginalExpression(), + "$<CXX_COMPILER_ID> expression requires one or two parameters"); + return std::string(); + } + if (!context->HeadTarget) + { + reportError(context, content->GetOriginalExpression(), + "$<CXX_COMPILER_ID> may only be used with targets. It may not " + "be used with add_custom_command."); + } + return this->EvaluateWithLanguage(parameters, context, content, + dagChecker, "CXX"); + } +} cxxCompilerIdNode; + +//---------------------------------------------------------------------------- +static const struct VersionGreaterNode : public cmGeneratorExpressionNode +{ + VersionGreaterNode() {} + + virtual int NumExpectedParameters() const { return 2; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, + parameters.front().c_str(), + parameters[1].c_str()) ? "1" : "0"; + } +} versionGreaterNode; + +//---------------------------------------------------------------------------- +static const struct VersionLessNode : public cmGeneratorExpressionNode +{ + VersionLessNode() {} + + virtual int NumExpectedParameters() const { return 2; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, + parameters.front().c_str(), + parameters[1].c_str()) ? "1" : "0"; + } +} versionLessNode; + +//---------------------------------------------------------------------------- +static const struct VersionEqualNode : public cmGeneratorExpressionNode +{ + VersionEqualNode() {} + + virtual int NumExpectedParameters() const { return 2; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, + parameters.front().c_str(), + parameters[1].c_str()) ? "1" : "0"; + } +} versionEqualNode; + +//---------------------------------------------------------------------------- static const struct ConfigurationNode : public cmGeneratorExpressionNode { ConfigurationNode() {} @@ -306,11 +459,158 @@ 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 *dagChecker) const + { + if (dagChecker && dagChecker->EvaluatingLinkLibraries()) + { + reportError(context, content->GetOriginalExpression(), + "$<LINK_LANGUAGE> expression can not be used while evaluating " + "link libraries"); + return std::string(); + } + 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."); + return std::string(); + } + + 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; + +#define TRANSITIVE_PROPERTY_NAME(PROPERTY) \ + , #PROPERTY //---------------------------------------------------------------------------- static const char* targetPropertyTransitiveWhitelist[] = { - "INTERFACE_INCLUDE_DIRECTORIES" - , "INTERFACE_COMPILE_DEFINITIONS" + 0 + CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_NAME) +}; + +std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, + cmTarget *target, + cmTarget *headTarget, + 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, + 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; }; //---------------------------------------------------------------------------- @@ -319,7 +619,7 @@ 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, @@ -436,7 +736,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode // No error. We just skip cyclic references. return std::string(); case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: - for (size_t i = 0; + for (size_t i = 1; i < (sizeof(targetPropertyTransitiveWhitelist) / sizeof(*targetPropertyTransitiveWhitelist)); ++i) @@ -464,8 +764,13 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } else { - assert(dagCheckerParent->EvaluatingIncludeDirectories() - || dagCheckerParent->EvaluatingCompileDefinitions()); +#define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) \ + dagCheckerParent->METHOD () || + + assert( + CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD( + ASSERT_TRANSITIVE_PROPERTY_METHOD) + false); } } @@ -484,50 +789,46 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode { interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS"; } + else if (propertyName == "INTERFACE_COMPILE_OPTIONS" + || propertyName == "COMPILE_OPTIONS") + { + interfacePropertyName = "INTERFACE_COMPILE_OPTIONS"; + } - if (interfacePropertyName == "INTERFACE_INCLUDE_DIRECTORIES" - || interfacePropertyName == "INTERFACE_COMPILE_DEFINITIONS") + cmTarget *headTarget = context->HeadTarget ? context->HeadTarget : target; + + const char **transBegin = targetPropertyTransitiveWhitelist + 1; + 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); + 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, + headTarget, + context, &dagChecker, + interfacePropertyName); + } + } + else if (std::find_if(transBegin, transEnd, + TransitiveWhitelistCompare(interfacePropertyName)) != transEnd) + { + const cmTarget::LinkImplementation *impl = target->GetLinkImplementation( + context->Config, + headTarget); + if(impl) + { + linkedTargetsContent = + getLinkedTargetsContent(impl->Libraries, target, + headTarget, + context, &dagChecker, + interfacePropertyName); } } @@ -562,7 +863,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode return linkedTargetsContent; } - for (size_t i = 0; + for (size_t i = 1; i < (sizeof(targetPropertyTransitiveWhitelist) / sizeof(*targetPropertyTransitiveWhitelist)); ++i) @@ -574,7 +875,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode std::string result = cge->Evaluate(context->Makefile, context->Config, context->Quiet, - context->HeadTarget, + headTarget, target, &dagChecker); @@ -600,7 +901,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, @@ -853,7 +1154,7 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode std::string Evaluate(const std::vector<std::string> ¶meters, cmGeneratorExpressionContext *context, const GeneratorExpressionContent *content, - cmGeneratorExpressionDAGChecker *) const + cmGeneratorExpressionDAGChecker *dagChecker) const { // Lookup the referenced target. std::string name = *parameters.begin(); @@ -878,6 +1179,13 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode "Target \"" + name + "\" is not an executable or library."); return std::string(); } + if (dagChecker && dagChecker->EvaluatingLinkLibraries(name.c_str())) + { + ::reportError(context, content->GetOriginalExpression(), + "Expressions which require the linker language may not " + "be used while evaluating link libraries"); + return std::string(); + } context->DependTargets.insert(target); context->AllTargets.insert(target); @@ -929,10 +1237,22 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) return &orNode; else if (identifier == "NOT") return ¬Node; + else if (identifier == "C_COMPILER_ID") + return &cCompilerIdNode; + else if (identifier == "CXX_COMPILER_ID") + return &cxxCompilerIdNode; + else if (identifier == "VERSION_GREATER") + return &versionGreaterNode; + else if (identifier == "VERSION_LESS") + return &versionLessNode; + else if (identifier == "VERSION_EQUAL") + return &versionEqualNode; else if (identifier == "CONFIGURATION") 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 +1293,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 +1315,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 +1397,8 @@ std::string GeneratorExpressionContent::Evaluate( if (!node->GeneratesContent()) { - if (node->AcceptsSingleArbitraryContentParameter()) + if (node->NumExpectedParameters() == 1 + && node->AcceptsArbitraryContentParameter()) { if (this->ParamChildren.empty()) { @@ -1041,50 +1415,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 +1441,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 +1466,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 +1506,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 +1534,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 ce7ad69bb6..218abf1603 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 335ba0f25f..f5d15607e0 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 cbcd8a5790..5f7019deb5 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/cmGetCMakePropertyCommand.cxx b/Source/cmGetCMakePropertyCommand.cxx index 8bb54877ee..e7ad91a364 100644 --- a/Source/cmGetCMakePropertyCommand.cxx +++ b/Source/cmGetCMakePropertyCommand.cxx @@ -11,6 +11,8 @@ ============================================================================*/ #include "cmGetCMakePropertyCommand.h" +#include "cmGlobalGenerator.h" +#include "cmLocalGenerator.h" #include "cmake.h" // cmGetCMakePropertyCommand diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx index fd1ad601f3..1d7fefcee4 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 f294daa0de..09af3325ab 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/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx index 7d33358877..985dc50b84 100644 --- a/Source/cmGetPropertyCommand.cxx +++ b/Source/cmGetPropertyCommand.cxx @@ -13,6 +13,9 @@ #include "cmake.h" #include "cmTest.h" +#include "cmGlobalGenerator.h" +#include "cmLocalGenerator.h" +#include "cmSourceFile.h" #include "cmPropertyDefinition.h" //---------------------------------------------------------------------------- diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index df1433105d..ad74767f74 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) @@ -407,7 +415,7 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages, { if(!mf->ReadListFile(0,fpath.c_str())) { - cmSystemTools::Error("Could not find cmake module file:", + cmSystemTools::Error("Could not find cmake module file: ", fpath.c_str()); } // if this file was found then the language was already determined @@ -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"); @@ -437,7 +445,7 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages, mf->GetModulesFile(determineCompiler.c_str()); if(!mf->ReadListFile(0,determineFile.c_str())) { - cmSystemTools::Error("Could not find cmake module file:", + cmSystemTools::Error("Could not find cmake module file: ", determineFile.c_str()); } needTestLanguage[lang] = true; @@ -471,7 +479,7 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages, fpath += "Compiler.cmake"; if(!mf->ReadListFile(0,fpath.c_str())) { - cmSystemTools::Error("Could not find cmake module file:", + cmSystemTools::Error("Could not find cmake module file: ", fpath.c_str()); } this->SetLanguageEnabledFlag(lang, mf); @@ -490,7 +498,7 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages, fpath = mf->GetModulesFile("CMakeSystemSpecificInformation.cmake"); if(!mf->ReadListFile(0,fpath.c_str())) { - cmSystemTools::Error("Could not find cmake module file:", + cmSystemTools::Error("Could not find cmake module file: ", fpath.c_str()); } } @@ -516,12 +524,12 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages, std::string informationFile = mf->GetModulesFile(fpath.c_str()); if (informationFile.empty()) { - cmSystemTools::Error("Could not find cmake module file:", + cmSystemTools::Error("Could not find cmake module file: ", fpath.c_str()); } else if(!mf->ReadListFile(0, informationFile.c_str())) { - cmSystemTools::Error("Could not process cmake module file:", + cmSystemTools::Error("Could not process cmake module file: ", informationFile.c_str()); } } @@ -560,7 +568,7 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages, std::string ifpath = mf->GetModulesFile(testLang.c_str()); if(!mf->ReadListFile(0,ifpath.c_str())) { - cmSystemTools::Error("Could not find cmake module file:", + cmSystemTools::Error("Could not find cmake module file: ", ifpath.c_str()); } std::string compilerWorks = "CMAKE_"; @@ -955,7 +963,7 @@ void cmGlobalGenerator::Generate() for ( tit = targets->begin(); tit != targets->end(); ++ tit ) { - tit->second.AppendBuildInterfaceIncludes(); + tit->second.AppendBuildInterfaceIncludes(); } } @@ -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 11616e0d06..2fcdc431eb 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 fa277b1d15..e2c0e18a24 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; @@ -959,6 +961,9 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) this->LocalGenerators.begin(); i != this->LocalGenerators.end(); ++i) { const std::vector<std::string>& lf = (*i)->GetMakefile()->GetListFiles(); implicitDeps.insert(implicitDeps.end(), lf.begin(), lf.end()); + + const std::vector<std::string>& of = (*i)->GetMakefile()->GetOutputFiles(); + implicitDeps.insert(implicitDeps.end(), of.begin(), of.end()); } std::sort(implicitDeps.begin(), implicitDeps.end()); implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()), diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index c3df7d9358..6e9378821d 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 e26cca9407..88cd6e5f84 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 385cdc4a16..5e9dce3a6b 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 b8c493916d..742ab78512 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 5926e0f214..dbe60442a0 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 9f3af71bbb..b3fabdade2 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 40149e9117..6bd39ca9a5 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 63cbdb8905..9a34ecff05 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 6e786201b9..3ebb408a32 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 808664d44e..f4be0cebc4 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 ceac564035..9cfbe42a00 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)) @@ -679,10 +681,6 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg, { // Add flags from target and source file properties. std::string flags; - if(cmtarget.GetProperty("COMPILE_FLAGS")) - { - lg->AppendFlags(flags, cmtarget.GetProperty("COMPILE_FLAGS")); - } const char* srcfmt = sf->GetProperty("Fortran_FORMAT"); switch(this->CurrentLocalGenerator->GetFortranFormat(srcfmt)) { @@ -746,12 +744,6 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg, } } - if(cmtarget.IsCFBundleOnApple()) - { - cmtarget.SetProperty("PREFIX", ""); - cmtarget.SetProperty("SUFFIX", ""); - } - // Add the fileRef to the top level Resources group/folder if it is not // already there. // @@ -839,7 +831,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 +874,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 +995,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); @@ -1319,8 +1311,40 @@ void cmGlobalXCodeGenerator::CreateCustomCommands(cmXCodeObject* buildPhases, = cmtarget.GetPreBuildCommands(); std::vector<cmCustomCommand> const & prelink = cmtarget.GetPreLinkCommands(); - std::vector<cmCustomCommand> const & postbuild + std::vector<cmCustomCommand> postbuild = cmtarget.GetPostBuildCommands(); + + if(cmtarget.GetType() == cmTarget::SHARED_LIBRARY && + !cmtarget.IsFrameworkOnApple()) + { + cmCustomCommandLines cmd; + cmd.resize(1); + cmd[0].push_back(this->CurrentMakefile->GetDefinition("CMAKE_COMMAND")); + cmd[0].push_back("-E"); + cmd[0].push_back("cmake_symlink_library"); + std::string str_file = "$<TARGET_FILE:"; + str_file += cmtarget.GetName(); + str_file += ">"; + std::string str_so_file = "$<TARGET_SONAME_FILE:"; + str_so_file += cmtarget.GetName(); + str_so_file += ">"; + std::string str_link_file = "$<TARGET_LINKER_FILE:"; + str_link_file += cmtarget.GetName(); + str_link_file += ">"; + cmd[0].push_back(str_file); + cmd[0].push_back(str_so_file); + cmd[0].push_back(str_link_file); + + cmCustomCommand command(this->CurrentMakefile, + std::vector<std::string>(), + std::vector<std::string>(), + cmd, + "Creating symlinks", + ""); + + postbuild.push_back(command); + } + std::vector<cmSourceFile*>const &classes = cmtarget.GetSourceFiles(); // add all the sources std::vector<cmCustomCommand> commands; @@ -1674,6 +1698,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, this->CurrentLocalGenerator->AddLanguageFlags(cflags, "C", configName); this->CurrentLocalGenerator->AddCMP0018Flags(cflags, &target, "C", configName); + this->CurrentLocalGenerator-> + AddCompileOptions(cflags, &target, "C", configName); } // Add language-specific flags. @@ -1682,11 +1708,17 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, // Add shared-library flags if needed. this->CurrentLocalGenerator->AddCMP0018Flags(flags, &target, lang, configName); + + this->CurrentLocalGenerator->AddVisibilityPresetFlags(flags, &target, + lang); + + this->CurrentLocalGenerator-> + AddCompileOptions(flags, &target, lang, configName); } else if(binary) { cmSystemTools::Error - ("CMake can not determine linker language for target:", + ("CMake can not determine linker language for target: ", target.GetName()); return; } @@ -1714,30 +1746,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"; @@ -1797,9 +1825,34 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, std::string pnprefix; std::string pnbase; std::string pnsuffix; - target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName); + const char* version = target.GetProperty("VERSION"); + const char* soversion = target.GetProperty("SOVERSION"); + if(!target.HasSOName(configName) || target.IsFrameworkOnApple()) + { + version = 0; + soversion = 0; + } + if(version && !soversion) + { + soversion = version; + } + if(!version && soversion) + { + version = soversion; + } + + std::string realName = pnbase; + std::string soName = pnbase; + if(version && soversion) + { + realName += "."; + realName += version; + soName += "."; + soName += soversion; + } + // Set attributes to specify the proper name for the target. std::string pndir = this->CurrentMakefile->GetCurrentOutputDirectory(); if(target.GetType() == cmTarget::STATIC_LIBRARY || @@ -1823,6 +1876,11 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, pndir = target.GetDirectory(configName); } + if(target.IsFrameworkOnApple() || target.IsCFBundleOnApple()) + { + pnprefix = ""; + } + buildSettings->AddAttribute("EXECUTABLE_PREFIX", this->CreateString(pnprefix.c_str())); buildSettings->AddAttribute("EXECUTABLE_SUFFIX", @@ -1852,7 +1910,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, // Store the product name for all target types. buildSettings->AddAttribute("PRODUCT_NAME", - this->CreateString(pnbase.c_str())); + this->CreateString(realName.c_str())); buildSettings->AddAttribute("SYMROOT", this->CreateString(pndir.c_str())); @@ -1930,9 +1988,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, { if(target.GetPropertyAsBool("FRAMEWORK")) { - std::string version = target.GetFrameworkVersion(); + std::string fw_version = target.GetFrameworkVersion(); buildSettings->AddAttribute("FRAMEWORK_VERSION", - this->CreateString(version.c_str())); + this->CreateString(fw_version.c_str())); std::string plist = this->ComputeInfoPListLocation(target); // Xcode will create the final version of Info.plist at build time, @@ -2028,20 +2086,16 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, dirs.Add(incpath.c_str()); } } - if(target.GetType() != cmTarget::OBJECT_LIBRARY && - target.GetType() != cmTarget::STATIC_LIBRARY) + // Add framework search paths needed for linking. + if(cmComputeLinkInformation* cli = target.GetLinkInformation(configName)) { - // Add framework search paths needed for linking. - if(cmComputeLinkInformation* cli = target.GetLinkInformation(configName)) + std::vector<std::string> const& fwDirs = cli->GetFrameworkPaths(); + for(std::vector<std::string>::const_iterator fdi = fwDirs.begin(); + fdi != fwDirs.end(); ++fdi) { - std::vector<std::string> const& fwDirs = cli->GetFrameworkPaths(); - for(std::vector<std::string>::const_iterator fdi = fwDirs.begin(); - fdi != fwDirs.end(); ++fdi) + if(emitted.insert(*fdi).second) { - if(emitted.insert(*fdi).second) - { - fdirs.Add(this->XCodeEscapePath(fdi->c_str()).c_str()); - } + fdirs.Add(this->XCodeEscapePath(fdi->c_str()).c_str()); } } } @@ -2156,25 +2210,55 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, if(target.GetType() == cmTarget::SHARED_LIBRARY) { // Get the install_name directory for the build tree. - install_name_dir = target.GetInstallNameDirForBuildTree(configName, true); - if(install_name_dir.empty()) - { - // Xcode will not pass the -install_name option at all if INSTALL_PATH - // is not given or is empty. We must explicitly put the flag in the - // link flags to create an install_name with just the library soname. - extraLinkOptions += " -install_name "; - extraLinkOptions += target.GetFullName(configName); - } - else + install_name_dir = target.GetInstallNameDirForBuildTree(configName); + // Xcode doesn't create the correct install_name in some cases. + // That is, if the INSTALL_PATH is empty, or if we have versioning + // of dylib libraries, we want to specify the install_name. + // This is done by adding a link flag to create an install_name + // with just the library soname. + std::string install_name; + if(!install_name_dir.empty()) { // Convert to a path for the native build tool. cmSystemTools::ConvertToUnixSlashes(install_name_dir); - // do not escape spaces on this since it is only a single path + install_name += install_name_dir; + install_name += "/"; + } + install_name += target.GetSOName(configName); + + if((realName != soName) || install_name_dir.empty()) + { + install_name_dir = ""; + extraLinkOptions += " -install_name "; + extraLinkOptions += XCodeEscapePath(install_name.c_str()); } } buildSettings->AddAttribute("INSTALL_PATH", this->CreateString(install_name_dir.c_str())); + // Create the LD_RUNPATH_SEARCH_PATHS + cmComputeLinkInformation* pcli = target.GetLinkInformation(configName); + if(pcli) + { + std::string search_paths; + std::vector<std::string> runtimeDirs; + pcli->GetRPath(runtimeDirs, false); + for(std::vector<std::string>::const_iterator i = runtimeDirs.begin(); + i != runtimeDirs.end(); ++i) + { + if(!search_paths.empty()) + { + search_paths += " "; + } + search_paths += this->XCodeEscapePath((*i).c_str()); + } + if(!search_paths.empty()) + { + buildSettings->AddAttribute("LD_RUNPATH_SEARCH_PATHS", + this->CreateString(search_paths.c_str())); + } + } + buildSettings->AddAttribute("OTHER_LDFLAGS", this->CreateString(extraLinkOptions.c_str())); buildSettings->AddAttribute("OTHER_REZFLAGS", @@ -2239,8 +2323,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 131a6e6d5f..c05394346b 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, @@ -84,6 +85,7 @@ public: virtual bool IsMultiConfig(); virtual bool SetGeneratorToolset(std::string const& ts); + void AppendFlag(std::string& flags, std::string const& flag); private: cmXCodeObject* CreateOrGetPBXGroup(cmTarget& cmtarget, cmSourceGroup* sg); @@ -197,7 +199,6 @@ private: void AppendDefines(BuildObjectListOrString& defs, std::vector<std::string> const& defines, bool dflag = false); - void AppendFlag(std::string& flags, std::string const& flag); protected: virtual const char* GetInstallTargetName() const { return "install"; } diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 56d717031e..57cec5bbbd 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -406,38 +406,6 @@ namespace } //========================================================================= - enum Op { OpLess, OpEqual, OpGreater }; - bool HandleVersionCompare(Op op, const char* lhs_str, const char* rhs_str) - { - // Parse out up to 8 components. - unsigned int lhs[8] = {0,0,0,0,0,0,0,0}; - unsigned int rhs[8] = {0,0,0,0,0,0,0,0}; - sscanf(lhs_str, "%u.%u.%u.%u.%u.%u.%u.%u", - &lhs[0], &lhs[1], &lhs[2], &lhs[3], - &lhs[4], &lhs[5], &lhs[6], &lhs[7]); - sscanf(rhs_str, "%u.%u.%u.%u.%u.%u.%u.%u", - &rhs[0], &rhs[1], &rhs[2], &rhs[3], - &rhs[4], &rhs[5], &rhs[6], &rhs[7]); - - // Do component-wise comparison. - for(unsigned int i=0; i < 8; ++i) - { - if(lhs[i] < rhs[i]) - { - // lhs < rhs, so true if operation is LESS - return op == OpLess; - } - else if(lhs[i] > rhs[i]) - { - // lhs > rhs, so true if operation is GREATER - return op == OpGreater; - } - } - // lhs == rhs, so true if operation is EQUAL - return op == OpEqual; - } - - //========================================================================= // level 0 processes parenthetical expressions bool HandleLevel0(std::list<std::string> &newArgs, cmMakefile *makefile, @@ -723,16 +691,16 @@ namespace { def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile); def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile); - Op op = OpEqual; + cmSystemTools::CompareOp op = cmSystemTools::OP_EQUAL; if(*argP1 == "VERSION_LESS") { - op = OpLess; + op = cmSystemTools::OP_LESS; } else if(*argP1 == "VERSION_GREATER") { - op = OpGreater; + op = cmSystemTools::OP_GREATER; } - bool result = HandleVersionCompare(op, def, def2); + bool result = cmSystemTools::VersionCompare(op, def, def2); HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); } diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx index 0d5f67b78e..bb891d6fc6 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 ffb0e8086b..30c174375d 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/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 5f9b6585eb..ed01210240 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -198,14 +198,12 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, // Install the whole framework directory. type = cmInstallType_DIRECTORY; literal_args += " USE_SOURCE_PERMISSIONS"; - std::string from1 = fromDirConfig + targetName + ".framework"; + + std::string from1 = fromDirConfig + targetName; + from1 = cmSystemTools::GetFilenamePath(from1); // Tweaks apply to the binary inside the bundle. - std::string to1 = toDir + targetName; - to1 += ".framework/Versions/"; - to1 += this->Target->GetFrameworkVersion(); - to1 += "/"; - to1 += targetName; + std::string to1 = toDir + targetNameReal; filesFrom.push_back(from1); filesTo.push_back(to1); @@ -528,7 +526,7 @@ cmInstallTargetGenerator // components of the install_name field then we need to create a // mapping to be applied after installation. std::string for_build = tgt->GetInstallNameDirForBuildTree(config); - std::string for_install = tgt->GetInstallNameDirForInstallTree(config); + std::string for_install = tgt->GetInstallNameDirForInstallTree(); if(for_build != for_install) { // The directory portions differ. Append the filename to @@ -555,7 +553,7 @@ cmInstallTargetGenerator std::string for_build = this->Target->GetInstallNameDirForBuildTree(config); std::string for_install = - this->Target->GetInstallNameDirForInstallTree(config); + this->Target->GetInstallNameDirForInstallTree(); if(this->Target->IsFrameworkOnApple() && for_install.empty()) { @@ -608,6 +606,12 @@ cmInstallTargetGenerator return; } + // Skip if on Apple + if(this->Target->GetMakefile()->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) + { + return; + } + // Get the link information for this target. // It can provide the RPATH. cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config); @@ -647,30 +651,62 @@ cmInstallTargetGenerator return; } - // Construct the original rpath string to be replaced. - std::string oldRpath = cli->GetRPathString(false); - - // Get the install RPATH from the link information. - std::string newRpath = cli->GetChrpathString(); - - // Skip the rule if the paths are identical - if(oldRpath == newRpath) + if(this->Target->GetMakefile()->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { - return; - } + // If using install_name_tool, set up the rules to modify the rpaths. + std::string installNameTool = + this->Target->GetMakefile()-> + GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL"); + + std::vector<std::string> oldRuntimeDirs, newRuntimeDirs; + cli->GetRPath(oldRuntimeDirs, false); + cli->GetRPath(newRuntimeDirs, true); + + // Note: These are separate commands to avoid install_name_tool + // corruption on 10.6. + for(std::vector<std::string>::const_iterator i = oldRuntimeDirs.begin(); + i != oldRuntimeDirs.end(); ++i) + { + os << indent << "execute_process(COMMAND " << installNameTool << "\n"; + os << indent << " -delete_rpath \"" << *i << "\"\n"; + os << indent << " \"" << toDestDirPath << "\")\n"; + } - // Write a rule to run chrpath to set the install-tree RPATH - if(newRpath.empty()) - { - os << indent << "FILE(RPATH_REMOVE\n" - << indent << " FILE \"" << toDestDirPath << "\")\n"; + for(std::vector<std::string>::const_iterator i = newRuntimeDirs.begin(); + i != newRuntimeDirs.end(); ++i) + { + os << indent << "execute_process(COMMAND " << installNameTool << "\n"; + os << indent << " -add_rpath \"" << *i << "\"\n"; + os << indent << " \"" << toDestDirPath << "\")\n"; + } } else { - os << indent << "FILE(RPATH_CHANGE\n" - << indent << " FILE \"" << toDestDirPath << "\"\n" - << indent << " OLD_RPATH \"" << oldRpath << "\"\n" - << indent << " NEW_RPATH \"" << newRpath << "\")\n"; + // Construct the original rpath string to be replaced. + std::string oldRpath = cli->GetRPathString(false); + + // Get the install RPATH from the link information. + std::string newRpath = cli->GetChrpathString(); + + // Skip the rule if the paths are identical + if(oldRpath == newRpath) + { + return; + } + + // Write a rule to run chrpath to set the install-tree RPATH + if(newRpath.empty()) + { + os << indent << "FILE(RPATH_REMOVE\n" + << indent << " FILE \"" << toDestDirPath << "\")\n"; + } + else + { + os << indent << "FILE(RPATH_CHANGE\n" + << indent << " FILE \"" << toDestDirPath << "\"\n" + << indent << " OLD_RPATH \"" << oldRpath << "\"\n" + << indent << " NEW_RPATH \"" << newRpath << "\")\n"; + } } } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index ee5b9d812d..00846d5f8c 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; @@ -761,7 +761,7 @@ void cmLocalGenerator if(!llang) { cmSystemTools::Error - ("CMake can not determine linker language for target:", + ("CMake can not determine linker language for target: ", target.Target->GetName()); return; } @@ -1044,11 +1044,20 @@ cmLocalGenerator::ExpandRuleVariable(std::string const& variable, // If this is the compiler then look for the extra variable // _COMPILER_ARG1 which must be the first argument to the compiler const char* compilerArg1 = 0; + const char* compilerTarget = 0; + const char* compilerOptionTarget = 0; if(actualReplace == "CMAKE_${LANG}_COMPILER") { std::string arg1 = actualReplace + "_ARG1"; cmSystemTools::ReplaceString(arg1, "${LANG}", lang); compilerArg1 = this->Makefile->GetDefinition(arg1.c_str()); + compilerTarget + = this->Makefile->GetDefinition( + (std::string("CMAKE_") + lang + "_COMPILER_TARGET").c_str()); + compilerOptionTarget + = this->Makefile->GetDefinition( + (std::string("CMAKE_") + lang + + "_COMPILE_OPTION_TARGET").c_str()); } if(actualReplace.find("${LANG}") != actualReplace.npos) { @@ -1069,6 +1078,11 @@ cmLocalGenerator::ExpandRuleVariable(std::string const& variable, ret += " "; ret += compilerArg1; } + if (compilerTarget && compilerOptionTarget) + { + ret += compilerOptionTarget; + ret += compilerTarget; + } return ret; } return replace; @@ -1084,8 +1098,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('<'); @@ -1327,6 +1339,54 @@ std::string cmLocalGenerator::GetIncludeFlags( } //---------------------------------------------------------------------------- +void cmLocalGenerator::AddCompileOptions( + std::string& flags, cmTarget* target, + const char* lang, const char* config + ) +{ + std::string langFlagRegexVar = std::string("CMAKE_")+lang+"_FLAG_REGEX"; + if(const char* langFlagRegexStr = + this->Makefile->GetDefinition(langFlagRegexVar.c_str())) + { + // Filter flags acceptable to this language. + cmsys::RegularExpression r(langFlagRegexStr); + std::vector<std::string> opts; + if(const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) + { + cmSystemTools::ParseWindowsCommandLine(targetFlags, opts); + } + target->GetCompileOptions(opts, config); + for(std::vector<std::string>::const_iterator i = opts.begin(); + i != opts.end(); ++i) + { + if(r.find(i->c_str())) + { + // (Re-)Escape this flag. COMPILE_FLAGS were already parsed + // as a command line above, and COMPILE_OPTIONS are escaped. + this->AppendFlagEscape(flags, i->c_str()); + } + } + } + else + { + // Use all flags. + if(const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) + { + // COMPILE_FLAGS are not escaped for historical reasons. + this->AppendFlags(flags, targetFlags); + } + std::vector<std::string> opts; // TODO: Emitted. + target->GetCompileOptions(opts, config); + for(std::vector<std::string>::const_iterator i = opts.begin(); + i != opts.end(); ++i) + { + // COMPILE_OPTIONS are escaped. + this->AppendFlagEscape(flags, i->c_str()); + } + } +} + +//---------------------------------------------------------------------------- void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, cmGeneratorTarget* target, const char* lang, @@ -1407,6 +1467,8 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, return; } + std::string rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT"); + std::vector<std::string> implicitDirs; // Load implicit include directories for this language. std::string impDirVar = "CMAKE_"; @@ -1419,7 +1481,9 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, for(std::vector<std::string>::const_iterator i = impDirVec.begin(); i != impDirVec.end(); ++i) { - emitted.insert(*i); + std::string d = rootPath + *i; + cmSystemTools::ConvertToUnixSlashes(d); + emitted.insert(d); if (!stripImplicitInclDirs) { implicitDirs.push_back(*i); @@ -1582,7 +1646,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, if(!linkLanguage) { cmSystemTools::Error - ("CMake can not determine linker language for target:", + ("CMake can not determine linker language for target: ", target->Target->GetName()); return; } @@ -1994,6 +2058,81 @@ void cmLocalGenerator::AddSharedFlags(std::string& flags, } } +static void AddVisibilityCompileOption(std::string &flags, cmTarget* target, + cmLocalGenerator *lg, const char *lang) +{ + std::string l(lang); + std::string compileOption = "CMAKE_" + l + "_COMPILE_OPTIONS_VISIBILITY"; + const char *opt = lg->GetMakefile()->GetDefinition(compileOption.c_str()); + if (!opt) + { + return; + } + std::string flagDefine = l + "_VISIBILITY_PRESET"; + + const char *prop = target->GetProperty(flagDefine.c_str()); + if (!prop) + { + return; + } + if (strcmp(prop, "hidden") != 0 + && strcmp(prop, "default") != 0 + && strcmp(prop, "protected") != 0 + && strcmp(prop, "internal") != 0 ) + { + cmOStringStream e; + e << "Target " << target->GetName() << " uses unsupported value \"" + << prop << "\" for " << flagDefine << "."; + cmSystemTools::Error(e.str().c_str()); + return; + } + std::string option = std::string(opt) + prop; + lg->AppendFlags(flags, option.c_str()); +} + +static void AddInlineVisibilityCompileOption(std::string &flags, + cmTarget* target, + cmLocalGenerator *lg) +{ + std::string compileOption + = "CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN"; + const char *opt = lg->GetMakefile()->GetDefinition(compileOption.c_str()); + if (!opt) + { + return; + } + + bool prop = target->GetPropertyAsBool("VISIBILITY_INLINES_HIDDEN"); + if (!prop) + { + return; + } + lg->AppendFlags(flags, opt); +} + +//---------------------------------------------------------------------------- +void cmLocalGenerator +::AddVisibilityPresetFlags(std::string &flags, cmTarget* target, + const char *lang) +{ + int targetType = target->GetType(); + bool suitableTarget = ((targetType == cmTarget::SHARED_LIBRARY) + || (targetType == cmTarget::MODULE_LIBRARY) + || (target->IsExecutableWithExports())); + + if (!suitableTarget) + { + return; + } + + if (!lang) + { + return; + } + AddVisibilityCompileOption(flags, target, this, lang); + AddInlineVisibilityCompileOption(flags, target, this); +} + //---------------------------------------------------------------------------- void cmLocalGenerator::AddCMP0018Flags(std::string &flags, cmTarget* target, std::string const& lang, @@ -2011,13 +2150,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", @@ -2105,7 +2244,7 @@ void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags, for(std::vector<std::string>::const_iterator oi = options.begin(); oi != options.end(); ++oi) { - this->AppendFlags(flags, this->EscapeForShell(oi->c_str()).c_str()); + this->AppendFlagEscape(flags, oi->c_str()); } } } @@ -2143,6 +2282,13 @@ void cmLocalGenerator::AppendFlags(std::string& flags, } //---------------------------------------------------------------------------- +void cmLocalGenerator::AppendFlagEscape(std::string& flags, + const char* rawFlag) +{ + this->AppendFlags(flags, this->EscapeForShell(rawFlag).c_str()); +} + +//---------------------------------------------------------------------------- void cmLocalGenerator::AppendDefines(std::set<std::string>& defines, const char* defines_list) { @@ -2248,7 +2394,7 @@ void cmLocalGenerator::AppendFeatureOptions( for(std::vector<std::string>::const_iterator oi = options.begin(); oi != options.end(); ++oi) { - this->AppendFlags(flags, this->EscapeForShell(oi->c_str()).c_str()); + this->AppendFlagEscape(flags, oi->c_str()); } } } diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index a1c34f076d..f35ef8e2be 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -143,10 +143,13 @@ public: const char* config); void AddCMP0018Flags(std::string &flags, cmTarget* target, std::string const& lang, const char *config); + void AddVisibilityPresetFlags(std::string &flags, cmTarget* target, + const char *lang); void AddConfigVariableFlags(std::string& flags, const char* var, const char* config); ///! Append flags to a string. virtual void AppendFlags(std::string& flags, const char* newFlags); + virtual void AppendFlagEscape(std::string& flags, const char* rawFlag); ///! Get the include flags for the current makefile and language std::string GetIncludeFlags(const std::vector<std::string> &includes, const char* lang, bool forResponseFile = false, @@ -215,6 +218,8 @@ public: cmGeneratorTarget* target, const char* lang = "C", const char *config = 0, bool stripImplicitInclDirs = true); + void AddCompileOptions(std::string& flags, cmTarget* target, + const char* lang, const char* config); /** Compute the language used to compile the given source file. */ const char* GetSourceFileLanguage(const cmSourceFile& source); diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index d902f4ef7a..294a539204 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 0f680f6a15..78a70f83ec 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/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index dc94476c8a..0b61e1db5f 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -1228,7 +1228,7 @@ void cmLocalVisualStudio6Generator if(!linkLanguage) { cmSystemTools::Error - ("CMake can not determine linker language for target:", + ("CMake can not determine linker language for target: ", target.GetName()); return; } @@ -1639,9 +1639,9 @@ void cmLocalVisualStudio6Generator // store flags for each configuration std::string flags = " "; std::string flagsRelease = " "; - std::string flagsMinSize = " "; + std::string flagsMinSizeRel = " "; std::string flagsDebug = " "; - std::string flagsDebugRel = " "; + std::string flagsRelWithDebInfo = " "; if(target.GetType() >= cmTarget::EXECUTABLE && target.GetType() <= cmTarget::OBJECT_LIBRARY) { @@ -1649,7 +1649,7 @@ void cmLocalVisualStudio6Generator if(!linkLanguage) { cmSystemTools::Error - ("CMake can not determine linker language for target:", + ("CMake can not determine linker language for target: ", target.GetName()); return; } @@ -1664,16 +1664,24 @@ void cmLocalVisualStudio6Generator flagsRelease += " -DCMAKE_INTDIR=\\\"Release\\\" "; flagVar = baseFlagVar + "_MINSIZEREL"; - flagsMinSize = this->Makefile->GetSafeDefinition(flagVar.c_str()); - flagsMinSize += " -DCMAKE_INTDIR=\\\"MinSizeRel\\\" "; + flagsMinSizeRel = this->Makefile->GetSafeDefinition(flagVar.c_str()); + flagsMinSizeRel += " -DCMAKE_INTDIR=\\\"MinSizeRel\\\" "; flagVar = baseFlagVar + "_DEBUG"; flagsDebug = this->Makefile->GetSafeDefinition(flagVar.c_str()); flagsDebug += " -DCMAKE_INTDIR=\\\"Debug\\\" "; flagVar = baseFlagVar + "_RELWITHDEBINFO"; - flagsDebugRel = this->Makefile->GetSafeDefinition(flagVar.c_str()); - flagsDebugRel += " -DCMAKE_INTDIR=\\\"RelWithDebInfo\\\" "; + flagsRelWithDebInfo = this->Makefile->GetSafeDefinition(flagVar.c_str()); + flagsRelWithDebInfo += " -DCMAKE_INTDIR=\\\"RelWithDebInfo\\\" "; + + this->AddCompileOptions(flags, &target, linkLanguage, 0); + this->AddCompileOptions(flagsDebug, &target, linkLanguage, "Debug"); + this->AddCompileOptions(flagsRelease, &target, linkLanguage, "Release"); + this->AddCompileOptions(flagsMinSizeRel, &target, linkLanguage, + "MinSizeRel"); + this->AddCompileOptions(flagsRelWithDebInfo, &target, linkLanguage, + "RelWithDebInfo"); } // if _UNICODE and _SBCS are not found, then add -D_MBCS @@ -1686,13 +1694,6 @@ void cmLocalVisualStudio6Generator flags += " /D \"_MBCS\""; } - // Add per-target flags. - if(const char* targetFlags = target.GetProperty("COMPILE_FLAGS")) - { - flags += " "; - flags += targetFlags; - } - // Add per-target and per-configuration preprocessor definitions. std::set<std::string> definesSet; std::set<std::string> debugDefinesSet; @@ -1731,19 +1732,19 @@ void cmLocalVisualStudio6Generator flags += defines; flagsDebug += debugDefines; flagsRelease += releaseDefines; - flagsMinSize += minsizeDefines; - flagsDebugRel += debugrelDefines; + flagsMinSizeRel += minsizeDefines; + flagsRelWithDebInfo += debugrelDefines; // The template files have CXX FLAGS in them, that need to be replaced. // There are not separate CXX and C template files, so we use the same // variable names. The previous code sets up flags* variables to contain // the correct C or CXX flags cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_MINSIZEREL", - flagsMinSize.c_str()); + flagsMinSizeRel.c_str()); cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_DEBUG", flagsDebug.c_str()); cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_RELWITHDEBINFO", - flagsDebugRel.c_str()); + flagsRelWithDebInfo.c_str()); cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_RELEASE", flagsRelease.c_str()); cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS", flags.c_str()); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 7d0bc67edb..1d2f7095a2 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}, @@ -683,7 +686,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, if(!linkLanguage) { cmSystemTools::Error - ("CMake can not determine linker language for target:", + ("CMake can not determine linker language for target: ", target.GetName()); return; } @@ -708,6 +711,9 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, { flags += " /TP "; } + + // Add the target-specific flags. + this->AddCompileOptions(flags, &target, linkLanguage, configName); } if(this->FortranProject) @@ -720,13 +726,6 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, } } - // Add the target-specific flags. - if(const char* targetFlags = target.GetProperty("COMPILE_FLAGS")) - { - flags += " "; - flags += targetFlags; - } - // Get preprocessor definitions for this directory. std::string defineFlags = this->Makefile->GetDefineFlags(); Options::Tool t = Options::Compiler; @@ -740,6 +739,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 +837,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/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx index 551ebd30a1..7c5f69df5f 100644 --- a/Source/cmLocalXCodeGenerator.cxx +++ b/Source/cmLocalXCodeGenerator.cxx @@ -33,3 +33,12 @@ cmLocalXCodeGenerator::GetTargetDirectory(cmTarget const&) const // No per-target directory for this generator (yet). return ""; } + +//---------------------------------------------------------------------------- +void cmLocalXCodeGenerator::AppendFlagEscape(std::string& flags, + const char* rawFlag) +{ + cmGlobalXCodeGenerator* gg = + static_cast<cmGlobalXCodeGenerator*>(this->GlobalGenerator); + gg->AppendFlag(flags, rawFlag); +} diff --git a/Source/cmLocalXCodeGenerator.h b/Source/cmLocalXCodeGenerator.h index eab228f6be..d97a41cea6 100644 --- a/Source/cmLocalXCodeGenerator.h +++ b/Source/cmLocalXCodeGenerator.h @@ -28,6 +28,7 @@ public: virtual ~cmLocalXCodeGenerator(); virtual std::string GetTargetDirectory(cmTarget const& target) const; + virtual void AppendFlagEscape(std::string& flags, const char* rawFlag); private: }; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 47a6d2e66c..f3a66bab85 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -21,6 +21,7 @@ #include "cmCacheManager.h" #include "cmFunctionBlocker.h" #include "cmListFileCache.h" +#include "cmDocumentGeneratorExpressions.h" #include "cmCommandArgumentParserHelper.h" #include "cmDocumentCompileDefinitions.h" #include "cmGeneratorExpression.h" @@ -1270,6 +1271,11 @@ void cmMakefile::RemoveDefineFlag(const char* flag, } } +void cmMakefile::AddCompileOption(const char* option) +{ + this->AppendProperty("COMPILE_OPTIONS", option); +} + bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove) { // Create a regular expression to match valid definitions. @@ -1436,7 +1442,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); } } @@ -1493,6 +1499,12 @@ void cmMakefile::InitializeFromParent() parentIncludes.begin(), parentIncludes.end()); + const std::vector<cmValueWithOrigin> parentOptions = + parent->GetCompileOptionsEntries(); + this->CompileOptionsEntries.insert(this->CompileOptionsEntries.end(), + parentOptions.begin(), + parentOptions.end()); + this->SystemIncludeDirectories = parent->SystemIncludeDirectories; // define flags @@ -2086,7 +2098,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); @@ -3357,8 +3369,9 @@ int cmMakefile::ConfigureFile(const char* infile, const char* outfile, } std::string soutfile = outfile; std::string sinfile = infile; - this->AddCMakeDependFile(infile); + this->AddCMakeDependFile(sinfile); cmSystemTools::ConvertToUnixSlashes(soutfile); + this->AddCMakeOutputFile(soutfile); mode_t perm = 0; cmSystemTools::GetPermissions(sinfile.c_str(), perm); std::string::size_type pos = soutfile.rfind('/'); @@ -3468,6 +3481,18 @@ void cmMakefile::SetProperty(const char* prop, const char* value) cmValueWithOrigin(value, lfbt)); return; } + if (propname == "COMPILE_OPTIONS") + { + this->CompileOptionsEntries.clear(); + if (!value) + { + return; + } + cmListFileBacktrace lfbt; + this->GetBacktrace(lfbt); + this->CompileOptionsEntries.push_back(cmValueWithOrigin(value, lfbt)); + return; + } if ( propname == "INCLUDE_REGULAR_EXPRESSION" ) { @@ -3507,6 +3532,14 @@ void cmMakefile::AppendProperty(const char* prop, const char* value, cmValueWithOrigin(value, lfbt)); return; } + if (propname == "COMPILE_OPTIONS") + { + cmListFileBacktrace lfbt; + this->GetBacktrace(lfbt); + this->CompileOptionsEntries.push_back( + cmValueWithOrigin(value, lfbt)); + return; + } if ( propname == "LINK_DIRECTORIES" ) { std::vector<std::string> varArgsExpanded; @@ -3632,6 +3665,20 @@ const char *cmMakefile::GetProperty(const char* prop, } return output.c_str(); } + else if (!strcmp("COMPILE_OPTIONS",prop)) + { + std::string sep; + for (std::vector<cmValueWithOrigin>::const_iterator + it = this->CompileOptionsEntries.begin(), + end = this->CompileOptionsEntries.end(); + it != end; ++it) + { + output += sep; + output += it->Value; + sep = ";"; + } + return output.c_str(); + } bool chain = false; const char *retVal = @@ -3986,23 +4033,37 @@ void cmMakefile::DefineProperties(cmake *cm) ("INCLUDE_DIRECTORIES", cmProperty::DIRECTORY, "List of preprocessor include file search directories.", "This property specifies the list of directories given " - "so far to the include_directories command. " - "This property exists on directories and targets. " + "so far to the include_directories command. " + "This property exists on directories and targets. " "In addition to accepting values from the include_directories " "command, values may be set directly on any directory or any " - "target using the set_property command. " + "target using the set_property command. " "A target gets its initial value for this property from the value " - "of the directory property. " + "of the directory property. " "A directory gets its initial value from its parent directory if " - "it has one. " + "it has one. " "Both directory and target property values are adjusted by calls " "to the include_directories command." "\n" "The target property values are used by the generators to set " - "the include paths for the compiler. " + "the include paths for the compiler. " "See also the include_directories command."); cm->DefineProperty + ("COMPILE_OPTIONS", cmProperty::DIRECTORY, + "List of options to pass to the compiler.", + "This property specifies the list of directories given " + "so far for this property. " + "This property exists on directories and targets. " + "\n" + "The target property values are used by the generators to set " + "the options for the compiler.\n" + "Contents of COMPILE_OPTIONS may use \"generator expressions\" with " + "the syntax \"$<...>\". " + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS); + + cm->DefineProperty ("LINK_DIRECTORIES", cmProperty::DIRECTORY, "List of linker search directories.", "This read-only property specifies the list of directories given " @@ -4043,7 +4104,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 +4120,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/cmMakefile.h b/Source/cmMakefile.h index 74a731d5bc..42971559e7 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -206,6 +206,7 @@ public: */ void AddDefineFlag(const char* definition); void RemoveDefineFlag(const char* definition); + void AddCompileOption(const char* option); /** Create a new imported target with the name and type given. */ cmTarget* AddImportedTarget(const char* name, cmTarget::TargetType type, @@ -647,7 +648,7 @@ public: const std::vector<std::string>& GetListFiles() const { return this->ListFiles; } ///! When the file changes cmake will be re-run from the build system. - void AddCMakeDependFile(const char* file) + void AddCMakeDependFile(const std::string& file) { this->ListFiles.push_back(file);} /** @@ -665,7 +666,7 @@ public: */ const std::vector<std::string>& GetOutputFiles() const { return this->OutputFiles; } - void AddCMakeOutputFile(const char* file) + void AddCMakeOutputFile(const std::string& file) { this->OutputFiles.push_back(file);} /** @@ -866,6 +867,10 @@ public: { return this->IncludeDirectoriesEntries; } + std::vector<cmValueWithOrigin> GetCompileOptionsEntries() const + { + return this->CompileOptionsEntries; + } bool IsGeneratingBuildSystem(){ return this->GeneratingBuildSystem; } void SetGeneratingBuildSystem(){ this->GeneratingBuildSystem = true; } @@ -919,6 +924,7 @@ protected: std::string DefineFlags; std::vector<cmValueWithOrigin> IncludeDirectoriesEntries; + std::vector<cmValueWithOrigin> CompileOptionsEntries; // Track the value of the computed DEFINITIONS property. void AddDefineFlag(const char*, std::string&); diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index b7a454b17b..271183e70a 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -30,11 +30,8 @@ cmMakefileExecutableTargetGenerator this->TargetNamePDB, this->ConfigName); this->OSXBundleGenerator = new cmOSXBundleGenerator(this->Target, - this->TargetNameOut, this->ConfigName); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); - this->MacContentDirectory = - this->OSXBundleGenerator->GetMacContentDirectory(); } //---------------------------------------------------------------------------- @@ -103,11 +100,11 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Construct the full path version of the names. std::string outpath = this->Target->GetDirectory(this->ConfigName); - outpath += "/"; if(this->Target->IsAppBundleOnApple()) { this->OSXBundleGenerator->CreateAppBundle(targetName, outpath); } + outpath += "/"; std::string outpathImp; if(relink) { @@ -368,6 +365,22 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.TargetVersionMajor = targetVersionMajor.c_str(); vars.TargetVersionMinor = targetVersionMinor.c_str(); + if (const char *rootPath = + this->Makefile->GetDefinition("CMAKE_SYSROOT")) + { + if (*rootPath) + { + if (const char *sysrootFlag = + this->Makefile->GetDefinition("CMAKE_SYSROOT_FLAG")) + { + flags += " "; + flags += sysrootFlag; + flags += this->LocalGenerator->EscapeForShell(rootPath); + flags += " "; + } + } + } + vars.LinkLibraries = linkLibs.c_str(); vars.Flags = flags.c_str(); vars.LinkFlags = linkFlags.c_str(); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 5b4e4d7743..36d1a5a4ac 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -24,19 +24,14 @@ cmMakefileLibraryTargetGenerator ::cmMakefileLibraryTargetGenerator(cmTarget* target): cmMakefileTargetGenerator(target) { - cmOSXBundleGenerator::PrepareTargetProperties(this->Target); - this->CustomCommandDriver = OnDepends; this->Target->GetLibraryNames( this->TargetNameOut, this->TargetNameSO, this->TargetNameReal, this->TargetNameImport, this->TargetNamePDB, this->ConfigName); this->OSXBundleGenerator = new cmOSXBundleGenerator(this->Target, - this->TargetNameOut, this->ConfigName); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); - this->MacContentDirectory = - this->OSXBundleGenerator->GetMacContentDirectory(); } //---------------------------------------------------------------------------- @@ -292,14 +287,15 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules std::string outpathImp; if(this->Target->IsFrameworkOnApple()) { - outpath = this->MacContentDirectory; - this->OSXBundleGenerator->CreateFramework(targetName); + outpath = this->Target->GetDirectory(this->ConfigName); + this->OSXBundleGenerator->CreateFramework(targetName, outpath); + outpath += "/"; } else if(this->Target->IsCFBundleOnApple()) { outpath = this->Target->GetDirectory(this->ConfigName); - outpath += "/"; this->OSXBundleGenerator->CreateCFBundle(targetName, outpath); + outpath += "/"; } else if(relink) { @@ -593,6 +589,26 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules cmLocalGenerator::SHELL); vars.ObjectDir = objdir.c_str(); vars.Target = targetOutPathReal.c_str(); + + if(this->Target->GetType() == cmTarget::SHARED_LIBRARY) + { + if (const char *rootPath = + this->Makefile->GetSafeDefinition("CMAKE_SYSROOT")) + { + if (*rootPath) + { + if (const char *sysrootFlag = + this->Makefile->GetDefinition("CMAKE_SYSROOT_FLAG")) + { + linkFlags += " "; + linkFlags += sysrootFlag; + linkFlags += this->LocalGenerator->EscapeForShell(rootPath); + linkFlags += " "; + } + } + } + } + vars.LinkLibraries = linkLibs.c_str(); vars.ObjectsQuoted = buildObjs.c_str(); if (this->Target->HasSOName(this->ConfigName)) @@ -727,7 +743,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules commands1.clear(); // Add a rule to create necessary symlinks for the library. - if(targetOutPath != targetOutPathReal) + // Frameworks are handled by cmOSXBundleGenerator. + if(targetOutPath != targetOutPathReal && !this->Target->IsFrameworkOnApple()) { std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_library "; symlink += targetOutPathReal; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 4220ae1486..1492dfabeb 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -271,6 +271,9 @@ std::string cmMakefileTargetGenerator::GetFlags(const std::string &l) this->LocalGenerator->AddCMP0018Flags(flags, this->Target, lang, this->ConfigName); + this->LocalGenerator->AddVisibilityPresetFlags(flags, this->Target, + lang); + // Add include directory flags. this->AddIncludeFlags(flags, lang); @@ -282,6 +285,10 @@ std::string cmMakefileTargetGenerator::GetFlags(const std::string &l) this->LocalGenerator-> AppendFlags(flags,this->GetFrameworkFlags().c_str()); + // Add target-specific flags. + this->LocalGenerator->AddCompileOptions(flags, this->Target, + lang, this->ConfigName); + ByLanguageMap::value_type entry(l, flags); i = this->FlagsByLanguage.insert(entry).first; } @@ -339,15 +346,6 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() *this->FlagFileStream << *l << "_DEFINES = " << this->GetDefines(*l) << "\n\n"; } - - // Add target-specific flags. - if(this->Target->GetProperty("COMPILE_FLAGS")) - { - std::string flags; - this->LocalGenerator->AppendFlags - (flags, this->Target->GetProperty("COMPILE_FLAGS")); - *this->FlagFileStream << "# TARGET_FLAGS = " << flags << "\n\n"; - } } @@ -357,7 +355,7 @@ cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator() (cmSourceFile& source, const char* pkgloc) { // Skip OS X content when not building a Framework or Bundle. - if(this->Generator->MacContentDirectory.empty()) + if(!this->Generator->GetTarget()->IsBundleOnApple()) { return; } @@ -532,37 +530,8 @@ cmMakefileTargetGenerator langFlags += "_FLAGS)"; this->LocalGenerator->AppendFlags(flags, langFlags.c_str()); - // Add target-specific flags. - if(this->Target->GetProperty("COMPILE_FLAGS")) - { - std::string langIncludeExpr = "CMAKE_"; - langIncludeExpr += lang; - langIncludeExpr += "_FLAG_REGEX"; - const char* regex = this->Makefile-> - GetDefinition(langIncludeExpr.c_str()); - if(regex) - { - cmsys::RegularExpression r(regex); - std::vector<std::string> args; - cmSystemTools::ParseWindowsCommandLine( - this->Target->GetProperty("COMPILE_FLAGS"), - args); - for(std::vector<std::string>::iterator i = args.begin(); - i != args.end(); ++i) - { - if(r.find(i->c_str())) - { - this->LocalGenerator->AppendFlags - (flags, i->c_str()); - } - } - } - else - { - this->LocalGenerator->AppendFlags - (flags, this->Target->GetProperty("COMPILE_FLAGS")); - } - } + std::string configUpper = + cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName); // Add Fortran format flags. if(strcmp(lang, "Fortran") == 0) @@ -594,8 +563,6 @@ cmMakefileTargetGenerator << compile_defs << "\n" << "\n"; } - std::string configUpper = - cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName); std::string defPropName = "COMPILE_DEFINITIONS_"; defPropName += configUpper; if(const char* config_compile_defs = @@ -677,6 +644,23 @@ cmMakefileTargetGenerator cmLocalGenerator::START_OUTPUT, cmLocalGenerator::SHELL); vars.ObjectDir = objectDir.c_str(); + + if (const char *rootPath = + this->Makefile->GetSafeDefinition("CMAKE_SYSROOT")) + { + if (*rootPath) + { + if (const char *sysrootFlag = + this->Makefile->GetDefinition("CMAKE_SYSROOT_FLAG")) + { + flags += " "; + flags += sysrootFlag; + flags += this->LocalGenerator->EscapeForShell(rootPath); + flags += " "; + } + } + } + vars.Flags = flags.c_str(); std::string definesString = "$("; diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 2798e5462c..f7a1e2e56a 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -233,7 +233,6 @@ protected: std::string TargetNamePDB; // Mac OS X content info. - std::string MacContentDirectory; std::set<cmStdString> MacContentFolders; cmOSXBundleGenerator* OSXBundleGenerator; MacOSXContentGeneratorType* MacOSXContentGenerator; diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx index 4456aa7946..1fa4e95b6f 100644 --- a/Source/cmMakefileUtilityTargetGenerator.cxx +++ b/Source/cmMakefileUtilityTargetGenerator.cxx @@ -25,11 +25,8 @@ cmMakefileUtilityTargetGenerator { this->CustomCommandDriver = OnUtility; this->OSXBundleGenerator = new cmOSXBundleGenerator(this->Target, - this->TargetNameOut, this->ConfigName); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); - this->MacContentDirectory = - this->OSXBundleGenerator->GetMacContentDirectory(); } //---------------------------------------------------------------------------- diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 7e48cd716e..6d352ed843 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -36,8 +36,6 @@ cmNinjaNormalTargetGenerator(cmTarget* target) , TargetNamePDB() , TargetLinkLanguage(0) { - cmOSXBundleGenerator::PrepareTargetProperties(target); - this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName()); if (target->GetType() == cmTarget::EXECUTABLE) target->GetExecutableNames(this->TargetNameOut, @@ -61,7 +59,6 @@ cmNinjaNormalTargetGenerator(cmTarget* target) } this->OSXBundleGenerator = new cmOSXBundleGenerator(target, - this->TargetNameOut, this->GetConfigName()); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); } @@ -74,7 +71,8 @@ cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator() void cmNinjaNormalTargetGenerator::Generate() { if (!this->TargetLinkLanguage) { - cmSystemTools::Error("CMake can not determine linker language for target:", + cmSystemTools::Error("CMake can not determine linker language for " + "target: ", this->GetTarget()->GetName()); return; } @@ -226,7 +224,27 @@ cmNinjaNormalTargetGenerator vars.TargetVersionMajor = targetVersionMajor.c_str(); vars.TargetVersionMinor = targetVersionMinor.c_str(); - vars.Flags = "$FLAGS"; + + std::string flags = "$FLAGS"; + + if (const char *rootPath = + this->GetMakefile()->GetSafeDefinition("CMAKE_SYSROOT")) + { + if (*rootPath) + { + if (const char *sysrootFlag = + this->GetMakefile()->GetDefinition("CMAKE_SYSROOT_FLAG")) + { + flags += " "; + flags += sysrootFlag; + flags += this->GetLocalGenerator()->EscapeForShell(rootPath); + flags += " "; + } + } + } + + vars.Flags = flags.c_str(); + vars.LinkFlags = "$LINK_FLAGS"; std::string langFlags; @@ -383,24 +401,32 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() if (this->GetTarget()->IsAppBundleOnApple()) { // Create the app bundle - std::string outpath; + std::string outpath = + this->GetTarget()->GetDirectory(this->GetConfigName()); this->OSXBundleGenerator->CreateAppBundle(this->TargetNameOut, outpath); // Calculate the output path - targetOutput = outpath + this->TargetNameOut; + targetOutput = outpath; + targetOutput += "/"; + targetOutput += this->TargetNameOut; targetOutput = this->ConvertToNinjaPath(targetOutput.c_str()); - targetOutputReal = outpath + this->TargetNameReal; + targetOutputReal = outpath; + targetOutputReal += "/"; + targetOutputReal += this->TargetNameReal; targetOutputReal = this->ConvertToNinjaPath(targetOutputReal.c_str()); } else if (this->GetTarget()->IsFrameworkOnApple()) { // Create the library framework. - this->OSXBundleGenerator->CreateFramework(this->TargetNameOut); + std::string outpath = + this->GetTarget()->GetDirectory(this->GetConfigName()); + this->OSXBundleGenerator->CreateFramework(this->TargetNameOut, outpath); } else if(this->GetTarget()->IsCFBundleOnApple()) { // Create the core foundation bundle. - std::string outpath; + std::string outpath = + this->GetTarget()->GetDirectory(this->GetConfigName()); this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut, outpath); } @@ -505,7 +531,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 3fb823cb03..3fce7cd0da 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -150,10 +150,13 @@ cmNinjaTargetGenerator::ComputeFlagsForObject(cmSourceFile *source, language.c_str(), this->GetConfigName()); + this->LocalGenerator->AddVisibilityPresetFlags(flags, this->Target, + language.c_str()); + // Add include directory flags. + const char *config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); { std::vector<std::string> includes; - const char *config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, language.c_str(), config); @@ -171,36 +174,8 @@ cmNinjaTargetGenerator::ComputeFlagsForObject(cmSourceFile *source, this->LocalGenerator->AppendFlags(flags, this->Makefile->GetDefineFlags()); // Add target-specific flags. - if(this->Target->GetProperty("COMPILE_FLAGS")) - { - std::string langIncludeExpr = "CMAKE_"; - langIncludeExpr += language; - langIncludeExpr += "_FLAG_REGEX"; - const char* regex = this->Makefile-> - GetDefinition(langIncludeExpr.c_str()); - if(regex) - { - cmsys::RegularExpression r(regex); - std::vector<std::string> args; - cmSystemTools::ParseWindowsCommandLine( - this->Target->GetProperty("COMPILE_FLAGS"), - args); - for(std::vector<std::string>::iterator i = args.begin(); - i != args.end(); ++i) - { - if(r.find(i->c_str())) - { - this->LocalGenerator->AppendFlags - (flags, i->c_str()); - } - } - } - else - { - this->LocalGenerator->AppendFlags - (flags, this->Target->GetProperty("COMPILE_FLAGS")); - } - } + this->LocalGenerator->AddCompileOptions(flags, this->Target, + language.c_str(), config); // Add source file specific flags. this->LocalGenerator->AppendFlags(flags, @@ -409,7 +384,23 @@ cmNinjaTargetGenerator cmSystemTools::ReplaceString(depFlagsStr, "<CMAKE_C_COMPILER>", mf->GetDefinition("CMAKE_C_COMPILER")); flags += " " + depFlagsStr; - } + + if (const char *rootPath = + this->Makefile->GetSafeDefinition("CMAKE_SYSROOT")) + { + if (*rootPath) + { + if (const char *sysrootFlag = + this->Makefile->GetDefinition("CMAKE_SYSROOT_FLAG")) + { + flags += " "; + flags += sysrootFlag; + flags += this->LocalGenerator->EscapeForShell(rootPath); + flags += " "; + } + } + } + } vars.Flags = flags.c_str(); @@ -569,11 +560,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); @@ -701,7 +690,7 @@ cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()( cmSourceFile& source, const char* pkgloc) { // Skip OS X content when not building a Framework or Bundle. - if(this->Generator->OSXBundleGenerator->GetMacContentDirectory().empty()) + if(!this->Generator->GetTarget()->IsBundleOnApple()) { return; } diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx index 42fad07426..a475c7cfa7 100644 --- a/Source/cmOSXBundleGenerator.cxx +++ b/Source/cmOSXBundleGenerator.cxx @@ -16,38 +16,19 @@ #include <cassert> -void cmOSXBundleGenerator::PrepareTargetProperties(cmTarget* target) -{ - if(target->IsCFBundleOnApple()) - { - target->SetProperty("PREFIX", ""); - target->SetProperty("SUFFIX", ""); - } -} - //---------------------------------------------------------------------------- cmOSXBundleGenerator:: cmOSXBundleGenerator(cmTarget* target, - std::string targetNameOut, const char* configName) : Target(target) , Makefile(target->GetMakefile()) , LocalGenerator(Makefile->GetLocalGenerator()) - , TargetNameOut(targetNameOut) , ConfigName(configName) - , MacContentDirectory() - , FrameworkVersion() , MacContentFolders(0) { if (this->MustSkip()) return; - this->MacContentDirectory = - this->Target->GetMacContentDirectory(this->ConfigName, - /*implib*/ false, - /*includeMacOS*/ false); - if(this->Target->IsFrameworkOnApple()) - this->FrameworkVersion = this->Target->GetFrameworkVersion(); } //---------------------------------------------------------------------------- @@ -57,41 +38,60 @@ bool cmOSXBundleGenerator::MustSkip() } //---------------------------------------------------------------------------- -void cmOSXBundleGenerator::CreateAppBundle(std::string& targetName, +void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, std::string& outpath) { if (this->MustSkip()) return; // Compute bundle directory names. - outpath = this->MacContentDirectory; - outpath += "MacOS"; - cmSystemTools::MakeDirectory(outpath.c_str()); - outpath += "/"; - this->Makefile->AddCMakeOutputFile(outpath.c_str()); + std::string out = outpath; + out += "/"; + out += this->Target->GetAppBundleDirectory(this->ConfigName, false); + cmSystemTools::MakeDirectory(out.c_str()); + this->Makefile->AddCMakeOutputFile(out); + + std::string newoutpath = out; // Configure the Info.plist file. Note that it needs the executable name // to be set. - std::string plist = this->MacContentDirectory + "Info.plist"; + std::string plist = outpath; + plist += "/"; + plist += this->Target->GetAppBundleDirectory(this->ConfigName, true); + plist += "/Info.plist"; this->LocalGenerator->GenerateAppleInfoPList(this->Target, targetName.c_str(), plist.c_str()); - this->Makefile->AddCMakeOutputFile(plist.c_str()); + this->Makefile->AddCMakeOutputFile(plist); + outpath = newoutpath; } //---------------------------------------------------------------------------- -void cmOSXBundleGenerator::CreateFramework(std::string const& targetName) +void cmOSXBundleGenerator::CreateFramework( + const std::string& targetName, const std::string& outpath) { if (this->MustSkip()) return; assert(this->MacContentFolders); + // Compute the location of the top-level foo.framework directory. + std::string contentdir = outpath + "/" + + this->Target->GetFrameworkDirectory(this->ConfigName, true); + contentdir += "/"; + + std::string newoutpath = outpath + "/" + + this->Target->GetFrameworkDirectory(this->ConfigName, false); + + std::string frameworkVersion = this->Target->GetFrameworkVersion(); + // Configure the Info.plist file into the Resources directory. this->MacContentFolders->insert("Resources"); - std::string plist = this->MacContentDirectory + "Resources/Info.plist"; + std::string plist = newoutpath; + plist += "/Resources/Info.plist"; + std::string name = cmSystemTools::GetFilenameName(targetName); this->LocalGenerator->GenerateFrameworkInfoPList(this->Target, - targetName.c_str(), + name.c_str(), plist.c_str()); // TODO: Use the cmMakefileTargetGenerator::ExtraFiles vector to @@ -99,50 +99,42 @@ void cmOSXBundleGenerator::CreateFramework(std::string const& targetName) std::string oldName; std::string newName; - // Compute the location of the top-level foo.framework directory. - std::string top = this->Target->GetDirectory(this->ConfigName); - top += "/"; - top += this->TargetNameOut; - top += ".framework/"; // Make foo.framework/Versions - std::string versions = top; + std::string versions = contentdir; versions += "Versions"; cmSystemTools::MakeDirectory(versions.c_str()); // Make foo.framework/Versions/version - std::string version = versions; - version += "/"; - version += this->FrameworkVersion; - cmSystemTools::MakeDirectory(version.c_str()); + cmSystemTools::MakeDirectory(newoutpath.c_str()); // Current -> version - oldName = this->FrameworkVersion; + oldName = frameworkVersion; newName = versions; newName += "/Current"; cmSystemTools::RemoveFile(newName.c_str()); cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str()); - this->Makefile->AddCMakeOutputFile(newName.c_str()); + this->Makefile->AddCMakeOutputFile(newName); // foo -> Versions/Current/foo oldName = "Versions/Current/"; - oldName += this->TargetNameOut; - newName = top; - newName += this->TargetNameOut; + oldName += name; + newName = contentdir; + newName += name; cmSystemTools::RemoveFile(newName.c_str()); cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str()); - this->Makefile->AddCMakeOutputFile(newName.c_str()); + this->Makefile->AddCMakeOutputFile(newName); // Resources -> Versions/Current/Resources if(this->MacContentFolders->find("Resources") != this->MacContentFolders->end()) { oldName = "Versions/Current/Resources"; - newName = top; + newName = contentdir; newName += "Resources"; cmSystemTools::RemoveFile(newName.c_str()); cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str()); - this->Makefile->AddCMakeOutputFile(newName.c_str()); + this->Makefile->AddCMakeOutputFile(newName); } // Headers -> Versions/Current/Headers @@ -150,11 +142,11 @@ void cmOSXBundleGenerator::CreateFramework(std::string const& targetName) this->MacContentFolders->end()) { oldName = "Versions/Current/Headers"; - newName = top; + newName = contentdir; newName += "Headers"; cmSystemTools::RemoveFile(newName.c_str()); cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str()); - this->Makefile->AddCMakeOutputFile(newName.c_str()); + this->Makefile->AddCMakeOutputFile(newName); } // PrivateHeaders -> Versions/Current/PrivateHeaders @@ -162,36 +154,37 @@ void cmOSXBundleGenerator::CreateFramework(std::string const& targetName) this->MacContentFolders->end()) { oldName = "Versions/Current/PrivateHeaders"; - newName = top; + newName = contentdir; newName += "PrivateHeaders"; cmSystemTools::RemoveFile(newName.c_str()); cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str()); - this->Makefile->AddCMakeOutputFile(newName.c_str()); + this->Makefile->AddCMakeOutputFile(newName); } } //---------------------------------------------------------------------------- -void cmOSXBundleGenerator::CreateCFBundle(std::string& targetName, - std::string& outpath) +void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName, + const std::string& root) { if (this->MustSkip()) return; // Compute bundle directory names. - outpath = this->MacContentDirectory; - outpath += "MacOS"; - cmSystemTools::MakeDirectory(outpath.c_str()); - outpath += "/"; - this->Makefile->AddCMakeOutputFile(outpath.c_str()); + std::string out = root; + out += "/"; + out += this->Target->GetCFBundleDirectory(this->ConfigName, false); + cmSystemTools::MakeDirectory(out.c_str()); + this->Makefile->AddCMakeOutputFile(out); // Configure the Info.plist file. Note that it needs the executable name // to be set. - std::string plist = this->MacContentDirectory; - plist += "Info.plist"; + std::string plist = + this->Target->GetCFBundleDirectory(this->ConfigName, true); + plist += "/Info.plist"; this->LocalGenerator->GenerateAppleInfoPList(this->Target, targetName.c_str(), plist.c_str()); - this->Makefile->AddCMakeOutputFile(plist.c_str()); + this->Makefile->AddCMakeOutputFile(plist); } //---------------------------------------------------------------------------- @@ -220,7 +213,11 @@ std::string cmOSXBundleGenerator::InitMacOSXContentDirectory(const char* pkgloc) { // Construct the full path to the content subdirectory. - std::string macdir = this->MacContentDirectory; + + std::string macdir = + this->Target->GetMacContentDirectory(this->ConfigName, + /*implib*/ false); + macdir += "/"; macdir += pkgloc; cmSystemTools::MakeDirectory(macdir.c_str()); diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h index 01e3cbeb43..ec82b9a159 100644 --- a/Source/cmOSXBundleGenerator.h +++ b/Source/cmOSXBundleGenerator.h @@ -25,15 +25,20 @@ class cmLocalGenerator; class cmOSXBundleGenerator { public: - static void PrepareTargetProperties(cmTarget* target); - cmOSXBundleGenerator(cmTarget* target, - std::string targetNameOut, const char* configName); - void CreateAppBundle(std::string& targetName, std::string& outpath); - void CreateFramework(std::string const& targetName); - void CreateCFBundle(std::string& targetName, std::string& outpath); + // create an app bundle at a given root, and return + // the directory within the bundle that contains the executable + void CreateAppBundle(const std::string& targetName, std::string& root); + + // create a framework at a given root + void CreateFramework(const std::string& targetName, + const std::string& root); + + // create a cf bundle at a given root + void CreateCFBundle(const std::string& targetName, + const std::string& root); struct MacOSXContentGeneratorType { @@ -46,10 +51,6 @@ public: MacOSXContentGeneratorType* generator); std::string InitMacOSXContentDirectory(const char* pkgloc); - std::string GetMacContentDirectory() const - { return this->MacContentDirectory; } - std::string GetFrameworkVersion() const - { return this->FrameworkVersion; } void SetMacContentFolders(std::set<cmStdString>* macContentFolders) { this->MacContentFolders = macContentFolders; } @@ -60,10 +61,7 @@ private: cmTarget* Target; cmMakefile* Makefile; cmLocalGenerator* LocalGenerator; - std::string TargetNameOut; const char* ConfigName; - std::string MacContentDirectory; - std::string FrameworkVersion; std::set<cmStdString>* MacContentFolders; }; diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx index 6e41768b09..93885b2f65 100644 --- a/Source/cmOrderDirectories.cxx +++ b/Source/cmOrderDirectories.cxx @@ -36,8 +36,25 @@ public: OD(od), GlobalGenerator(od->GlobalGenerator) { this->FullPath = file; - this->Directory = cmSystemTools::GetFilenamePath(file); - this->FileName = cmSystemTools::GetFilenameName(file); + + if(file.rfind(".framework") != std::string::npos) + { + cmsys::RegularExpression splitFramework; + splitFramework.compile("^(.*)/(.*).framework/.*/(.*)$"); + if(splitFramework.find(file) && + (splitFramework.match(2) == splitFramework.match(3))) + { + this->Directory = splitFramework.match(1); + this->FileName = + std::string(file.begin() + this->Directory.size() + 1, file.end()); + } + } + + if(this->FileName.empty()) + { + this->Directory = cmSystemTools::GetFilenamePath(file); + this->FileName = cmSystemTools::GetFilenameName(file); + } } virtual ~cmOrderDirectoriesConstraint() {} @@ -301,22 +318,42 @@ void cmOrderDirectories::AddRuntimeLibrary(std::string const& fullPath, // Add the runtime library at most once. if(this->EmmittedConstraintSOName.insert(fullPath).second) { + std::string soname2 = soname ? soname : ""; // Implicit link directories need special handling. if(!this->ImplicitDirectories.empty()) { std::string dir = cmSystemTools::GetFilenamePath(fullPath); + + if(fullPath.rfind(".framework") != std::string::npos) + { + cmsys::RegularExpression splitFramework; + splitFramework.compile("^(.*)/(.*).framework/(.*)/(.*)$"); + if(splitFramework.find(fullPath) && + (splitFramework.match(2) == splitFramework.match(4))) + { + dir = splitFramework.match(1); + soname2 = splitFramework.match(2); + soname2 += ".framework/"; + soname2 += splitFramework.match(3); + soname2 += "/"; + soname2 += splitFramework.match(4); + } + } + if(this->ImplicitDirectories.find(dir) != this->ImplicitDirectories.end()) { this->ImplicitDirEntries.push_back( - new cmOrderDirectoriesConstraintSOName(this, fullPath, soname)); + new cmOrderDirectoriesConstraintSOName(this, fullPath, + soname2.c_str())); return; } } // Construct the runtime information entry for this library. this->ConstraintEntries.push_back( - new cmOrderDirectoriesConstraintSOName(this, fullPath, soname)); + new cmOrderDirectoriesConstraintSOName(this, fullPath, + soname2.c_str())); } else { diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 831e92e925..32829a617b 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 c11af07140..a033e879b2 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 a1fa31f2a7..05c43c4b39 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -152,10 +152,44 @@ bool cmQtAutomoc::InitializeMocSourceFile(cmTarget* target) return true; } -void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) +static void GetCompileDefinitionsAndDirectories(cmTarget *target, + const char * config, + std::string &incs, + std::string &defs) { cmMakefile* makefile = target->GetMakefile(); cmLocalGenerator* localGen = makefile->GetLocalGenerator(); + std::vector<std::string> includeDirs; + cmGeneratorTarget gtgt(target); + // Get the include dirs for this target, without stripping the implicit + // include dirs off, see http://public.kitware.com/Bug/view.php?id=13667 + localGen->GetIncludeDirectories(includeDirs, >gt, "CXX", config, false); + const char* sep = ""; + incs = ""; + for(std::vector<std::string>::const_iterator incDirIt = includeDirs.begin(); + incDirIt != includeDirs.end(); + ++incDirIt) + { + incs += sep; + sep = ";"; + incs += *incDirIt; + } + + defs = target->GetCompileDefinitions(config); + + const char *tmp = makefile->GetProperty("COMPILE_DEFINITIONS"); + sep = ""; + if (tmp) + { + defs += sep; + sep = ";"; + defs += tmp; + } +} + +void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) +{ + cmMakefile* makefile = target->GetMakefile(); const char* targetName = target->GetName(); bool relaxedMode = makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE"); @@ -175,6 +209,7 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) currentLine.push_back("-E"); currentLine.push_back("cmake_automoc"); currentLine.push_back(targetDir); + currentLine.push_back("$<CONFIGURATION>"); cmCustomCommandLines commandLines; commandLines.push_back(currentLine); @@ -188,6 +223,7 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) #if defined(_WIN32) && !defined(__CYGWIN__) bool usePRE_BUILD = false; + cmLocalGenerator* localGen = makefile->GetLocalGenerator(); cmGlobalGenerator* gg = localGen->GetGlobalGenerator(); if(strstr(gg->GetName(), "Visual Studio")) { @@ -263,36 +299,7 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) } } - - std::vector<std::string> includeDirs; - cmGeneratorTarget gtgt(target); - // Get the include dirs for this target, without stripping the implicit - // include dirs off, see http://public.kitware.com/Bug/view.php?id=13667 - localGen->GetIncludeDirectories(includeDirs, >gt, "CXX", 0, false); - std::string _moc_incs = ""; - const char* sep = ""; - for(std::vector<std::string>::const_iterator incDirIt = includeDirs.begin(); - incDirIt != includeDirs.end(); - ++incDirIt) - { - _moc_incs += sep; - sep = ";"; - _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"); - if (tmp) - { - _moc_compile_defs += ";"; - _moc_compile_defs += tmp; - } - tmp = target->GetProperty("AUTOMOC_MOC_OPTIONS"); + const char* tmp = target->GetProperty("AUTOMOC_MOC_OPTIONS"); std::string _moc_options = (tmp!=0 ? tmp : ""); // forget the variables added here afterwards again: @@ -301,10 +308,6 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) makefile->AddDefinition("_moc_target_name", cmLocalGenerator::EscapeForCMake(automocTargetName.c_str()).c_str()); - makefile->AddDefinition("_moc_incs", - cmLocalGenerator::EscapeForCMake(_moc_incs.c_str()).c_str()); - makefile->AddDefinition("_moc_compile_defs", - cmLocalGenerator::EscapeForCMake(_moc_compile_defs.c_str()).c_str()); makefile->AddDefinition("_moc_options", cmLocalGenerator::EscapeForCMake(_moc_options.c_str()).c_str()); makefile->AddDefinition("_moc_files", @@ -313,6 +316,89 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) cmLocalGenerator::EscapeForCMake(_moc_headers.c_str()).c_str()); makefile->AddDefinition("_moc_relaxed_mode", relaxedMode ? "TRUE" : "FALSE"); + std::string _moc_incs; + std::string _moc_compile_defs; + std::vector<std::string> configs; + const char *config = makefile->GetConfigurations(configs); + GetCompileDefinitionsAndDirectories(target, config, + _moc_incs, _moc_compile_defs); + + makefile->AddDefinition("_moc_incs", + cmLocalGenerator::EscapeForCMake(_moc_incs.c_str()).c_str()); + makefile->AddDefinition("_moc_compile_defs", + cmLocalGenerator::EscapeForCMake(_moc_compile_defs.c_str()).c_str()); + + std::map<std::string, std::string> configIncludes; + std::map<std::string, std::string> configDefines; + + for (std::vector<std::string>::const_iterator li = configs.begin(); + li != configs.end(); ++li) + { + std::string config_moc_incs; + std::string config_moc_compile_defs; + GetCompileDefinitionsAndDirectories(target, li->c_str(), + config_moc_incs, + config_moc_compile_defs); + if (config_moc_incs != _moc_incs) + { + configIncludes["_moc_incs_" + *li] = + cmLocalGenerator::EscapeForCMake(config_moc_incs.c_str()); + if(_moc_incs.empty()) + { + _moc_incs = config_moc_incs; + } + } + if (config_moc_compile_defs != _moc_compile_defs) + { + configDefines["_moc_compile_defs_" + *li] = + cmLocalGenerator::EscapeForCMake(config_moc_compile_defs.c_str()); + if(_moc_compile_defs.empty()) + { + _moc_compile_defs = config_moc_compile_defs; + } + } + } + + const char *qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR"); + if (!qtVersion) + { + qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR"); + } + if (const char *targetQtVersion = + target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", 0)) + { + qtVersion = targetQtVersion; + } + if (qtVersion) + { + makefile->AddDefinition("_target_qt_version", qtVersion); + } + + { + const char *qtMoc = makefile->GetSafeDefinition("QT_MOC_EXECUTABLE"); + makefile->AddDefinition("_qt_moc_executable", qtMoc); + } + + if (strcmp(qtVersion, "5") == 0) + { + cmTarget *qt5Moc = makefile->FindTargetToUse("Qt5::moc"); + if (!qt5Moc) + { + cmSystemTools::Error("Qt5::moc target not found ", + automocTargetName.c_str()); + return; + } + makefile->AddDefinition("_qt_moc_executable", qt5Moc->GetLocation(0)); + } + else + { + if (strcmp(qtVersion, "4") != 0) + { + cmSystemTools::Error("The CMAKE_AUTOMOC feature supports only Qt 4 and " + "Qt 5 ", automocTargetName.c_str()); + } + } + const char* cmakeRoot = makefile->GetSafeDefinition("CMAKE_ROOT"); std::string inputFile = cmakeRoot; inputFile += "/Modules/AutomocInfo.cmake.in"; @@ -320,17 +406,50 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) outputFile += "/AutomocInfo.cmake"; makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(), false, true, false); + + if (!configDefines.empty() || !configIncludes.empty()) + { + std::ofstream infoFile(outputFile.c_str(), std::ios::app); + if ( !infoFile ) + { + std::string error = "Internal CMake error when trying to open file: "; + error += outputFile.c_str(); + error += " for writing."; + cmSystemTools::Error(error.c_str()); + return; + } + if (!configDefines.empty()) + { + for (std::map<std::string, std::string>::iterator + it = configDefines.begin(), end = configDefines.end(); + it != end; ++it) + { + infoFile << "SET(AM_MOC_COMPILE_DEFINITIONS_" << it->first << + " " << it->second << ")\n"; + } + } + if (!configIncludes.empty()) + { + for (std::map<std::string, std::string>::iterator + it = configIncludes.begin(), end = configIncludes.end(); + it != end; ++it) + { + infoFile << "SET(AM_MOC_INCLUDES_" << it->first << + " " << it->second << ")\n"; + } + } + } } -bool cmQtAutomoc::Run(const char* targetDirectory) +bool cmQtAutomoc::Run(const char* targetDirectory, const char *config) { bool success = true; cmake cm; cmGlobalGenerator* gg = this->CreateGlobalGenerator(&cm, targetDirectory); cmMakefile* makefile = gg->GetCurrentLocalGenerator()->GetMakefile(); - this->ReadAutomocInfoFile(makefile, targetDirectory); + this->ReadAutomocInfoFile(makefile, targetDirectory, config); this->ReadOldMocDefinitionsFile(makefile, targetDirectory); this->Init(); @@ -367,7 +486,8 @@ cmGlobalGenerator* cmQtAutomoc::CreateGlobalGenerator(cmake* cm, bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile, - const char* targetDirectory) + const char* targetDirectory, + const char *config) { std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); cmSystemTools::ConvertToUnixSlashes(filename); @@ -375,7 +495,7 @@ bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile, if (!makefile->ReadListFile(0, filename.c_str())) { - cmSystemTools::Error("Error processing file:", filename.c_str()); + cmSystemTools::Error("Error processing file: ", filename.c_str()); return false; } @@ -392,9 +512,26 @@ bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile, this->Srcdir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR"); this->Builddir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_BINARY_DIR"); this->MocExecutable = makefile->GetSafeDefinition("AM_QT_MOC_EXECUTABLE"); - this->MocCompileDefinitionsStr = makefile->GetSafeDefinition( - "AM_MOC_COMPILE_DEFINITIONS"); - this->MocIncludesStr = makefile->GetSafeDefinition("AM_MOC_INCLUDES"); + std::string compileDefsPropOrig = "AM_MOC_COMPILE_DEFINITIONS"; + std::string compileDefsProp = compileDefsPropOrig; + if(config) + { + compileDefsProp += "_"; + compileDefsProp += config; + } + const char *compileDefs = makefile->GetDefinition(compileDefsProp.c_str()); + this->MocCompileDefinitionsStr = compileDefs ? compileDefs + : makefile->GetSafeDefinition(compileDefsPropOrig.c_str()); + std::string includesPropOrig = "AM_MOC_INCLUDES"; + std::string includesProp = includesPropOrig; + if(config) + { + includesProp += "_"; + includesProp += config; + } + const char *includes = makefile->GetDefinition(includesProp.c_str()); + this->MocIncludesStr = includes ? includes + : makefile->GetSafeDefinition(includesPropOrig.c_str()); this->MocOptionsStr = makefile->GetSafeDefinition("AM_MOC_OPTIONS"); this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR"); this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR"); @@ -696,7 +833,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 +1007,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/cmQtAutomoc.h b/Source/cmQtAutomoc.h index 01b68fc54a..ebeeb0eeee 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -21,7 +21,7 @@ class cmQtAutomoc { public: cmQtAutomoc(); - bool Run(const char* targetDirectory); + bool Run(const char* targetDirectory, const char *config); bool InitializeMocSourceFile(cmTarget* target); void SetupAutomocTarget(cmTarget* target); @@ -31,7 +31,8 @@ private: const char* targetDirectory); bool ReadAutomocInfoFile(cmMakefile* makefile, - const char* targetDirectory); + const char* targetDirectory, + const char *config); bool ReadOldMocDefinitionsFile(cmMakefile* makefile, const char* targetDirectory); void WriteOldMocDefinitionsFile(const char* targetDirectory); diff --git a/Source/cmSetTargetPropertiesCommand.h b/Source/cmSetTargetPropertiesCommand.h index 9dd7848d35..cf9c19350c 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 1d4b0c8b40..8bb7d96f50 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 e49edd8788..68ba13f625 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()); @@ -530,8 +534,12 @@ void cmStringCommand::ClearMatches(cmMakefile* mf) { char name[128]; sprintf(name, "CMAKE_MATCH_%d", i); - mf->AddDefinition(name, ""); - mf->MarkVariableAsUsed(name); + const char* s = mf->GetDefinition(name); + if(s && *s != 0) + { + mf->AddDefinition(name, ""); + mf->MarkVariableAsUsed(name); + } } } @@ -540,10 +548,14 @@ void cmStringCommand::StoreMatches(cmMakefile* mf,cmsys::RegularExpression& re) { for (unsigned int i=0; i<10; i++) { - char name[128]; - sprintf(name, "CMAKE_MATCH_%d", i); - mf->AddDefinition(name, re.match(i).c_str()); - mf->MarkVariableAsUsed(name); + std::string m = re.match(i); + if(m.size() > 0) + { + char name[128]; + sprintf(name, "CMAKE_MATCH_%d", i); + mf->AddDefinition(name, re.match(i).c_str()); + mf->MarkVariableAsUsed(name); + } } } @@ -755,6 +767,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 802e0b8500..f584cfdbf0 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 0cfe7722da..e497b4642d 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.cxx b/Source/cmSystemTools.cxx index 67f3023911..4ae16cca8d 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1951,7 +1951,7 @@ bool extract_tar(const char* outFileName, bool verbose, { cmSystemTools::Error("Problem with archive_write_header(): ", archive_error_string(ext)); - cmSystemTools::Error("Current file:", + cmSystemTools::Error("Current file: ", archive_entry_pathname(entry)); break; } @@ -2413,6 +2413,30 @@ bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath, } //---------------------------------------------------------------------------- +bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath, + std::string& soname) +{ + std::vector<cmStdString> cmds; + cmds.push_back("otool"); + cmds.push_back("-D"); + cmds.push_back(fullPath.c_str()); + + std::string output; + RunSingleCommand(cmds, &output, 0, 0, OUTPUT_NONE); + + std::vector<std::string> strs = cmSystemTools::tokenize(output, "\n"); + // otool returns extra lines reporting multiple install names + // in case the binary is multi-arch and none of the architectures + // is native (e.g. i386;ppc on x86_64) + if(strs.size() >= 2) + { + soname = strs[1]; + return true; + } + return false; +} + +//---------------------------------------------------------------------------- #if defined(CMAKE_USE_ELF_PARSER) std::string::size_type cmSystemToolsFindRPath(std::string const& have, std::string const& want) @@ -2659,13 +2683,18 @@ bool cmSystemTools::ChangeRPath(std::string const& file, bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, const char* lhss, const char* rhss) { - unsigned int lhs[4] = {0,0,0,0}; - unsigned int rhs[4] = {0,0,0,0}; - sscanf(lhss, "%u.%u.%u.%u", &lhs[0], &lhs[1], &lhs[2], &lhs[3]); - sscanf(rhss, "%u.%u.%u.%u", &rhs[0], &rhs[1], &rhs[2], &rhs[3]); + // Parse out up to 8 components. + unsigned int lhs[8] = {0,0,0,0,0,0,0,0}; + unsigned int rhs[8] = {0,0,0,0,0,0,0,0}; + sscanf(lhss, "%u.%u.%u.%u.%u.%u.%u.%u", + &lhs[0], &lhs[1], &lhs[2], &lhs[3], + &lhs[4], &lhs[5], &lhs[6], &lhs[7]); + sscanf(rhss, "%u.%u.%u.%u.%u.%u.%u.%u", + &rhs[0], &rhs[1], &rhs[2], &rhs[3], + &rhs[4], &rhs[5], &rhs[6], &rhs[7]); // Do component-wise comparison. - for(unsigned int i=0; i < 4; ++i) + for(unsigned int i=0; i < 8; ++i) { if(lhs[i] < rhs[i]) { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 0b2def216c..ec539292a8 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). @@ -274,7 +274,7 @@ public: static bool GetRunCommandOutput() { return s_DisableRunCommandOutput; } /** - * Come constants for different file formats. + * Some constants for different file formats. */ enum FileFormat { NO_FILE_FORMAT = 0, @@ -439,6 +439,10 @@ public: static bool GuessLibrarySOName(std::string const& fullPath, std::string& soname); + /** Try to guess the install name of a shared library. */ + static bool GuessLibraryInstallName(std::string const& fullPath, + std::string& soname); + /** Try to set the RPATH in an ELF binary. */ static bool ChangeRPath(std::string const& file, std::string const& oldRPath, diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index d14bfcaf61..b14db43da8 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -130,31 +130,35 @@ public: typedef std::map<cmSourceFile*, SourceEntry> SourceEntriesType; SourceEntriesType SourceEntries; - struct IncludeDirectoriesEntry { - IncludeDirectoriesEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge, + struct TargetPropertyEntry { + TargetPropertyEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge, const std::string &targetName = std::string()) : ge(cge), TargetName(targetName) {} const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge; - std::vector<std::string> CachedIncludes; + std::vector<std::string> CachedEntries; const std::string TargetName; }; - std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries; - std::vector<cmValueWithOrigin> LinkInterfaceIncludeDirectoriesEntries; + std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries; + std::vector<TargetPropertyEntry*> CompileOptionsEntries; + std::vector<cmValueWithOrigin> LinkInterfacePropertyEntries; - std::map<std::string, std::vector<IncludeDirectoriesEntry*> > + std::map<std::string, std::vector<TargetPropertyEntry*> > CachedLinkInterfaceIncludeDirectoriesEntries; + std::map<std::string, std::vector<TargetPropertyEntry*> > + CachedLinkInterfaceCompileOptionsEntries; std::map<std::string, std::string> CachedLinkInterfaceCompileDefinitions; std::map<std::string, bool> CacheLinkInterfaceIncludeDirectoriesDone; std::map<std::string, bool> CacheLinkInterfaceCompileDefinitionsDone; + std::map<std::string, bool> CacheLinkInterfaceCompileOptionsDone; }; //---------------------------------------------------------------------------- void deleteAndClear( - std::vector<cmTargetInternals::IncludeDirectoriesEntry*> &entries) + std::vector<cmTargetInternals::TargetPropertyEntry*> &entries) { - for (std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::const_iterator + for (std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator it = entries.begin(), end = entries.end(); it != end; ++it) @@ -167,10 +171,10 @@ void deleteAndClear( //---------------------------------------------------------------------------- void deleteAndClear( std::map<std::string, - std::vector<cmTargetInternals::IncludeDirectoriesEntry*> > &entries) + std::vector<cmTargetInternals::TargetPropertyEntry*> > &entries) { for (std::map<std::string, - std::vector<cmTargetInternals::IncludeDirectoriesEntry*> >::iterator + std::vector<cmTargetInternals::TargetPropertyEntry*> >::iterator it = entries.begin(), end = entries.end(); it != end; ++it) { deleteAndClear(it->second); @@ -180,7 +184,8 @@ void deleteAndClear( //---------------------------------------------------------------------------- cmTargetInternals::~cmTargetInternals() { - deleteAndClear(CachedLinkInterfaceIncludeDirectoriesEntries); + deleteAndClear(this->CachedLinkInterfaceIncludeDirectoriesEntries); + deleteAndClear(this->CachedLinkInterfaceCompileOptionsEntries); } //---------------------------------------------------------------------------- @@ -191,6 +196,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; @@ -198,6 +204,7 @@ cmTarget::cmTarget() this->IsImportedTarget = false; this->BuildInterfaceIncludesAppended = false; this->DebugIncludesDone = false; + this->DebugCompileOptionsDone = false; } //---------------------------------------------------------------------------- @@ -277,6 +284,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 @@ -285,6 +293,32 @@ void cmTarget::DefineProperties(cmake *cm) "This is the configuration-specific version of COMPILE_DEFINITIONS."); cm->DefineProperty + ("COMPILE_OPTIONS", cmProperty::TARGET, + "List of options to pass to the compiler.", + "This property specifies the list of options specified " + "so far for this property. " + "This property exists on directories and targets. " + "\n" + "The target property values are used by the generators to set " + "the options for the compiler.\n" + "Contents of COMPILE_OPTIONS may use \"generator expressions\" with " + "the syntax \"$<...>\". " + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS); + + cm->DefineProperty + ("INTERFACE_COMPILE_OPTIONS", cmProperty::TARGET, + "List of interface options to pass to the compiler.", + "Targets may populate this property to publish the compile options " + "required to compile against the headers for the target. Consuming " + "targets can add entries to their own COMPILE_OPTIONS property such " + "as $<TARGET_PROPERTY:foo,INTERFACE_COMPILE_OPTIONS> to use the " + "compile options specified in the interface of 'foo'." + "\n" + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_LANGUAGE_GENERATOR_EXPRESSIONS); + + cm->DefineProperty ("DEFINE_SYMBOL", cmProperty::TARGET, "Define a symbol when compiling this target's sources.", "DEFINE_SYMBOL sets the name of the preprocessor symbol defined when " @@ -292,7 +326,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 @@ -605,7 +639,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, @@ -802,7 +837,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, @@ -813,7 +849,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, @@ -867,6 +904,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 " @@ -886,9 +930,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."); @@ -916,6 +960,35 @@ void cmTarget::DefineProperties(cmake *cm) "(such as \"lib\") on a library name."); cm->DefineProperty + ("C_VISIBILITY_PRESET", cmProperty::TARGET, + "Value for symbol visibility compile flags", + "The C_VISIBILITY_PRESET property determines the value passed used in " + "a visibility related compile option, such as -fvisibility=. This " + "property only has an affect for libraries and executables with " + "exports. This property is initialized by the value of the variable " + "CMAKE_C_VISIBILITY_PRESET if it is set when a target is created."); + + cm->DefineProperty + ("CXX_VISIBILITY_PRESET", cmProperty::TARGET, + "Value for symbol visibility compile flags", + "The CXX_VISIBILITY_PRESET property determines the value passed used in " + "a visibility related compile option, such as -fvisibility=. This " + "property only has an affect for libraries and executables with " + "exports. This property is initialized by the value of the variable " + "CMAKE_CXX_VISIBILITY_PRESET if it is set when a target is created."); + + cm->DefineProperty + ("VISIBILITY_INLINES_HIDDEN", cmProperty::TARGET, + "Whether to add a compile flag to hide symbols of inline functions", + "The VISIBILITY_INLINES_HIDDEN property determines whether a flag for " + "hiding symbols for inline functions. the value passed used in " + "a visibility related compile option, such as -fvisibility=. This " + "property only has an affect for libraries and executables with " + "exports. This property is initialized by the value of the variable " + "CMAKE_VISIBILITY_INLINES_HIDDEN if it is set when a target is " + "created."); + + cm->DefineProperty ("POSITION_INDEPENDENT_CODE", cmProperty::TARGET, "Whether to create a position-independent target", "The POSITION_INDEPENDENT_CODE property determines whether position " @@ -1054,7 +1127,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 " @@ -1092,7 +1165,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 " @@ -1156,7 +1229,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. " @@ -1174,6 +1247,15 @@ void cmTarget::DefineProperties(cmake *cm) "hard-code all the settings instead of using the target properties."); cm->DefineProperty + ("MACOSX_RPATH", cmProperty::TARGET, + "Whether to use rpaths on Mac OS X.", + "When this property is set to true, the directory portion of the" + "\"install_name\" field of shared libraries will default to \"@rpath\"." + "Runtime paths will also be embedded in binaries using this target." + "This property is initialized by the value of the variable " + "CMAKE_MACOSX_RPATH if it is set when a target is created."); + + cm->DefineProperty ("ENABLE_EXPORTS", cmProperty::TARGET, "Specify whether an executable exports symbols for loadable modules.", "Normally an executable does not export any symbols because it is " @@ -1247,7 +1329,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()."); @@ -1316,6 +1398,16 @@ void cmTarget::DefineProperties(cmake *cm) "this value with \"ManagedCProj\", for example, in a Visual " "Studio managed C++ unit test project."); cm->DefineProperty + ("VS_GLOBAL_ROOTNAMESPACE", cmProperty::TARGET, + "Visual Studio project root namespace.", + "Sets the \"RootNamespace\" attribute for a generated Visual Studio " + "project. The attribute will be generated only if this is set."); + cm->DefineProperty + ("VS_DOTNET_TARGET_FRAMEWORK_VERSION", cmProperty::TARGET, + "Specify the .NET target framework version.", + "Used to specify the .NET target framework version for C++/CLI. " + "For example, \"v4.5\"."); + cm->DefineProperty ("VS_DOTNET_REFERENCES", cmProperty::TARGET, "Visual Studio managed project .NET references", "Adds one or more semicolon-delimited .NET references to a " @@ -1397,9 +1489,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" @@ -1501,6 +1593,8 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("LINK_INTERFACE_LIBRARIES", 0); this->SetPropertyDefault("WIN32_EXECUTABLE", 0); this->SetPropertyDefault("MACOSX_BUNDLE", 0); + this->SetPropertyDefault("MACOSX_RPATH", 0); + // Collect the set of configuration types. std::vector<std::string> configNames; @@ -1551,6 +1645,18 @@ void cmTarget::SetMakefile(cmMakefile* mf) { this->InsertInclude(*it); } + const std::vector<cmValueWithOrigin> parentOptions = + this->Makefile->GetCompileOptionsEntries(); + + for (std::vector<cmValueWithOrigin>::const_iterator it + = parentOptions.begin(); it != parentOptions.end(); ++it) + { + this->InsertCompileOption(*it); + } + + this->SetPropertyDefault("C_VISIBILITY_PRESET", 0); + this->SetPropertyDefault("CXX_VISIBILITY_PRESET", 0); + this->SetPropertyDefault("VISIBILITY_INLINES_HIDDEN", 0); if(this->TargetTypeValue == cmTarget::SHARED_LIBRARY || this->TargetTypeValue == cmTarget::MODULE_LIBRARY) @@ -1568,6 +1674,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); } //---------------------------------------------------------------------------- @@ -1669,6 +1777,13 @@ bool cmTarget::IsCFBundleOnApple() } //---------------------------------------------------------------------------- +bool cmTarget::IsBundleOnApple() +{ + return this->IsFrameworkOnApple() || this->IsAppBundleOnApple() || + this->IsCFBundleOnApple(); +} + +//---------------------------------------------------------------------------- class cmTargetTraceDependencies { public: @@ -2491,8 +2606,6 @@ cmTarget::AnalyzeLibDependencies( const cmMakefile& mf ) } } - typedef std::vector< std::string > LinkLine; - // The dependency map. DependencyMap dep_map; @@ -2716,19 +2829,38 @@ void cmTarget::SetProperty(const char* prop, const char* value) deleteAndClear(this->Internal->IncludeDirectoriesEntries); cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); this->Internal->IncludeDirectoriesEntries.push_back( - new cmTargetInternals::IncludeDirectoriesEntry(cge)); + new cmTargetInternals::TargetPropertyEntry(cge)); + return; + } + if(strcmp(prop,"COMPILE_OPTIONS") == 0) + { + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmGeneratorExpression ge(lfbt); + deleteAndClear(this->Internal->CompileOptionsEntries); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); + this->Internal->CompileOptionsEntries.push_back( + new cmTargetInternals::TargetPropertyEntry(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(); + this->Internal->LinkInterfacePropertyEntries.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); + this->Internal->LinkInterfacePropertyEntries.push_back(entry); } // Fall through } @@ -2750,7 +2882,24 @@ void cmTarget::AppendProperty(const char* prop, const char* value, this->Makefile->GetBacktrace(lfbt); cmGeneratorExpression ge(lfbt); this->Internal->IncludeDirectoriesEntries.push_back( - new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(value))); + new cmTargetInternals::TargetPropertyEntry(ge.Parse(value))); + return; + } + if(strcmp(prop,"COMPILE_OPTIONS") == 0) + { + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmGeneratorExpression ge(lfbt); + this->Internal->CompileOptionsEntries.push_back( + new cmTargetInternals::TargetPropertyEntry(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) @@ -2761,7 +2910,7 @@ void cmTarget::AppendProperty(const char* prop, const char* value, cmListFileBacktrace lfbt; this->Makefile->GetBacktrace(lfbt); cmValueWithOrigin entry(value, lfbt); - this->Internal->LinkInterfaceIncludeDirectoriesEntries.push_back(entry); + this->Internal->LinkInterfacePropertyEntries.push_back(entry); } // Fall through } @@ -2770,6 +2919,26 @@ void cmTarget::AppendProperty(const char* prop, const char* value, } //---------------------------------------------------------------------------- +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 && @@ -2806,17 +2975,31 @@ void cmTarget::InsertInclude(const cmValueWithOrigin &entry, { cmGeneratorExpression ge(entry.Backtrace); - std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::iterator position + std::vector<cmTargetInternals::TargetPropertyEntry*>::iterator position = before ? this->Internal->IncludeDirectoriesEntries.begin() : this->Internal->IncludeDirectoriesEntries.end(); this->Internal->IncludeDirectoriesEntries.insert(position, - new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(entry.Value))); + new cmTargetInternals::TargetPropertyEntry(ge.Parse(entry.Value))); +} + +//---------------------------------------------------------------------------- +void cmTarget::InsertCompileOption(const cmValueWithOrigin &entry, + bool before) +{ + cmGeneratorExpression ge(entry.Backtrace); + + std::vector<cmTargetInternals::TargetPropertyEntry*>::iterator position + = before ? this->Internal->CompileOptionsEntries.begin() + : this->Internal->CompileOptionsEntries.end(); + + this->Internal->CompileOptionsEntries.insert(position, + new cmTargetInternals::TargetPropertyEntry(ge.Parse(entry.Value))); } //---------------------------------------------------------------------------- static void processIncludeDirectories(cmTarget *tgt, - const std::vector<cmTargetInternals::IncludeDirectoriesEntry*> &entries, + const std::vector<cmTargetInternals::TargetPropertyEntry*> &entries, std::vector<std::string> &includes, std::set<std::string> &uniqueIncludes, cmGeneratorExpressionDAGChecker *dagChecker, @@ -2824,12 +3007,12 @@ static void processIncludeDirectories(cmTarget *tgt, { cmMakefile *mf = tgt->GetMakefile(); - for (std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::const_iterator + for (std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator it = entries.begin(), end = entries.end(); it != end; ++it) { bool testIsOff = true; bool cacheIncludes = false; - std::vector<std::string> entryIncludes = (*it)->CachedIncludes; + std::vector<std::string> entryIncludes = (*it)->CachedEntries; if(!entryIncludes.empty()) { testIsOff = false; @@ -2876,14 +3059,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; } } @@ -2905,7 +3115,7 @@ static void processIncludeDirectories(cmTarget *tgt, } if (cacheIncludes) { - (*it)->CachedIncludes = entryIncludes; + (*it)->CachedEntries = entryIncludes; } if (!usedIncludes.empty()) { @@ -2925,8 +3135,8 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config) cmListFileBacktrace lfbt; cmGeneratorExpressionDAGChecker dagChecker(lfbt, - this->GetName(), - "INCLUDE_DIRECTORIES", 0, 0); + this->GetName(), + "INCLUDE_DIRECTORIES", 0, 0); this->AppendBuildInterfaceIncludes(); @@ -2961,8 +3171,8 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config) if (!this->Internal->CacheLinkInterfaceIncludeDirectoriesDone[configString]) { for (std::vector<cmValueWithOrigin>::const_iterator - it = this->Internal->LinkInterfaceIncludeDirectoriesEntries.begin(), - end = this->Internal->LinkInterfaceIncludeDirectoriesEntries.end(); + it = this->Internal->LinkInterfacePropertyEntries.begin(), + end = this->Internal->LinkInterfacePropertyEntries.end(); it != end; ++it) { { @@ -2991,7 +3201,7 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config) this->Internal ->CachedLinkInterfaceIncludeDirectoriesEntries[configString].push_back( - new cmTargetInternals::IncludeDirectoriesEntry(cge, + new cmTargetInternals::TargetPropertyEntry(cge, it->Value)); } } @@ -3019,6 +3229,159 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config) } //---------------------------------------------------------------------------- +static void processCompileOptions(cmTarget *tgt, + const std::vector<cmTargetInternals::TargetPropertyEntry*> &entries, + std::vector<std::string> &options, + std::set<std::string> &uniqueOptions, + cmGeneratorExpressionDAGChecker *dagChecker, + const char *config, bool debugOptions) +{ + cmMakefile *mf = tgt->GetMakefile(); + + for (std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator + it = entries.begin(), end = entries.end(); it != end; ++it) + { + bool cacheOptions = false; + std::vector<std::string> entryOptions = (*it)->CachedEntries; + if(entryOptions.empty()) + { + cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(mf, + config, + false, + tgt, + dagChecker), + entryOptions); + if (mf->IsGeneratingBuildSystem() + && !(*it)->ge->GetHadContextSensitiveCondition()) + { + cacheOptions = true; + } + } + std::string usedOptions; + for(std::vector<std::string>::iterator + li = entryOptions.begin(); li != entryOptions.end(); ++li) + { + std::string opt = *li; + + if(uniqueOptions.insert(opt).second) + { + options.push_back(opt); + if (debugOptions) + { + usedOptions += " * " + opt + "\n"; + } + } + } + if (cacheOptions) + { + (*it)->CachedEntries = entryOptions; + } + if (!usedOptions.empty()) + { + mf->GetCMakeInstance()->IssueMessage(cmake::LOG, + std::string("Used compile options for target ") + + tgt->GetName() + ":\n" + + usedOptions, (*it)->ge->GetBacktrace()); + } + } +} + +//---------------------------------------------------------------------------- +void cmTarget::GetCompileOptions(std::vector<std::string> &result, + const char *config) +{ + std::set<std::string> uniqueOptions; + cmListFileBacktrace lfbt; + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + "COMPILE_OPTIONS", 0, 0); + + std::vector<std::string> debugProperties; + const char *debugProp = + this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); + if (debugProp) + { + cmSystemTools::ExpandListArgument(debugProp, debugProperties); + } + + bool debugOptions = !this->DebugCompileOptionsDone + && std::find(debugProperties.begin(), + debugProperties.end(), + "COMPILE_OPTIONS") + != debugProperties.end(); + + if (this->Makefile->IsGeneratingBuildSystem()) + { + this->DebugCompileOptionsDone = true; + } + + processCompileOptions(this, + this->Internal->CompileOptionsEntries, + result, + uniqueOptions, + &dagChecker, + config, + debugOptions); + + std::string configString = config ? config : ""; + if (!this->Internal->CacheLinkInterfaceCompileOptionsDone[configString]) + { + for (std::vector<cmValueWithOrigin>::const_iterator + it = this->Internal->LinkInterfacePropertyEntries.begin(), + end = this->Internal->LinkInterfacePropertyEntries.end(); + it != end; ++it) + { + { + cmGeneratorExpression ge(lfbt); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = + ge.Parse(it->Value); + std::string targetResult = cge->Evaluate(this->Makefile, config, + false, this, 0, 0); + if (!this->Makefile->FindTargetToUse(targetResult.c_str())) + { + continue; + } + } + std::string optionGenex = "$<TARGET_PROPERTY:" + + it->Value + ",INTERFACE_COMPILE_OPTIONS>"; + 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. + optionGenex = "$<$<BOOL:" + it->Value + ">:" + optionGenex + ">"; + } + cmGeneratorExpression ge(it->Backtrace); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse( + optionGenex); + + this->Internal + ->CachedLinkInterfaceCompileOptionsEntries[configString].push_back( + new cmTargetInternals::TargetPropertyEntry(cge, + it->Value)); + } + } + + processCompileOptions(this, + this->Internal->CachedLinkInterfaceCompileOptionsEntries[configString], + result, + uniqueOptions, + &dagChecker, + config, + debugOptions); + + if (!this->Makefile->IsGeneratingBuildSystem()) + { + deleteAndClear(this->Internal->CachedLinkInterfaceCompileOptionsEntries); + } + else + { + this->Internal->CacheLinkInterfaceCompileOptionsDone[configString] = true; + } +} + +//---------------------------------------------------------------------------- std::string cmTarget::GetCompileDefinitions(const char *config) { const char *configProp = 0; @@ -3304,17 +3667,23 @@ const char* cmTarget::NormalGetLocation(const char* config) // Now handle the deprecated build-time configuration location. this->Location = this->GetDirectory(); - if(!this->Location.empty()) - { - this->Location += "/"; - } const char* cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR"); if(cfgid && strcmp(cfgid, ".") != 0) { - this->Location += cfgid; this->Location += "/"; + this->Location += cfgid; + } + + if(this->IsAppBundleOnApple()) + { + std::string macdir = this->BuildMacContentDirectory("", config, false); + if(!macdir.empty()) + { + this->Location += "/"; + this->Location += macdir; + } } - this->Location = this->BuildMacContentDirectory(this->Location, config); + this->Location += "/"; this->Location += this->GetFullName(config, false); return this->Location.c_str(); } @@ -3437,9 +3806,9 @@ const char *cmTarget::GetProperty(const char* prop, static std::string output; output = ""; std::string sep; - typedef cmTargetInternals::IncludeDirectoriesEntry - IncludeDirectoriesEntry; - for (std::vector<IncludeDirectoriesEntry*>::const_iterator + typedef cmTargetInternals::TargetPropertyEntry + TargetPropertyEntry; + for (std::vector<TargetPropertyEntry*>::const_iterator it = this->Internal->IncludeDirectoriesEntries.begin(), end = this->Internal->IncludeDirectoriesEntries.end(); it != end; ++it) @@ -3450,6 +3819,24 @@ const char *cmTarget::GetProperty(const char* prop, } return output.c_str(); } + if(strcmp(prop,"COMPILE_OPTIONS") == 0) + { + static std::string output; + output = ""; + std::string sep; + typedef cmTargetInternals::TargetPropertyEntry + TargetPropertyEntry; + for (std::vector<TargetPropertyEntry*>::const_iterator + it = this->Internal->CompileOptionsEntries.begin(), + end = this->Internal->CompileOptionsEntries.end(); + it != end; ++it) + { + output += sep; + output += (*it)->ge->GetInput(); + sep = ";"; + } + return output.c_str(); + } if (strcmp(prop,"IMPORTED") == 0) { @@ -3798,6 +4185,10 @@ std::string cmTarget::GetSOName(const char* config) else { // Use the soname given if any. + if(info->SOName.find("@rpath/") == 0) + { + return info->SOName.substr(6); + } return info->SOName; } } @@ -3820,6 +4211,75 @@ std::string cmTarget::GetSOName(const char* config) } //---------------------------------------------------------------------------- +bool cmTarget::HasMacOSXRpath(const char* config) +{ + bool install_name_is_rpath = false; + bool macosx_rpath = this->GetPropertyAsBool("MACOSX_RPATH"); + + if(!this->IsImportedTarget) + { + const char* install_name = this->GetProperty("INSTALL_NAME_DIR"); + bool use_install_name = + this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"); + if(install_name && use_install_name && + std::string(install_name) == "@rpath") + { + install_name_is_rpath = true; + } + } + else + { + // Lookup the imported soname. + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this)) + { + if(!info->NoSOName && !info->SOName.empty()) + { + if(info->SOName.find("@rpath/") == 0) + { + install_name_is_rpath = true; + } + } + else + { + std::string install_name; + cmSystemTools::GuessLibraryInstallName(info->Location, install_name); + if(install_name.find("@rpath") != std::string::npos) + { + install_name_is_rpath = true; + } + } + } + } + + if(!install_name_is_rpath && !macosx_rpath) + { + return false; + } + + if(!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) + { + cmOStringStream w; + w << "Attempting to use"; + if(macosx_rpath) + { + w << " MACOSX_RPATH"; + } + else + { + w << " @rpath"; + } + w << " without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being set."; + w << " This could be because you are using a Mac OS X version"; + w << " less than 10.5 or because CMake's platform configuration is"; + w << " corrupt."; + cmake* cm = this->Makefile->GetCMakeInstance(); + cm->IssueMessage(cmake::FATAL_ERROR, w.str(), this->GetBacktrace()); + } + + return true; +} + +//---------------------------------------------------------------------------- bool cmTarget::IsImportedSharedLibWithoutSOName(const char* config) { if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY) @@ -3916,7 +4376,13 @@ std::string cmTarget::GetFullPath(const char* config, bool implib, std::string cmTarget::NormalGetFullPath(const char* config, bool implib, bool realname) { - std::string fpath = this->GetMacContentDirectory(config, implib); + std::string fpath = this->GetDirectory(config, implib); + fpath += "/"; + if(this->IsAppBundleOnApple()) + { + fpath = this->BuildMacContentDirectory(fpath, config, false); + fpath += "/"; + } // Add the full name of the target. if(implib) @@ -4048,10 +4514,28 @@ void cmTarget::GetFullNameInternal(const char* config, targetSuffix = this->Makefile->GetSafeDefinition(suffixVar); } - // frameworks do not have a prefix or a suffix + // frameworks have directory prefix but no suffix + std::string fw_prefix; if(this->IsFrameworkOnApple()) { - targetPrefix = 0; + fw_prefix = this->GetOutputName(config, false); + fw_prefix += ".framework/"; + targetPrefix = fw_prefix.c_str(); + targetSuffix = 0; + } + + if(this->IsCFBundleOnApple()) + { + fw_prefix = this->GetOutputName(config, false); + fw_prefix += "."; + const char *ext = this->GetProperty("BUNDLE_EXTENSION"); + if (!ext) + { + ext = "bundle"; + } + fw_prefix += ext; + fw_prefix += "/Contents/MacOS/"; + targetPrefix = fw_prefix.c_str(); targetSuffix = 0; } @@ -4131,13 +4615,24 @@ void cmTarget::GetLibraryNames(std::string& name, // The library name. name = prefix+base+suffix; - // The library's soname. - this->ComputeVersionedName(soName, prefix, base, suffix, - name, soversion); - - // The library's real name on disk. - this->ComputeVersionedName(realName, prefix, base, suffix, - name, version); + if(this->IsFrameworkOnApple()) + { + realName = prefix; + realName += "Versions/"; + realName += this->GetFrameworkVersion(); + realName += "/"; + realName += base; + soName = realName; + } + else + { + // The library's soname. + this->ComputeVersionedName(soName, prefix, base, suffix, + name, soversion); + // The library's real name on disk. + this->ComputeVersionedName(realName, prefix, base, suffix, + name, version); + } // The import library name. if(this->GetType() == cmTarget::SHARED_LIBRARY || @@ -4425,14 +4920,13 @@ bool cmTarget::NeedRelinkBeforeInstall(const char* config) } //---------------------------------------------------------------------------- -std::string cmTarget::GetInstallNameDirForBuildTree(const char* config, - bool for_xcode) +std::string cmTarget::GetInstallNameDirForBuildTree(const char* config) { // If building directly for installation then the build tree install_name // is the same as the install tree. if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) { - return GetInstallNameDirForInstallTree(config, for_xcode); + return GetInstallNameDirForInstallTree(); } // Use the build tree directory for the target. @@ -4440,12 +4934,16 @@ std::string cmTarget::GetInstallNameDirForBuildTree(const char* config, !this->Makefile->IsOn("CMAKE_SKIP_RPATH") && !this->GetPropertyAsBool("SKIP_BUILD_RPATH")) { - std::string dir = this->GetDirectory(config); - dir += "/"; - if(this->IsFrameworkOnApple() && !for_xcode) + std::string dir; + if(this->GetPropertyAsBool("MACOSX_RPATH")) { - dir += this->GetFrameworkDirectory(config); + dir = "@rpath"; } + else + { + dir = this->GetDirectory(config); + } + dir += "/"; return dir; } else @@ -4455,8 +4953,7 @@ std::string cmTarget::GetInstallNameDirForBuildTree(const char* config, } //---------------------------------------------------------------------------- -std::string cmTarget::GetInstallNameDirForInstallTree(const char* config, - bool for_xcode) +std::string cmTarget::GetInstallNameDirForInstallTree() { if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { @@ -4472,12 +4969,10 @@ std::string cmTarget::GetInstallNameDirForInstallTree(const char* config, dir += "/"; } } - - if(this->IsFrameworkOnApple() && !for_xcode) + if(dir.empty() && this->GetPropertyAsBool("MACOSX_RPATH")) { - dir += this->GetFrameworkDirectory(config); + dir = "@rpath/"; } - return dir; } else @@ -5059,7 +5554,6 @@ void cmTarget::GetLanguages(std::set<cmStdString>& languages) const //---------------------------------------------------------------------------- bool cmTarget::IsChrpathUsed(const char* config) { -#if defined(CMAKE_USE_ELF_PARSER) // Only certain target types have an rpath. if(!(this->GetType() == cmTarget::SHARED_LIBRARY || this->GetType() == cmTarget::MODULE_LIBRARY || @@ -5093,6 +5587,12 @@ bool cmTarget::IsChrpathUsed(const char* config) return false; } + if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) + { + return true; + } + +#if defined(CMAKE_USE_ELF_PARSER) // Enable if the rpath flag uses a separator and the target uses ELF // binaries. if(const char* ll = this->GetLinkerLanguage(config, this)) @@ -5289,7 +5789,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. @@ -5936,59 +6435,86 @@ cmTarget::GetLinkInformation(const char* config, cmTarget *head) } //---------------------------------------------------------------------------- -std::string cmTarget::GetFrameworkDirectory(const char* config) +std::string cmTarget::GetFrameworkDirectory(const char* config, + bool rootDir) { std::string fpath; - fpath += this->GetFullName(config, false); - fpath += ".framework/Versions/"; - fpath += this->GetFrameworkVersion(); - fpath += "/"; + fpath += this->GetOutputName(config, false); + fpath += ".framework"; + if(!rootDir) + { + fpath += "/Versions/"; + fpath += this->GetFrameworkVersion(); + } + return fpath; +} + +//---------------------------------------------------------------------------- +std::string cmTarget::GetCFBundleDirectory(const char* config, + bool contentOnly) +{ + std::string fpath; + fpath += this->GetOutputName(config, false); + fpath += "."; + const char *ext = this->GetProperty("BUNDLE_EXTENSION"); + if (!ext) + { + ext = "bundle"; + } + fpath += ext; + fpath += "/Contents"; + if(!contentOnly) + fpath += "/MacOS"; + return fpath; +} + +//---------------------------------------------------------------------------- +std::string cmTarget::GetAppBundleDirectory(const char* config, + bool contentOnly) +{ + std::string fpath = this->GetFullName(config, false); + fpath += ".app/Contents"; + if(!contentOnly) + fpath += "/MacOS"; return fpath; } //---------------------------------------------------------------------------- std::string cmTarget::BuildMacContentDirectory(const std::string& base, const char* config, - bool includeMacOS) + bool contentOnly) { std::string fpath = base; if(this->IsAppBundleOnApple()) { - fpath += this->GetFullName(config, false); - fpath += ".app/Contents/"; - if(includeMacOS) - fpath += "MacOS/"; + fpath += this->GetAppBundleDirectory(config, contentOnly); } if(this->IsFrameworkOnApple()) { - fpath += this->GetFrameworkDirectory(config); + fpath += this->GetFrameworkDirectory(config, contentOnly); } if(this->IsCFBundleOnApple()) { - fpath += this->GetFullName(config, false); - fpath += "."; - const char *ext = this->GetProperty("BUNDLE_EXTENSION"); - if (!ext) - { - ext = "bundle"; - } - fpath += ext; - fpath += "/Contents/"; - if(includeMacOS) - fpath += "MacOS/"; + fpath += this->GetCFBundleDirectory(config, contentOnly); } return fpath; } //---------------------------------------------------------------------------- std::string cmTarget::GetMacContentDirectory(const char* config, - bool implib, - bool includeMacOS) + bool implib) { // Start with the output directory for the target. std::string fpath = this->GetDirectory(config, implib); fpath += "/"; - fpath = this->BuildMacContentDirectory(fpath, config, includeMacOS); + bool contentOnly = true; + if(this->IsFrameworkOnApple()) + { + // additional files with a framework go into the version specific + // directory + contentOnly = false; + } + fpath = this->BuildMacContentDirectory(fpath, config, contentOnly); return fpath; } @@ -6035,6 +6561,7 @@ cmTargetInternalPointer cmTargetInternalPointer::~cmTargetInternalPointer() { deleteAndClear(this->Pointer->IncludeDirectoriesEntries); + deleteAndClear(this->Pointer->CompileOptionsEntries); delete this->Pointer; } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 9d467961b6..3bc0ab2e2a 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 */ @@ -362,6 +367,9 @@ public: /** Get the soname of the target. Allowed only for a shared library. */ std::string GetSOName(const char* config); + /** Whether this library has @rpath and platform supports it. */ + bool HasMacOSXRpath(const char* config); + /** Test for special case of a third-party shared library that has no soname at all. */ bool IsImportedSharedLibWithoutSOName(const char* config); @@ -407,10 +415,14 @@ public: /** Return true if builtin chrpath will work for this target */ bool IsChrpathUsed(const char* config); - std::string GetInstallNameDirForBuildTree(const char* config, - bool for_xcode = false); - std::string GetInstallNameDirForInstallTree(const char* config, - bool for_xcode = false); + /** Return the install name directory for the target in the + * build tree. For example: "@rpath/", "@loader_path/", + * or "/full/path/to/library". */ + std::string GetInstallNameDirForBuildTree(const char* config); + + /** Return the install name directory for the target in the + * install tree. For example: "@rpath/" or "@loader_path/". */ + std::string GetInstallNameDirForInstallTree(); cmComputeLinkInformation* GetLinkInformation(const char* config, cmTarget *head = 0); @@ -462,6 +474,10 @@ public: /** Return whether this target is an executable Bundle on Apple. */ bool IsAppBundleOnApple(); + /** Return whether this target is an executable Bundle, a framework + or CFBundle on Apple. */ + bool IsBundleOnApple(); + /** Return the framework version string. Undefined if IsFrameworkOnApple returns false. */ std::string GetFrameworkVersion(); @@ -476,28 +492,33 @@ public: directory. */ bool UsesDefaultOutputDir(const char* config, bool implib); - /** Append to @a base the mac content directory and return it. */ - std::string BuildMacContentDirectory(const std::string& base, - const char* config = 0, - bool includeMacOS = true); - /** @return the mac content directory for this target. */ - std::string GetMacContentDirectory(const char* config = 0, - bool implib = false, - bool includeMacOS = true); + std::string GetMacContentDirectory(const char* config, + bool implib); /** @return whether this target have a well defined output file name. */ bool HaveWellDefinedOutputFiles(); /** @return the Mac framework directory without the base. */ - std::string GetFrameworkDirectory(const char* config = 0); + std::string GetFrameworkDirectory(const char* config, bool rootDir); + + /** @return the Mac CFBundle directory without the base */ + std::string GetCFBundleDirectory(const char* config, bool contentOnly); + + /** @return the Mac App directory without the base */ + std::string GetAppBundleDirectory(const char* config, bool contentOnly); std::vector<std::string> GetIncludeDirectories(const char *config); void InsertInclude(const cmValueWithOrigin &entry, bool before = false); + void InsertCompileOption(const cmValueWithOrigin &entry, + bool before = false); void AppendBuildInterfaceIncludes(); + void GetCompileOptions(std::vector<std::string> &result, + const char *config); + bool IsNullImpliedByLinkLibraries(const std::string &p); bool IsLinkInterfaceDependentBoolProperty(const std::string &p, const char *config); @@ -596,6 +617,11 @@ private: the same as GetFullName. */ std::string NormalGetRealName(const char* config); + /** Append to @a base the mac content directory and return it. */ + std::string BuildMacContentDirectory(const std::string& base, + const char* config, + bool contentOnly); + private: std::string Name; std::vector<cmCustomCommand> PreBuildCommands; @@ -622,6 +648,7 @@ private: bool IsApple; bool IsImportedTarget; bool DebugIncludesDone; + bool DebugCompileOptionsDone; mutable std::set<std::string> LinkImplicitNullProperties; bool BuildInterfaceIncludesAppended; @@ -664,6 +691,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 ec9b071dbb..22d8fa8e9c 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/cmTargetCompileOptionsCommand.cxx b/Source/cmTargetCompileOptionsCommand.cxx new file mode 100644 index 0000000000..e80c8456ba --- /dev/null +++ b/Source/cmTargetCompileOptionsCommand.cxx @@ -0,0 +1,62 @@ +/*============================================================================ + 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 "cmTargetCompileOptionsCommand.h" + +bool cmTargetCompileOptionsCommand +::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) +{ + return this->HandleArguments(args, "COMPILE_OPTIONS", PROCESS_BEFORE); +} + +void cmTargetCompileOptionsCommand +::HandleImportedTarget(const std::string &tgt) +{ + cmOStringStream e; + e << "Cannot specify compile options for imported target \"" + << tgt << "\"."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); +} + +void cmTargetCompileOptionsCommand +::HandleMissingTarget(const std::string &name) +{ + cmOStringStream e; + e << "Cannot specify compile options for target \"" << name << "\" " + "which is not built by this project."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); +} + +//---------------------------------------------------------------------------- +std::string cmTargetCompileOptionsCommand +::Join(const std::vector<std::string> &content) +{ + std::string defs; + std::string sep; + for(std::vector<std::string>::const_iterator it = content.begin(); + it != content.end(); ++it) + { + defs += sep + *it; + sep = ";"; + } + return defs; +} + +//---------------------------------------------------------------------------- +void cmTargetCompileOptionsCommand +::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content, + bool) +{ + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmValueWithOrigin entry(this->Join(content), lfbt); + tgt->InsertCompileOption(entry); +} diff --git a/Source/cmTargetCompileOptionsCommand.h b/Source/cmTargetCompileOptionsCommand.h new file mode 100644 index 0000000000..87fa1a720e --- /dev/null +++ b/Source/cmTargetCompileOptionsCommand.h @@ -0,0 +1,90 @@ +/*============================================================================ + 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 cmTargetCompileOptionsCommand_h +#define cmTargetCompileOptionsCommand_h + +#include "cmTargetPropCommandBase.h" + +class cmTargetCompileOptionsCommand : public cmTargetPropCommandBase +{ +public: + /** + * This is a virtual constructor for the command. + */ + virtual cmCommand* Clone() + { + return new cmTargetCompileOptionsCommand; + } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + virtual bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus &status); + + /** + * The name of the command as specified in CMakeList.txt. + */ + virtual const char* GetName() const { return "target_compile_options";} + + /** + * Succinct documentation. + */ + virtual const char* GetTerseDocumentation() const + { + return + "Add compile options to a target."; + } + + /** + * More documentation. + */ + virtual const char* GetFullDocumentation() const + { + return + " target_compile_options(<target> [BEFORE] " + "<INTERFACE|PUBLIC|PRIVATE> [items1...]\n" + " [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])\n" + "Specify compile options to use when compiling a given target. " + "The named <target> must have been created by a command such as " + "add_executable or add_library and must not be an IMPORTED target. " + "If BEFORE is specified, the content will be prepended to the property " + "instead of being appended.\n" + "The INTERFACE, PUBLIC and PRIVATE keywords are required to specify " + "the scope of the following arguments. PRIVATE and PUBLIC items will " + "populate the COMPILE_OPTIONS property of <target>. PUBLIC and " + "INTERFACE items will populate the INTERFACE_COMPILE_OPTIONS " + "property of <target>. " + "The following arguments specify compile opitions. " + "Repeated calls for the same <target> append items in the order called." + "\n" + "Arguments to target_compile_options may use \"generator " + "expressions\" with the syntax \"$<...>\". " + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + ; + } + + cmTypeMacro(cmTargetCompileOptionsCommand, cmTargetPropCommandBase); + +private: + virtual void HandleImportedTarget(const std::string &tgt); + virtual void HandleMissingTarget(const std::string &name); + + virtual void HandleDirectContent(cmTarget *tgt, + const std::vector<std::string> &content, + bool prepend); + virtual std::string Join(const std::vector<std::string> &content); +}; + +#endif diff --git a/Source/cmTargetIncludeDirectoriesCommand.h b/Source/cmTargetIncludeDirectoriesCommand.h index e4bc9cf67f..4a1a4df349 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/cmTest.cxx b/Source/cmTest.cxx index 912ec7634a..0904431d15 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/cmTryCompileCommand.h b/Source/cmTryCompileCommand.h index 6caa130ce0..163756d0c0 100644 --- a/Source/cmTryCompileCommand.h +++ b/Source/cmTryCompileCommand.h @@ -64,16 +64,16 @@ public: "Specify targetName to build a specific target instead of the 'all' or " "'ALL_BUILD' target." "\n" - " try_compile(RESULT_VAR <bindir> <srcfile>\n" + " try_compile(RESULT_VAR <bindir> <srcfile|SOURCES srcfile...>\n" " [CMAKE_FLAGS flags...]\n" " [COMPILE_DEFINITIONS flags...]\n" " [LINK_LIBRARIES libs...]\n" " [OUTPUT_VARIABLE <var>]\n" " [COPY_FILE <fileName>])\n" - "Try building a source file into an executable. " - "In this form the user need only supply a source file that defines " - "a 'main'. " - "CMake will create a CMakeLists.txt file to build the source " + "Try building an executable from one or more source files. " + "In this form the user need only supply one or more source files " + "that include a definition for 'main'. " + "CMake will create a CMakeLists.txt file to build the source(s) " "as an executable. " "Specify COPY_FILE to get a copy of the linked executable at the " "given fileName." diff --git a/Source/cmVariableWatch.cxx b/Source/cmVariableWatch.cxx index f5fdca4652..3905e9bdae 100644 --- a/Source/cmVariableWatch.cxx +++ b/Source/cmVariableWatch.cxx @@ -15,6 +15,7 @@ static const char* const cmVariableWatchAccessStrings[] = { "READ_ACCESS", "UNKNOWN_READ_ACCESS", + "UNKNOWN_DEFINED_ACCESS", "ALLOWED_UNKNOWN_READ_ACCESS", "MODIFIED_ACCESS", "REMOVED_ACCESS", diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx index a432943ae1..297a92b934 100644 --- a/Source/cmVariableWatchCommand.cxx +++ b/Source/cmVariableWatchCommand.cxx @@ -117,24 +117,9 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable, if ( !processed ) { cmOStringStream msg; - msg << "* Variable \"" << variable.c_str() << "\" was accessed using " - << accessString << " in: " << currentListFile << std::endl; - msg << " The value of the variable: \"" << newValue << "\"" << std::endl; - msg << " The list file stack: " << stack.c_str(); - cmSystemTools::Message(msg.str().c_str()); - std::vector<std::string> vars = makefile->GetDefinitions(); - cmOStringStream msg2; - size_t cc; - for ( cc = 0; cc < vars.size(); cc ++ ) - { - if ( vars[cc] == variable ) - { - continue; - } - msg2 << vars[cc] << " = \"" - << makefile->GetDefinition(vars[cc].c_str()) << "\"" << std::endl; - } - //cmSystemTools::Message(msg2.str().c_str()); + msg << "Variable \"" << variable.c_str() << "\" was accessed using " + << accessString << " with value \"" << newValue << "\"."; + makefile->IssueMessage(cmake::LOG, msg.str()); } this->InCallback = false; } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 9cfb3703e7..c70bf3ac67 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -274,6 +274,15 @@ void cmVisualStudio10TargetGenerator::Generate() "</Keyword>\n"; } + const char* vsGlobalRootNamespace = + this->Target->GetProperty("VS_GLOBAL_ROOTNAMESPACE"); + if(vsGlobalRootNamespace) + { + this->WriteString("<RootNamespace>", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(vsGlobalRootNamespace) << + "</RootNamespace>\n"; + } + this->WriteString("<Platform>", 2); (*this->BuildFileStream) << this->Platform << "</Platform>\n"; const char* projLabel = this->Target->GetProperty("PROJECT_LABEL"); @@ -283,6 +292,13 @@ void cmVisualStudio10TargetGenerator::Generate() } this->WriteString("<ProjectName>", 2); (*this->BuildFileStream) << projLabel << "</ProjectName>\n"; + if(const char* targetFrameworkVersion = this->Target->GetProperty( + "VS_DOTNET_TARGET_FRAMEWORK_VERSION")) + { + this->WriteString("<TargetFrameworkVersion>", 2); + (*this->BuildFileStream) << targetFrameworkVersion + << "</TargetFrameworkVersion>\n"; + } this->WriteString("</PropertyGroup>\n", 1); this->WriteString("<Import Project=" "\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n", @@ -303,6 +319,7 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteCustomCommands(); this->WriteAllSources(); this->WriteDotNetReferences(); + this->WriteWinRTReferences(); this->WriteProjectReferences(); this->WriteString( @@ -467,6 +484,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); } } @@ -659,6 +682,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); @@ -713,6 +753,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 @@ -844,8 +901,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); } @@ -1192,7 +1261,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( if(!linkLanguage) { cmSystemTools::Error - ("CMake can not determine linker language for target:", + ("CMake can not determine linker language for target: ", this->Name.c_str()); return false; } @@ -1219,17 +1288,16 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( { flags += " /TP "; } + this->LocalGenerator->AddCompileOptions(flags, this->Target, + linkLanguage, configName.c_str()); } - // Add the target-specific flags. - if(const char* targetFlags = this->Target->GetProperty("COMPILE_FLAGS")) - { - flags += " "; - flags += targetFlags; - } + // Get preprocessor definitions for this directory. 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( @@ -1272,18 +1340,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); } @@ -1377,7 +1434,7 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) if(!linkLanguage) { cmSystemTools::Error - ("CMake can not determine linker language for target:", + ("CMake can not determine linker language for target: ", this->Name.c_str()); return false; } @@ -1459,7 +1516,7 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) if(!pcli) { cmSystemTools::Error - ("CMake can not compute cmComputeLinkInformation for target:", + ("CMake can not compute cmComputeLinkInformation for target: ", this->Name.c_str()); return false; } @@ -1591,6 +1648,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); @@ -1730,3 +1802,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 55a850a1b1..73d5961594 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 01950e16d5..f4df1a97c1 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, ">", ">"); @@ -229,7 +230,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 0000000000..82b4ee84f3 --- /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 0000000000..ec128cf11c --- /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 0000000000..bae59740ad --- /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 0000000000..bee70cc13d --- /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 5752ab61cf..1bdeffbed7 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 98b6bda986..2127ebd2e8 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 376758e48b..b9c043b96f 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -129,7 +129,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()); @@ -384,11 +384,22 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) cmCacheManager::CacheEntryType type = cmCacheManager::UNINITIALIZED; if(cmCacheManager::ParseEntry(entry.c_str(), var, value, type)) { + // The value is transformed if it is a filepath for example, so + // we can't compare whether the value is already in the cache until + // after we call AddCacheEntry. + const char *cachedValue = + this->CacheManager->GetCacheValue(var.c_str()); + this->CacheManager->AddCacheEntry(var.c_str(), value.c_str(), "No help, variable specified on the command line.", type); if(this->WarnUnusedCli) { - this->WatchUnusedCli(var.c_str()); + if (!cachedValue + || strcmp(this->CacheManager->GetCacheValue(var.c_str()), + cachedValue) != 0) + { + this->WatchUnusedCli(var.c_str()); + } } } else @@ -539,7 +550,7 @@ void cmake::ReadListFile(const std::vector<std::string>& args, } if (!lg->GetMakefile()->ReadListFile(0, path)) { - cmSystemTools::Error("Error processing file:", path); + cmSystemTools::Error("Error processing file: ", path); } } @@ -1158,9 +1169,8 @@ void CMakeCommandUsage(const char* program) << " remove_directory dir - remove a directory and its contents\n" << " rename oldname newname - rename a file or directory " "(on one volume)\n" - << " tar [cxt][vfz][cvfj] file.tar " - "file/dir1 file/dir2 ... - create a tar " - "archive\n" + << " tar [cxt][vfz][cvfj] file.tar [file/dir1 file/dir2 ...]\n" + << " - create or extract a tar or zip archive\n" << " time command [args] ... - run command and return elapsed time\n" << " touch file - touch a file.\n" << " touch_nocreate file - touch a file but do not create it.\n" @@ -1727,7 +1737,8 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& args) else if (args[1] == "cmake_automoc") { cmQtAutomoc automoc; - bool automocSuccess = automoc.Run(args[2].c_str()); + const char *config = args[3].empty() ? 0 : args[3].c_str(); + bool automocSuccess = automoc.Run(args[2].c_str(), config); return automocSuccess ? 0 : 1; } #endif @@ -2367,7 +2378,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")) { @@ -2633,7 +2644,8 @@ const char* cmake::GetCacheDefinition(const char* name) const void cmake::AddDefaultCommands() { std::list<cmCommand*> commands; - GetBootstrapCommands(commands); + GetBootstrapCommands1(commands); + GetBootstrapCommands2(commands); GetPredefinedCommands(commands); for(std::list<cmCommand*>::iterator i = commands.begin(); i != commands.end(); ++i) @@ -4049,7 +4061,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)) { @@ -4121,7 +4133,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) @@ -4177,7 +4189,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 63065a17c4..a50c1ed02a 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 42678419e4..77a5e43949 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 749f669d0d..bac403a893 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 04dab59d0f..262d83ba56 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 3e63183ebc..e767a16123 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/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 124b8aca05..6f0281d129 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -569,8 +569,17 @@ IF(KWSYS_USE_SystemTools) "Checking whether CXX compiler has unsetenv" DIRECT) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H "Checking whether CXX compiler has environ in stdlib.h" DIRECT) - SET_SOURCE_FILES_PROPERTIES(SystemTools.cxx PROPERTIES - COMPILE_FLAGS "-DKWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV} -DKWSYS_CXX_HAS_UNSETENV=${KWSYS_CXX_HAS_UNSETENV} -DKWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=${KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H}") + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMES + "Checking whether CXX compiler has utimes" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMENSAT + "Checking whether CXX compiler has utimensat" DIRECT) + SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV} + KWSYS_CXX_HAS_UNSETENV=${KWSYS_CXX_HAS_UNSETENV} + KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=${KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H} + KWSYS_CXX_HAS_UTIMES=${KWSYS_CXX_HAS_UTIMES} + KWSYS_CXX_HAS_UTIMENSAT=${KWSYS_CXX_HAS_UTIMENSAT} + ) ENDIF() IF(KWSYS_USE_SystemInformation) diff --git a/Source/kwsys/CommandLineArguments.hxx.in b/Source/kwsys/CommandLineArguments.hxx.in index 68e9600ef2..cbf6ee3938 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 8521099ad6..8bbc74ac26 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 9e2a93d7c2..9db1dee381 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 8f4cb4e5a8..f7c454e0d4 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 22bf193b08..4d5af5ea75 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -605,7 +605,7 @@ bool SystemTools::MakeDirectory(const char* path) } if(SystemTools::FileExists(path)) { - return true; + return SystemTools::FileIsDirectory(path); } kwsys_stl::string dir = path; if(dir.size() == 0) @@ -1124,22 +1124,58 @@ bool SystemTools::Touch(const char* filename, bool create) } return false; } -#ifdef _MSC_VER -#define utime _utime -#define utimbuf _utimbuf -#endif - struct stat fromStat; - if(stat(filename, &fromStat) < 0) +#if defined(_WIN32) && !defined(__CYGWIN__) + HANDLE h = CreateFile(filename, FILE_WRITE_ATTRIBUTES, + FILE_SHARE_WRITE, 0, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, 0); + if(!h) + { + return false; + } + FILETIME mtime; + GetSystemTimeAsFileTime(&mtime); + if(!SetFileTime(h, 0, 0, &mtime)) { + CloseHandle(h); return false; } - struct utimbuf buf; - buf.actime = fromStat.st_atime; - buf.modtime = static_cast<time_t>(SystemTools::GetTime()); - if(utime(filename, &buf) < 0) + CloseHandle(h); +#elif KWSYS_CXX_HAS_UTIMENSAT + struct timespec times[2] = {{0,UTIME_OMIT},{0,UTIME_NOW}}; + if(utimensat(AT_FDCWD, filename, times, 0) < 0) { return false; } +#else + struct stat st; + if(stat(filename, &st) < 0) + { + return false; + } + struct timeval mtime; + gettimeofday(&mtime, 0); +# if KWSYS_CXX_HAS_UTIMES + struct timeval times[2] = + { +# if KWSYS_STAT_HAS_ST_MTIM + {st.st_atim.tv_sec, st.st_atim.tv_nsec/1000}, /* tv_sec, tv_usec */ +# else + {st.st_atime, 0}, +# endif + mtime + }; + if(utimes(filename, times) < 0) + { + return false; + } +# else + struct utimbuf times = {st.st_atime, mtime.tv_sec}; + if(utime(filename, ×) < 0) + { + return false; + } +# endif +#endif return true; } @@ -2741,15 +2777,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. @@ -3040,7 +3085,7 @@ SystemToolsAppendComponents( { if(*i == "..") { - if(out_components.begin() != out_components.end()) + if(out_components.size() > 1) { out_components.erase(out_components.end()-1, out_components.end()); } @@ -4002,7 +4047,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 9c56e96b07..e55d4319f9 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/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx index 48976c442a..a7e3b50c0d 100644 --- a/Source/kwsys/kwsysPlatformTestsCXX.cxx +++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx @@ -494,6 +494,25 @@ int main() } #endif +#ifdef TEST_KWSYS_CXX_HAS_UTIMES +#include <sys/time.h> +int main() +{ + struct timeval* current_time = 0; + return utimes("/example", current_time); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_UTIMENSAT +#include <fcntl.h> +#include <sys/stat.h> +int main() +{ + struct timespec times[2] = {{0,UTIME_OMIT},{0,UTIME_NOW}}; + return utimensat(AT_FDCWD, "/example", times, AT_SYMLINK_NOFOLLOW); +} +#endif + #ifdef TEST_KWSYS_CXX_TYPE_INFO /* Collect fundamental type information and save it to a CMake script. */ diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx index 61c157291e..dd6d603909 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 3b971e2687..f0c7f1a7bc 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 49a686c175..738043f77e 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"; } |