diff options
author | Kévin THIERRY <kevin.thierry@open.eurogiciel.org> | 2014-12-23 09:30:24 +0100 |
---|---|---|
committer | Kévin THIERRY <kevin.thierry@open.eurogiciel.org> | 2014-12-23 09:30:24 +0100 |
commit | 317dbdb79761ef65e45c7358cfc7571c6afa54ad (patch) | |
tree | d6e8d59029aea04ca4a0579fb1c19c3e493af78f /Source | |
parent | 297c63fa65327491a2b50e521b661c5835a19fe4 (diff) | |
download | cmake-317dbdb79761ef65e45c7358cfc7571c6afa54ad.tar.gz cmake-317dbdb79761ef65e45c7358cfc7571c6afa54ad.tar.bz2 cmake-317dbdb79761ef65e45c7358cfc7571c6afa54ad.zip |
Imported Upstream version 2.8.12.2upstream/2.8.12.2sandbox/kevinthierry/upstream
Diffstat (limited to 'Source')
249 files changed, 10159 insertions, 2871 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index f0519fe7c..8412e3e86 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 @@ -385,7 +394,7 @@ if(WIN32 AND NOT CYGWIN AND NOT BORLAND) set_source_files_properties(cmcldeps.cxx PROPERTIES COMPILE_DEFINITIONS _WIN32_WINNT=0x0501) add_executable(cmcldeps cmcldeps.cxx) target_link_libraries(cmcldeps CMakeLib) - install_targets(/bin cmcldeps) + install(TARGETS cmcldeps DESTINATION bin) endif() # create a library used by the command line and the GUI @@ -539,12 +548,13 @@ 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) target_link_libraries(cmw9xcom CMakeLib) - install_targets(/bin cmw9xcom) + install(TARGETS cmw9xcom DESTINATION bin) endif() endif() @@ -570,11 +580,9 @@ endif() include (${CMake_BINARY_DIR}/Source/LocalUserOptions.cmake OPTIONAL) include (${CMake_SOURCE_DIR}/Source/LocalUserOptions.cmake OPTIONAL) -install_targets(/bin cmake) -install_targets(/bin ctest) -install_targets(/bin cpack) +install(TARGETS cmake ctest cpack DESTINATION bin) if(APPLE) - install_targets(/bin cmakexbuild) + install(TARGETS cmakexbuild DESTINATION bin) endif() -install_files(${CMAKE_DATA_DIR}/include cmCPluginAPI.h) +install(FILES cmCPluginAPI.h DESTINATION ${CMAKE_DATA_DIR}/include) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index a8b890775..fd315ce6c 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 11) +set(CMake_VERSION_PATCH 12) set(CMake_VERSION_TWEAK 2) #set(CMake_VERSION_RC 0) diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index e8b0ea971..cc9dec7b8 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -100,6 +100,11 @@ bool cmCPackWIXGenerator::RunLightCommand(const std::string& objectFiles) command << " -nologo"; command << " -out " << QuotePath(packageFileNames.at(0)); command << " -ext WixUIExtension"; + const char* const cultures = GetOption("CPACK_WIX_CULTURES"); + if(cultures) + { + command << " -cultures:" << cultures; + } command << " " << objectFiles; return RunWiXCommand(command.str()); @@ -224,6 +229,9 @@ bool cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_ICON"); CopyDefinition(includeFile, "CPACK_WIX_UI_BANNER"); CopyDefinition(includeFile, "CPACK_WIX_UI_DIALOG"); + SetOptionIfNotSet("CPACK_WIX_PROGRAM_MENU_FOLDER", + GetOption("CPACK_PACKAGE_NAME")); + CopyDefinition(includeFile, "CPACK_WIX_PROGRAM_MENU_FOLDER"); return true; } @@ -339,25 +347,114 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() featureDefinitions.BeginElement("FeatureRef"); featureDefinitions.AddAttribute("Id", "ProductFeature"); + const char *cpackPackageExecutables = GetOption("CPACK_PACKAGE_EXECUTABLES"); + std::vector<std::string> cpackPkgExecutables; + std::string regKey; + if ( cpackPackageExecutables ) + { + cmSystemTools::ExpandListArgument(cpackPackageExecutables, + cpackPkgExecutables); + if ( cpackPkgExecutables.size() % 2 != 0 ) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and " + "<icon name>." << std::endl); + cpackPkgExecutables.clear(); + } + + const char *cpackVendor = GetOption("CPACK_PACKAGE_VENDOR"); + const char *cpackPkgName = GetOption("CPACK_PACKAGE_NAME"); + if (!cpackVendor || !cpackPkgName) + { + cmCPackLogger(cmCPackLog::LOG_WARNING, "CPACK_PACKAGE_VENDOR and " + "CPACK_PACKAGE_NAME must be defined for shortcut creation" << std::endl); + cpackPkgExecutables.clear(); + } + else + { + regKey = std::string("Software/") + cpackVendor + "/" + cpackPkgName; + } + } + + std::vector<std::string> dirIdExecutables; AddDirectoryAndFileDefinitons( toplevel, "INSTALL_ROOT", directoryDefinitions, fileDefinitions, featureDefinitions, - directoryCounter, fileCounter); + directoryCounter, fileCounter, cpackPkgExecutables, dirIdExecutables); - featureDefinitions.EndElement(); - featureDefinitions.EndElement(); - fileDefinitions.EndElement(); + directoryDefinitions.EndElement(); + directoryDefinitions.EndElement(); - for(size_t i = 1; i < install_root.size(); ++i) + if (dirIdExecutables.size() > 0 && dirIdExecutables.size() % 3 == 0) { - directoryDefinitions.EndElement(); - } + fileDefinitions.BeginElement("DirectoryRef"); + fileDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER"); + fileDefinitions.BeginElement("Component"); + fileDefinitions.AddAttribute("Id", "SHORTCUT"); + fileDefinitions.AddAttribute("Guid", "*"); - directoryDefinitions.EndElement(); - directoryDefinitions.EndElement(); + std::vector<std::string>::iterator it; + for ( it = dirIdExecutables.begin() ; + it != dirIdExecutables.end(); + ++it) + { + std::string fileName = *it++; + std::string iconName = *it++; + std::string directoryId = *it; + + fileDefinitions.BeginElement("Shortcut"); + std::string shortcutName = fileName; // the iconName is mor likely to contain blanks early on + std::string::size_type const dotPos = shortcutName.find('.'); + if(std::string::npos == dotPos) + { shortcutName = shortcutName.substr(0, dotPos); } + fileDefinitions.AddAttribute("Id", "SHORTCUT_" + shortcutName); + fileDefinitions.AddAttribute("Name", iconName); + std::string target = "[" + directoryId + "]" + fileName; + fileDefinitions.AddAttribute("Target", target); + fileDefinitions.AddAttribute("WorkingDirectory", directoryId); + fileDefinitions.EndElement(); + } + fileDefinitions.BeginElement("Shortcut"); + fileDefinitions.AddAttribute("Id", "UNINSTALL"); + std::string pkgName = GetOption("CPACK_PACKAGE_NAME"); + fileDefinitions.AddAttribute("Name", "Uninstall " + pkgName); + fileDefinitions.AddAttribute("Description", "Uninstalls " + pkgName); + fileDefinitions.AddAttribute("Target", "[SystemFolder]msiexec.exe"); + fileDefinitions.AddAttribute("Arguments", "/x [ProductCode]"); + fileDefinitions.EndElement(); + fileDefinitions.BeginElement("RemoveFolder"); + fileDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER"); + fileDefinitions.AddAttribute("On", "uninstall"); + fileDefinitions.EndElement(); + fileDefinitions.BeginElement("RegistryValue"); + fileDefinitions.AddAttribute("Root", "HKCU"); + fileDefinitions.AddAttribute("Key", regKey); + fileDefinitions.AddAttribute("Name", "installed"); + fileDefinitions.AddAttribute("Type", "integer"); + fileDefinitions.AddAttribute("Value", "1"); + fileDefinitions.AddAttribute("KeyPath", "yes"); + + featureDefinitions.BeginElement("ComponentRef"); + featureDefinitions.AddAttribute("Id", "SHORTCUT"); + featureDefinitions.EndElement(); + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", "ProgramMenuFolder"); + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER"); + const char *startMenuFolder = GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER"); + directoryDefinitions.AddAttribute("Name", startMenuFolder); + } + + featureDefinitions.EndElement(); + featureDefinitions.EndElement(); + fileDefinitions.EndElement(); directoryDefinitions.EndElement(); std::string wixTemplate = FindTemplate("WIX.template.in"); + if(GetOption("CPACK_WIX_TEMPLATE") != 0) + { + wixTemplate = GetOption("CPACK_WIX_TEMPLATE"); + } if(wixTemplate.empty()) { cmCPackLogger(cmCPackLog::LOG_ERROR, @@ -435,7 +532,9 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( cmWIXSourceWriter& fileDefinitions, cmWIXSourceWriter& featureDefinitions, size_t& directoryCounter, - size_t& fileCounter) + size_t& fileCounter, + const std::vector<std::string>& pkgExecutables, + std::vector<std::string>& dirIdExecutables) { cmsys::Directory dir; dir.Load(topdir.c_str()); @@ -467,8 +566,9 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( fileDefinitions, featureDefinitions, directoryCounter, - fileCounter); - + fileCounter, + pkgExecutables, + dirIdExecutables); directoryDefinitions.EndElement(); } else @@ -499,6 +599,23 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( featureDefinitions.BeginElement("ComponentRef"); featureDefinitions.AddAttribute("Id", componentId); featureDefinitions.EndElement(); + + std::vector<std::string>::const_iterator it; + for (it = pkgExecutables.begin() ; + it != pkgExecutables.end() ; + ++it) + { + std::string execName = *it++; + std::string iconName = *it; + + if (cmSystemTools::LowerCase(fileName) == + cmSystemTools::LowerCase(execName) + ".exe") + { + dirIdExecutables.push_back(fileName); + dirIdExecutables.push_back(iconName); + dirIdExecutables.push_back(directoryId); + } + } } } } diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h index 0e95d70f6..aaccf9d46 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.h +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -83,7 +83,11 @@ private: cmWIXSourceWriter& fileDefinitions, cmWIXSourceWriter& featureDefinitions, size_t& directoryCounter, - size_t& fileCounter); + size_t& fileCounter, + const std::vector<std::string>& pkgExecutables, + std::vector<std::string>& dirIdExecutables + ); + bool RequireOption(const std::string& name, std::string& value) const; diff --git a/Source/CPack/cmCPackDocumentVariables.cxx b/Source/CPack/cmCPackDocumentVariables.cxx index 6a841fa8d..8b16ae985 100644 --- a/Source/CPack/cmCPackDocumentVariables.cxx +++ b/Source/CPack/cmCPackDocumentVariables.cxx @@ -28,7 +28,7 @@ void cmCPackDocumentVariables::DefineVariables(cmake* cm) " the so-called top level directory. The purpose of" " is to include (set to 1 or ON or TRUE) the top level directory" " in the package or not (set to 0 or OFF or FALSE).\n" - "Each CPack generator as a built-in default value for this" + "Each CPack generator has a built-in default value for this" " variable. E.g. Archive generators (ZIP, TGZ, ...) includes" " the top level whereas RPM or DEB don't. The user may override" " the default value by setting this variable.\n" @@ -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 7cc152269..3c685bd9d 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/cmCTestBatchTestHandler.cxx b/Source/CTest/cmCTestBatchTestHandler.cxx index a22c7be41..934481b88 100644 --- a/Source/CTest/cmCTestBatchTestHandler.cxx +++ b/Source/CTest/cmCTestBatchTestHandler.cxx @@ -89,7 +89,7 @@ void cmCTestBatchTestHandler::WriteTestCommand(int test, std::fstream& fout) command = cmSystemTools::ConvertToOutputPath(command.c_str()); //Prepends memcheck args to our command string if this is a memcheck - this->TestHandler->GenerateTestCommand(processArgs); + this->TestHandler->GenerateTestCommand(processArgs, test); processArgs.push_back(command); for(std::vector<std::string>::iterator arg = processArgs.begin(); diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx index f4d38cef1..1f63185c1 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 d6d39a98f..db33cb68e 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 453e32ce2..2e2feb047 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 80218ad38..3ae2ac6a7 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: @@ -201,6 +200,7 @@ void cmCTestMemCheckHandler::Initialize() this->CustomMaximumPassedTestOutputSize = 0; this->CustomMaximumFailedTestOutputSize = 0; this->MemoryTester = ""; + this->MemoryTesterDynamicOptions.clear(); this->MemoryTesterOptions.clear(); this->MemoryTesterStyle = UNKNOWN; this->MemoryTesterOutputFile = ""; @@ -243,12 +243,28 @@ int cmCTestMemCheckHandler::PostProcessHandler() //---------------------------------------------------------------------- void cmCTestMemCheckHandler::GenerateTestCommand( - std::vector<std::string>& args) + std::vector<std::string>& args, int test) { std::vector<cmStdString>::size_type pp; - std::string memcheckcommand = ""; - memcheckcommand + cmStdString index; + cmOStringStream stream; + std::string memcheckcommand = cmSystemTools::ConvertToOutputPath(this->MemoryTester.c_str()); + stream << test; + index = stream.str(); + for ( pp = 0; pp < this->MemoryTesterDynamicOptions.size(); pp ++ ) + { + cmStdString arg = this->MemoryTesterDynamicOptions[pp]; + cmStdString::size_type pos = arg.find("??"); + if (pos != cmStdString::npos) + { + arg.replace(pos, 2, index); + } + args.push_back(arg); + memcheckcommand += " \""; + memcheckcommand += arg; + memcheckcommand += "\""; + } for ( pp = 0; pp < this->MemoryTesterOptions.size(); pp ++ ) { args.push_back(this->MemoryTesterOptions[pp]); @@ -461,13 +477,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( @@ -486,18 +495,19 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() = cmSystemTools::ParseArguments(memoryTesterOptions.c_str()); this->MemoryTesterOutputFile - = this->CTest->GetBinaryDir() + "/Testing/Temporary/MemoryChecker.log"; + = this->CTest->GetBinaryDir() + + "/Testing/Temporary/MemoryChecker.??.log"; 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 +526,11 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() + this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile"); this->MemoryTesterOptions.push_back(suppressions); } + std::string outputFile = "--log-file=" + + this->MemoryTesterOutputFile; + this->MemoryTesterDynamicOptions.push_back(outputFile); break; + } case cmCTestMemCheckHandler::PURIFY: { std::string outputFile; @@ -542,19 +556,19 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() outputFile = "-log-file="; #endif outputFile += this->MemoryTesterOutputFile; - this->MemoryTesterOptions.push_back(outputFile); + this->MemoryTesterDynamicOptions.push_back(outputFile); break; } case cmCTestMemCheckHandler::BOUNDS_CHECKER: { this->BoundsCheckerXMLFile = this->MemoryTesterOutputFile; std::string dpbdFile = this->CTest->GetBinaryDir() - + "/Testing/Temporary/MemoryChecker.DPbd"; + + "/Testing/Temporary/MemoryChecker.??.DPbd"; this->BoundsCheckerDPBDFile = dpbdFile; - this->MemoryTesterOptions.push_back("/B"); - this->MemoryTesterOptions.push_back(dpbdFile); - this->MemoryTesterOptions.push_back("/X"); - this->MemoryTesterOptions.push_back(this->MemoryTesterOutputFile); + this->MemoryTesterDynamicOptions.push_back("/B"); + this->MemoryTesterDynamicOptions.push_back(dpbdFile); + this->MemoryTesterDynamicOptions.push_back("/X"); + this->MemoryTesterDynamicOptions.push_back(this->MemoryTesterOutputFile); this->MemoryTesterOptions.push_back("/M"); break; } @@ -902,25 +916,23 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput( // This method puts the bounds checker output file into the output // for the test void -cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res) +cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res, + int test) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "PostProcessBoundsCheckerTest for : " << res.Name.c_str() << std::endl); - if ( !cmSystemTools::FileExists(this->MemoryTesterOutputFile.c_str()) ) + cmStdString ofile = testOutputFileName(test); + if ( ofile.empty() ) { - std::string log = "Cannot find memory tester output file: " - + this->MemoryTesterOutputFile; - cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl); return; } // put a scope around this to close ifs so the file can be removed { - std::ifstream ifs(this->MemoryTesterOutputFile.c_str()); + std::ifstream ifs(ofile.c_str()); if ( !ifs ) { - std::string log = "Cannot read memory tester output file: " - + this->MemoryTesterOutputFile; + std::string log = "Cannot read memory tester output file: " + ofile; cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl); return; } @@ -943,23 +955,39 @@ cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res) } void -cmCTestMemCheckHandler::PostProcessPurifyTest(cmCTestTestResult& res) +cmCTestMemCheckHandler::PostProcessPurifyTest(cmCTestTestResult& res, + int test) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "PostProcessPurifyTest for : " << res.Name.c_str() << std::endl); - if ( !cmSystemTools::FileExists(this->MemoryTesterOutputFile.c_str()) ) + appendMemTesterOutput(res, test); +} + +void +cmCTestMemCheckHandler::PostProcessValgrindTest(cmCTestTestResult& res, + int test) +{ + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "PostProcessValgrindTest for : " + << res.Name.c_str() << std::endl); + appendMemTesterOutput(res, test); +} + +void +cmCTestMemCheckHandler::appendMemTesterOutput(cmCTestTestResult& res, + int test) +{ + cmStdString ofile = testOutputFileName(test); + + if ( ofile.empty() ) { - std::string log = "Cannot find memory tester output file: " - + this->MemoryTesterOutputFile; - cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl); return; } - std::ifstream ifs(this->MemoryTesterOutputFile.c_str()); + std::ifstream ifs(ofile.c_str()); if ( !ifs ) { - std::string log = "Cannot read memory tester output file: " - + this->MemoryTesterOutputFile; + std::string log = "Cannot read memory tester output file: " + ofile; cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl); return; } @@ -970,3 +998,25 @@ cmCTestMemCheckHandler::PostProcessPurifyTest(cmCTestTestResult& res) res.Output += "\n"; } } + +cmStdString +cmCTestMemCheckHandler::testOutputFileName(int test) +{ + cmStdString index; + cmOStringStream stream; + stream << test; + index = stream.str(); + cmStdString ofile = this->MemoryTesterOutputFile; + cmStdString::size_type pos = ofile.find("??"); + ofile.replace(pos, 2, index); + + if ( !cmSystemTools::FileExists(ofile.c_str()) ) + { + std::string log = "Cannot find memory tester output file: " + + ofile; + cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl); + ofile = ""; + } + + return ofile; +} diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h index 1e81c893b..040d2e092 100644 --- a/Source/CTest/cmCTestMemCheckHandler.h +++ b/Source/CTest/cmCTestMemCheckHandler.h @@ -37,7 +37,7 @@ public: protected: virtual int PreProcessHandler(); virtual int PostProcessHandler(); - virtual void GenerateTestCommand(std::vector<std::string>& args); + virtual void GenerateTestCommand(std::vector<std::string>& args, int test); private: @@ -89,6 +89,7 @@ private: std::string BoundsCheckerDPBDFile; std::string BoundsCheckerXMLFile; std::string MemoryTester; + std::vector<cmStdString> MemoryTesterDynamicOptions; std::vector<cmStdString> MemoryTesterOptions; int MemoryTesterStyle; std::string MemoryTesterOutputFile; @@ -117,8 +118,16 @@ private: bool ProcessMemCheckBoundsCheckerOutput(const std::string& str, std::string& log, int* results); - void PostProcessPurifyTest(cmCTestTestResult& res); - void PostProcessBoundsCheckerTest(cmCTestTestResult& res); + void PostProcessPurifyTest(cmCTestTestResult& res, int test); + void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test); + void PostProcessValgrindTest(cmCTestTestResult& res, int test); + + ///! append MemoryTesterOutputFile to the test log + void appendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res, + int test); + + ///! generate the output filename for the given test index + cmStdString testOutputFileName(int test); }; #endif diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 5eabf3fbe..0e2fa41b9 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, this->Index); + break; + case cmCTestMemCheckHandler::PURIFY: + handler->PostProcessPurifyTest(this->TestResult, this->Index); + break; + case cmCTestMemCheckHandler::BOUNDS_CHECKER: + handler->PostProcessBoundsCheckerTest(this->TestResult, this->Index); + break; + default: + break; } } @@ -516,7 +524,7 @@ void cmCTestRunTest::ComputeArguments() = cmSystemTools::ConvertToOutputPath(this->ActualCommand.c_str()); //Prepends memcheck args to our command string - this->TestHandler->GenerateTestCommand(this->Arguments); + this->TestHandler->GenerateTestCommand(this->Arguments, this->Index); for(std::vector<std::string>::iterator i = this->Arguments.begin(); i != this->Arguments.end(); ++i) { diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 142bb4613..941d34877 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -120,7 +120,7 @@ static size_t cmCTestSubmitHandlerWriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { - register int realsize = (int)(size * nmemb); + int realsize = (int)(size * nmemb); cmCTestSubmitHandlerVectorOfChar *vec = static_cast<cmCTestSubmitHandlerVectorOfChar*>(data); diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index e7491bba3..497774d1b 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; } @@ -1108,7 +1107,7 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed, } //---------------------------------------------------------------------- -void cmCTestTestHandler::GenerateTestCommand(std::vector<std::string>&) +void cmCTestTestHandler::GenerateTestCommand(std::vector<std::string>&, int) { } @@ -1303,10 +1302,9 @@ int cmCTestTestHandler::ExecuteCommands(std::vector<cmStdString>& vec) for ( it = vec.begin(); it != vec.end(); ++it ) { int retVal = 0; - std::string cmd = cmSystemTools::ConvertToOutputPath(it->c_str()); - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run command: " << cmd + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run command: " << *it << std::endl); - if ( !cmSystemTools::RunSingleCommand(cmd.c_str(), 0, &retVal, 0, + if ( !cmSystemTools::RunSingleCommand(it->c_str(), 0, &retVal, 0, cmSystemTools::OUTPUT_MERGE /*this->Verbose*/) || retVal != 0 ) { @@ -1363,7 +1361,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 +1372,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/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index 8e59e5915..93b793b20 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -153,7 +153,7 @@ protected: // compute a final test list virtual int PreProcessHandler(); virtual int PostProcessHandler(); - virtual void GenerateTestCommand(std::vector<std::string>& args); + virtual void GenerateTestCommand(std::vector<std::string>& args, int test); int ExecuteCommands(std::vector<cmStdString>& vec); void WriteTestResultHeader(std::ostream& os, cmCTestTestResult* result); diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx index 5dfcfe50a..6b4adb4bd 100644 --- a/Source/CTest/cmParseGTMCoverage.cxx +++ b/Source/CTest/cmParseGTMCoverage.cxx @@ -98,7 +98,7 @@ bool cmParseGTMCoverage::ReadMCovFile(const char* file) bool found = this->FindMumpsFile(routine, filepath); if(found) { - int lineoffset; + int lineoffset = 0; if(this->FindFunctionInMumpsFile(filepath, function, lineoffset)) @@ -106,8 +106,8 @@ bool cmParseGTMCoverage::ReadMCovFile(const char* file) cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector = this->Coverage.TotalCoverage[filepath]; coverageVector[lineoffset + linenumber] += count; + lastoffset = lineoffset; } - lastoffset = lineoffset; } else { diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 000bc8503..167b992c9 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/CMakeLists.txt b/Source/CursesDialog/CMakeLists.txt index 96e28b491..5efc2fb1a 100644 --- a/Source/CursesDialog/CMakeLists.txt +++ b/Source/CursesDialog/CMakeLists.txt @@ -34,4 +34,4 @@ add_executable(ccmake ${CURSES_SRCS} ) target_link_libraries(ccmake CMakeLib) target_link_libraries(ccmake cmForm) -install_targets(/bin ccmake) +install(TARGETS ccmake DESTINATION bin) diff --git a/Source/CursesDialog/form/frm_driver.c b/Source/CursesDialog/form/frm_driver.c index f234722f3..b9611bf10 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 8fc4cd7b6..59058a98c 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/CursesDialog/form/fty_ipv4.c b/Source/CursesDialog/form/fty_ipv4.c index 4ac8a50ec..c855af655 100644 --- a/Source/CursesDialog/form/fty_ipv4.c +++ b/Source/CursesDialog/form/fty_ipv4.c @@ -30,7 +30,7 @@ static bool Check_IPV4_Field(FIELD * field, const void * argp) { char *bp = field_buffer(field,0); int num = 0, len; - unsigned int d1, d2, d3, d4; + unsigned int d1=256, d2=256, d3=256, d4=256; argp=0; /* Silence unused parameter warning. */ diff --git a/Source/CursesDialog/form/fty_regex.c b/Source/CursesDialog/form/fty_regex.c index 0af1cef17..f90e0c108 100644 --- a/Source/CursesDialog/form/fty_regex.c +++ b/Source/CursesDialog/form/fty_regex.c @@ -40,7 +40,7 @@ static char *RegEx_Error(int code) return 0; } -#define INIT register char *sp = RegEx_Init(instring); +#define INIT char *sp = RegEx_Init(instring); #define GETC() (*sp++) #define PEEKC() (*sp) #define UNGETC(c) (--sp) diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt index 1684fb229..ef252944e 100644 --- a/Source/QtDialog/CMakeLists.txt +++ b/Source/QtDialog/CMakeLists.txt @@ -11,6 +11,9 @@ #============================================================================= project(QtDialog) +if(POLICY CMP0020) + cmake_policy(SET CMP0020 NEW) # Drop when CMake >= 2.8.11 required +endif() find_package(Qt5Widgets QUIET) if (Qt5Widgets_FOUND) include_directories(${Qt5Widgets_INCLUDE_DIRS}) @@ -29,6 +32,11 @@ if (Qt5Widgets_FOUND) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") + + if(WIN32 AND TARGET Qt5::Core) + get_property(_Qt5_Core_LOCATION TARGET Qt5::Core PROPERTY LOCATION) + get_filename_component(Qt_BIN_DIR "${_Qt5_Core_LOCATION}" PATH) + endif() else() set(QT_MIN_VERSION "4.4.0") find_package(Qt4 REQUIRED) @@ -38,6 +46,13 @@ else() endif() include(${QT_USE_FILE}) + + if(WIN32 AND EXISTS "${QT_QMAKE_EXECUTABLE}") + get_filename_component(_Qt_BIN_DIR "${QT_QMAKE_EXECUTABLE}" PATH) + if(EXISTS "${_Qt_BIN_DIR}/QtCore4.dll") + set(Qt_BIN_DIR ${_Qt_BIN_DIR}) + endif() + endif() endif() set(SRCS @@ -91,6 +106,9 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) add_executable(cmake-gui WIN32 MACOSX_BUNDLE ${SRCS}) target_link_libraries(cmake-gui CMakeLib ${QT_QTMAIN_LIBRARY} ${QT_LIBRARIES}) +if(Qt_BIN_DIR) + set_property(TARGET cmake-gui PROPERTY Qt_BIN_DIR ${Qt_BIN_DIR}) +endif() if(APPLE) set_target_properties(cmake-gui PROPERTIES diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index c0dde1c2c..4d62f7263 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 259967580..963c7d12e 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 dc8ee3fbd..98da249d5 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 6006758c7..bae6a30a7 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 000000000..a6c3c005c --- /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 000000000..e9bbf2816 --- /dev/null +++ b/Source/cmAddCompileOptionsCommand.h @@ -0,0 +1,71 @@ +/*============================================================================ + 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 + ; + } + + cmTypeMacro(cmAddCompileOptionsCommand, cmCommand); +}; + +#endif diff --git a/Source/cmAddDefinitionsCommand.h b/Source/cmAddDefinitionsCommand.h index 7bb37674d..ff2c4a038 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/cmAddDependenciesCommand.cxx b/Source/cmAddDependenciesCommand.cxx index 04a304e39..e4d7f7f1e 100644 --- a/Source/cmAddDependenciesCommand.cxx +++ b/Source/cmAddDependenciesCommand.cxx @@ -24,6 +24,13 @@ bool cmAddDependenciesCommand } std::string target_name = args[0]; + if(this->Makefile->IsAlias(target_name.c_str())) + { + cmOStringStream e; + e << "Cannot add target-level dependencies to alias target \"" + << target_name << "\".\n"; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + } if(cmTarget* target = this->Makefile->FindTargetToUse(target_name.c_str())) { std::vector<std::string>::const_iterator s = args.begin(); diff --git a/Source/cmAddExecutableCommand.cxx b/Source/cmAddExecutableCommand.cxx index 6dd8e5c64..578525969 100644 --- a/Source/cmAddExecutableCommand.cxx +++ b/Source/cmAddExecutableCommand.cxx @@ -30,6 +30,7 @@ bool cmAddExecutableCommand bool excludeFromAll = false; bool importTarget = false; bool importGlobal = false; + bool isAlias = false; while ( s != args.end() ) { if (*s == "WIN32") @@ -57,6 +58,11 @@ bool cmAddExecutableCommand ++s; importGlobal = true; } + else if(*s == "ALIAS") + { + ++s; + isAlias = true; + } else { break; @@ -83,6 +89,72 @@ bool cmAddExecutableCommand } return false; } + if (isAlias) + { + if(!cmGeneratorExpression::IsValidTargetName(exename.c_str())) + { + this->SetError(("Invalid name for ALIAS: " + exename).c_str()); + return false; + } + if(excludeFromAll) + { + this->SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense."); + return false; + } + if(importTarget || importGlobal) + { + this->SetError("IMPORTED with ALIAS is not allowed."); + return false; + } + if(args.size() != 3) + { + cmOStringStream e; + e << "ALIAS requires exactly one target argument."; + this->SetError(e.str().c_str()); + return false; + } + + const char *aliasedName = s->c_str(); + if(this->Makefile->IsAlias(aliasedName)) + { + cmOStringStream e; + e << "cannot create ALIAS target \"" << exename + << "\" because target \"" << aliasedName << "\" is itself an ALIAS."; + this->SetError(e.str().c_str()); + return false; + } + cmTarget *aliasedTarget = + this->Makefile->FindTargetToUse(aliasedName, true); + if(!aliasedTarget) + { + cmOStringStream e; + e << "cannot create ALIAS target \"" << exename + << "\" because target \"" << aliasedName << "\" does not already " + "exist."; + this->SetError(e.str().c_str()); + return false; + } + cmTarget::TargetType type = aliasedTarget->GetType(); + if(type != cmTarget::EXECUTABLE) + { + cmOStringStream e; + e << "cannot create ALIAS target \"" << exename + << "\" because target \"" << aliasedName << "\" is not an " + "executable."; + this->SetError(e.str().c_str()); + return false; + } + if(aliasedTarget->IsImported()) + { + cmOStringStream e; + e << "cannot create ALIAS target \"" << exename + << "\" because target \"" << aliasedName << "\" is IMPORTED."; + this->SetError(e.str().c_str()); + return false; + } + this->Makefile->AddAlias(exename.c_str(), aliasedTarget); + return true; + } // Handle imported target creation. if(importTarget) diff --git a/Source/cmAddExecutableCommand.h b/Source/cmAddExecutableCommand.h index 1e9f9b3be..2774ce841 100644 --- a/Source/cmAddExecutableCommand.h +++ b/Source/cmAddExecutableCommand.h @@ -107,6 +107,19 @@ public: "(and its per-configuration version IMPORTED_LOCATION_<CONFIG>) " "which specifies the location of the main executable file on disk. " "See documentation of the IMPORTED_* properties for more information." + "\n" + "The signature\n" + " add_executable(<name> ALIAS <target>)\n" + "creates an alias, such that <name> can be used to refer to <target> " + "in subsequent commands. The <name> does not appear in the generated " + "buildsystem as a make target. The <target> may not be an IMPORTED " + "target or an ALIAS. Alias targets can be used as linkable targets, " + "targets to read properties from, executables for custom commands and " + "custom targets. They can also be tested for existance with the " + "regular if(TARGET) subcommand. The <name> may not be used to modify " + "properties of <target>, that is, it may not be used as the operand of " + "set_property, set_target_properties, target_link_libraries etc. An " + "ALIAS target may not be installed of exported." ; } diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index fd39eec02..cbc6ed1e9 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -43,6 +43,7 @@ bool cmAddLibraryCommand // the type of library. Otherwise, it is treated as a source or // source list name. There may be two keyword arguments, check for them bool haveSpecifiedType = false; + bool isAlias = false; while ( s != args.end() ) { std::string libType = *s; @@ -76,6 +77,11 @@ bool cmAddLibraryCommand type = cmTarget::UNKNOWN_LIBRARY; haveSpecifiedType = true; } + else if(libType == "ALIAS") + { + ++s; + isAlias = true; + } else if(*s == "EXCLUDE_FROM_ALL") { ++s; @@ -96,6 +102,80 @@ bool cmAddLibraryCommand break; } } + if (isAlias) + { + if(!cmGeneratorExpression::IsValidTargetName(libName.c_str())) + { + this->SetError(("Invalid name for ALIAS: " + libName).c_str()); + return false; + } + if(excludeFromAll) + { + this->SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense."); + return false; + } + if(importTarget || importGlobal) + { + this->SetError("IMPORTED with ALIAS is not allowed."); + return false; + } + if(args.size() != 3) + { + cmOStringStream e; + e << "ALIAS requires exactly one target argument."; + this->SetError(e.str().c_str()); + return false; + } + + const char *aliasedName = s->c_str(); + if(this->Makefile->IsAlias(aliasedName)) + { + cmOStringStream e; + e << "cannot create ALIAS target \"" << libName + << "\" because target \"" << aliasedName << "\" is itself an ALIAS."; + this->SetError(e.str().c_str()); + return false; + } + cmTarget *aliasedTarget = + this->Makefile->FindTargetToUse(aliasedName, true); + if(!aliasedTarget) + { + cmOStringStream e; + e << "cannot create ALIAS target \"" << libName + << "\" because target \"" << aliasedName << "\" does not already " + "exist."; + this->SetError(e.str().c_str()); + return false; + } + cmTarget::TargetType aliasedType = aliasedTarget->GetType(); + if(aliasedType != cmTarget::SHARED_LIBRARY + && aliasedType != cmTarget::STATIC_LIBRARY + && aliasedType != cmTarget::MODULE_LIBRARY + && aliasedType != cmTarget::OBJECT_LIBRARY) + { + cmOStringStream e; + e << "cannot create ALIAS target \"" << libName + << "\" because target \"" << aliasedName << "\" is not a library."; + this->SetError(e.str().c_str()); + return false; + } + if(aliasedTarget->IsImported()) + { + cmOStringStream e; + e << "cannot create ALIAS target \"" << libName + << "\" because target \"" << aliasedName << "\" is IMPORTED."; + this->SetError(e.str().c_str()); + return false; + } + this->Makefile->AddAlias(libName.c_str(), aliasedTarget); + return true; + } + + if(importTarget && excludeFromAll) + { + this->SetError("excludeFromAll with IMPORTED target makes no sense."); + return false; + } /* ideally we should check whether for the linker language of the target CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to diff --git a/Source/cmAddLibraryCommand.h b/Source/cmAddLibraryCommand.h index e5f27cb51..59354b0f5 100644 --- a/Source/cmAddLibraryCommand.h +++ b/Source/cmAddLibraryCommand.h @@ -138,6 +138,19 @@ public: "Some native build systems may not like targets that have only " "object files, so consider adding at least one real source file " "to any target that references $<TARGET_OBJECTS:objlib>." + "\n" + "The signature\n" + " add_library(<name> ALIAS <target>)\n" + "creates an alias, such that <name> can be used to refer to <target> " + "in subsequent commands. The <name> does not appear in the generated " + "buildsystem as a make target. The <target> may not be an IMPORTED " + "target or an ALIAS. Alias targets can be used as linkable targets, " + "targets to read properties from. They can also be tested for " + "existance with the " + "regular if(TARGET) subcommand. The <name> may not be used to modify " + "properties of <target>, that is, it may not be used as the operand of " + "set_property, set_target_properties, target_link_libraries etc. An " + "ALIAS target may not be installed of exported." ; } diff --git a/Source/cmAddSubDirectoryCommand.h b/Source/cmAddSubDirectoryCommand.h index fa322b0c4..e7f907c3f 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/cmAddTestCommand.h b/Source/cmAddTestCommand.h index 6a0cd9d2e..ec7fda3f3 100644 --- a/Source/cmAddTestCommand.h +++ b/Source/cmAddTestCommand.h @@ -71,6 +71,9 @@ public: " add_test(NAME <name> [CONFIGURATIONS [Debug|Release|...]]\n" " [WORKING_DIRECTORY dir]\n" " COMMAND <command> [arg1 [arg2 ...]])\n" + "Add a test called <name>. " + "The test name may not contain spaces, quotes, or other characters " + "special in CMake syntax. " "If COMMAND specifies an executable target (created by " "add_executable) it will automatically be replaced by the location " "of the executable created at build time. " diff --git a/Source/cmBootstrapCommands1.cxx b/Source/cmBootstrapCommands1.cxx new file mode 100644 index 000000000..9093579dc --- /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 e3a2ad4e5..be72526ba 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 91d55a5a2..b6e2569a5 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 000000000..62f238369 --- /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 000000000..d1b8700ff --- /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/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx index 48ae50e42..cb62f21e6 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -422,8 +422,9 @@ int CCONV cmExecuteCommand(void *arg, const char *name, for(int i = 0; i < numArgs; ++i) { // Assume all arguments are quoted. - lff.Arguments.push_back(cmListFileArgument(args[i], true, - "[CMake-Plugin]", 0)); + lff.Arguments.push_back( + cmListFileArgument(args[i], cmListFileArgument::Quoted, + "[CMake-Plugin]", 0)); } cmExecutionStatus status; return mf->ExecuteCommand(lff,status); diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 322a6a26f..14e1f5014 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -175,7 +175,7 @@ std::string cmCTest::GetCostDataFile() static size_t HTTPResponseCallback(void *ptr, size_t size, size_t nmemb, void *data) { - register int realsize = (int)(size * nmemb); + int realsize = (int)(size * nmemb); std::string *response = static_cast<std::string*>(data); @@ -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 587a6db51..5dd35ce41 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 3d5b24b84..ed09545cb 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 4a5ee450f..a5e5eeeff 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/cmCommandArgumentLexer.cxx b/Source/cmCommandArgumentLexer.cxx index 1d7140bb2..e68f6b5fd 100644 --- a/Source/cmCommandArgumentLexer.cxx +++ b/Source/cmCommandArgumentLexer.cxx @@ -730,9 +730,9 @@ extern int cmCommandArgument_yylex (yyscan_t yyscanner); */ YY_DECL { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; #line 64 "cmCommandArgumentLexer.in.l" @@ -782,7 +782,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1082,9 +1082,9 @@ return 0; /* this should not happend but it should silence a warning */ static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = yyg->yytext_ptr; - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) @@ -1216,15 +1216,15 @@ static int yy_get_next_buffer (yyscan_t yyscanner) static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { - register yy_state_type yy_current_state; - register char *yy_cp; + yy_state_type yy_current_state; + char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1249,11 +1249,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { - register int yy_is_jam; + int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ - register char *yy_cp = yyg->yy_c_buf_p; + char *yy_cp = yyg->yy_c_buf_p; - register YY_CHAR yy_c = 1; + YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -2015,7 +2015,7 @@ int cmCommandArgument_yylex_destroy (yyscan_t yyscanner) #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) { - register int i; + int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } @@ -2024,7 +2024,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysca #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) { - register int n; + int n; for ( n = 0; s[n]; ++n ) ; diff --git a/Source/cmCommandArgumentLexer.in.l b/Source/cmCommandArgumentLexer.in.l index fdca61bfa..24a0eec85 100644 --- a/Source/cmCommandArgumentLexer.in.l +++ b/Source/cmCommandArgumentLexer.in.l @@ -22,6 +22,7 @@ Modify cmCommandArgumentLexer.cxx: - add #include "cmStandardIncludes.h" to top of file - put header block at top of file - remove TABs + - remove use of the 'register' storage class specifier - remove "yyscanner" argument from these methods: yy_fatal_error, cmCommandArgument_yyalloc, cmCommandArgument_yyrealloc, cmCommandArgument_yyfree - remove all YY_BREAK lines occurring right after return statements diff --git a/Source/cmCommandArgumentParser.y b/Source/cmCommandArgumentParser.y index 3e700c80b..48f5c8ecd 100644 --- a/Source/cmCommandArgumentParser.y +++ b/Source/cmCommandArgumentParser.y @@ -20,6 +20,7 @@ Run bison like this: Modify cmCommandArgumentParser.cxx: - remove TABs + - remove use of the 'register' storage class specifier - put header block at top of file */ diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index 2f26b0cd4..dbeeb0793 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -12,10 +12,10 @@ #include "cmCommandArgumentParserHelper.h" #include "cmSystemTools.h" -#include "cmCommandArgumentLexer.h" - #include "cmMakefile.h" +#include "cmCommandArgumentLexer.h" + int cmCommandArgument_yyparse( yyscan_t yyscanner ); // cmCommandArgumentParserHelper::cmCommandArgumentParserHelper() diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index 227b22678..1e2a85cfb 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 096fc2006..c56673fed 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 896b50aa5..fb7b5b67d 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; @@ -1339,12 +1345,23 @@ void cmComputeLinkInformation::AddFrameworkItem(std::string const& item) return; } + std::string fw_path = this->SplitFramework.match(1); + std::string fw = this->SplitFramework.match(2); + std::string full_fw = fw_path; + full_fw += "/"; + full_fw += fw; + full_fw += ".framework"; + full_fw += "/"; + full_fw += fw; + // Add the directory portion to the framework search path. - this->AddFrameworkPath(this->SplitFramework.match(1)); + this->AddFrameworkPath(fw_path); + + // add runtime information + this->AddLibraryRuntimeInfo(full_fw); // Add the item using the -framework option. this->Items.push_back(Item("-framework", false)); - std::string fw = this->SplitFramework.match(2); fw = this->LocalGenerator->EscapeForShell(fw.c_str()); this->Items.push_back(Item(fw, false)); } @@ -1724,6 +1741,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 +1784,61 @@ 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) && + (std::string::npos != + splitFramework.match(3).find(splitFramework.match(2)))) + { + is_shared_library = true; + } } } + if(!is_shared_library) + { + return; + } + // Include this library in the runtime path ordering. this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath); if(this->LinkWithRuntimePath) diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 1a76922a5..e6ee87185 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/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 8fd95b9cd..0829add20 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -282,6 +282,8 @@ void cmComputeTargetDepends::AddInterfaceDepends(int depender_index, if(emitted.insert(*lib).second) { this->AddTargetDepend(depender_index, lib->c_str(), true); + this->AddInterfaceDepends(depender_index, lib->c_str(), + true, emitted); } } } diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index 114afd7b7..ab53b1d27 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -19,4 +19,4 @@ #cmakedefine CMAKE_STRICT #define CMAKE_ROOT_DIR "${CMake_SOURCE_DIR}" #define CMAKE_BUILD_DIR "${CMake_BINARY_DIR}" -#define CMAKE_DATA_DIR "@CMAKE_DATA_DIR@" +#define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@" diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 85e49a928..086f27a58 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -12,6 +12,7 @@ #include "cmCoreTryCompile.h" #include "cmake.h" #include "cmCacheManager.h" +#include "cmLocalGenerator.h" #include "cmGlobalGenerator.h" #include "cmExportTryCompileFileGenerator.h" #include <cmsys/Directory.hxx> @@ -23,150 +24,170 @@ 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::string copyFileError; + std::vector<cmTarget*> targets; + std::string libsToLink = " "; + bool useOldLinkLibs = true; + char targetNameBuf[64]; + bool didOutputVariable = false; + bool didCopyFile = false; + bool didCopyFileError = false; + bool useSources = argv[2] == "SOURCES"; + std::vector<std::string> sources; + + enum Doing { DoingNone, DoingCMakeFlags, DoingCompileDefinitions, + DoingLinkLibraries, DoingOutputVariable, DoingCopyFile, + DoingCopyFileError, 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(argv[i] == "COPY_FILE_ERROR") + { + doing = DoingCopyFileError; + didCopyFileError = 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 += "\"" + cmSystemTools::TrimWhitespace(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 == DoingCopyFileError) + { + copyFileError = 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; + } + + if(didCopyFileError && copyFileError.empty()) + { + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "COPY_FILE_ERROR must be followed by a variable name"); + return -1; + } + + if(didCopyFileError && !didCopyFile) + { + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "COPY_FILE_ERROR may be used only with COPY_FILE"); + return -1; + } + + if(didOutputVariable && outputVariable.empty()) + { + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "OUTPUT_VARIABLE must be followed by a variable name"); + return -1; } - // do we have a srcfile signature - if (argv.size() - extraArgs == 3) + if(useSources && sources.empty()) { - this->SrcFileSignature = true; + 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 +200,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 +234,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. + cmLocalGenerator* lg = this->Makefile->GetLocalGenerator(); + cmGlobalGenerator* gg = lg->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 +288,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 +297,48 @@ 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); + std::string langFlags = "CMAKE_" + *li + "_FLAGS"; + const char* flags = this->Makefile->GetDefinition(langFlags.c_str()); + fprintf(fout, "SET(CMAKE_%s_FLAGS %s)\n", li->c_str(), + lg->EscapeForCMake(flags?flags:"").c_str()); + fprintf(fout, "SET(CMAKE_%s_FLAGS \"${CMAKE_%s_FLAGS}" + " ${COMPILE_DEFINITIONS}\")\n", li->c_str(), li->c_str()); } - 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 +413,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 +439,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(); @@ -438,6 +470,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) if (this->SrcFileSignature) { + std::string copyFileErrorMessage; this->FindOutputFile(targetName); if ((res==0) && (copyFile.size())) @@ -455,10 +488,23 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) { emsg << this->FindErrorMessage.c_str(); } - this->Makefile->IssueMessage(cmake::FATAL_ERROR, emsg.str()); - return -1; + if(copyFileError.empty()) + { + this->Makefile->IssueMessage(cmake::FATAL_ERROR, emsg.str()); + return -1; + } + else + { + copyFileErrorMessage = emsg.str(); + } } } + + if(!copyFileError.empty()) + { + this->Makefile->AddDefinition(copyFileError.c_str(), + copyFileErrorMessage.c_str()); + } } return res; } diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index bd860ee6a..3620a3895 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -13,6 +13,8 @@ #include "cmMakefile.h" +#include <cmsys/auto_ptr.hxx> + //---------------------------------------------------------------------------- cmCustomCommand::cmCustomCommand() { @@ -36,6 +38,32 @@ cmCustomCommand::cmCustomCommand(const cmCustomCommand& r): } //---------------------------------------------------------------------------- +cmCustomCommand& cmCustomCommand::operator=(cmCustomCommand const& r) +{ + if(this == &r) + { + return *this; + } + + this->Outputs = r.Outputs; + this->Depends = r.Depends; + this->CommandLines = r.CommandLines; + this->HaveComment = r.HaveComment; + this->Comment = r.Comment; + this->WorkingDirectory = r.WorkingDirectory; + this->EscapeAllowMakeVars = r.EscapeAllowMakeVars; + this->EscapeOldStyle = r.EscapeOldStyle; + this->ImplicitDepends = r.ImplicitDepends; + + cmsys::auto_ptr<cmListFileBacktrace> + newBacktrace(new cmListFileBacktrace(*r.Backtrace)); + delete this->Backtrace; + this->Backtrace = newBacktrace.release(); + + return *this; +} + +//---------------------------------------------------------------------------- cmCustomCommand::cmCustomCommand(cmMakefile* mf, const std::vector<std::string>& outputs, const std::vector<std::string>& depends, diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index dd92e34d7..e20d2bf40 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -27,6 +27,7 @@ public: /** Default and copy constructors for STL containers. */ cmCustomCommand(); cmCustomCommand(const cmCustomCommand& r); + cmCustomCommand& operator=(cmCustomCommand const& r); /** Main constructor specifies all information for the command. */ cmCustomCommand(cmMakefile* mf, diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 43b7b8a60..a252a1ab7 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -193,17 +193,8 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources, // Construct the name of the file as if it were in the current // include directory. Avoid using a leading "./". - tempPathStr = ""; - if((*i) == ".") - { - tempPathStr += current.FileName; - } - else - { - tempPathStr += *i; - tempPathStr+="/"; - tempPathStr+=current.FileName; - } + tempPathStr = + cmSystemTools::CollapseCombinedPath(*i, current.FileName); // Look for the file in this location. if(cmSystemTools::FileExists(tempPathStr.c_str(), true)) @@ -458,9 +449,8 @@ void cmDependsC::Scan(std::istream& is, const char* directory, // This was a double-quoted include with a relative path. We // must check for the file in the directory containing the // file we are scanning. - entry.QuotedLocation = directory; - entry.QuotedLocation += "/"; - entry.QuotedLocation += entry.FileName; + entry.QuotedLocation = + cmSystemTools::CollapseCombinedPath(directory, entry.FileName); } // Queue the file if it has not yet been encountered and it diff --git a/Source/cmDependsFortranLexer.cxx b/Source/cmDependsFortranLexer.cxx index b0d9a742d..924d9d2a9 100644 --- a/Source/cmDependsFortranLexer.cxx +++ b/Source/cmDependsFortranLexer.cxx @@ -913,9 +913,9 @@ extern int cmDependsFortran_yylex (yyscan_t yyscanner); */ YY_DECL { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; #line 71 "cmDependsFortranLexer.in.l" @@ -966,7 +966,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1386,9 +1386,9 @@ ECHO; static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = yyg->yytext_ptr; - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) @@ -1520,8 +1520,8 @@ static int yy_get_next_buffer (yyscan_t yyscanner) static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { - register yy_state_type yy_current_state; - register char *yy_cp; + yy_state_type yy_current_state; + char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; @@ -1529,7 +1529,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1554,11 +1554,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { - register int yy_is_jam; + int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ - register char *yy_cp = yyg->yy_c_buf_p; + char *yy_cp = yyg->yy_c_buf_p; - register YY_CHAR yy_c = 1; + YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1576,9 +1576,9 @@ static int yy_get_next_buffer (yyscan_t yyscanner) return yy_is_jam ? 0 : yy_current_state; } - static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) + static void yyunput (int c, char * yy_bp , yyscan_t yyscanner) { - register char *yy_cp; + char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_cp = yyg->yy_c_buf_p; @@ -1589,10 +1589,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner) if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ - register int number_to_move = yyg->yy_n_chars + 2; - register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + int number_to_move = yyg->yy_n_chars + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; - register char *source = + char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) @@ -2359,7 +2359,7 @@ int cmDependsFortran_yylex_destroy (yyscan_t yyscanner) #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) { - register int i; + int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } @@ -2368,7 +2368,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysca #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) { - register int n; + int n; for ( n = 0; s[n]; ++n ) ; diff --git a/Source/cmDependsFortranLexer.in.l b/Source/cmDependsFortranLexer.in.l index 40e80b719..01488024e 100644 --- a/Source/cmDependsFortranLexer.in.l +++ b/Source/cmDependsFortranLexer.in.l @@ -30,6 +30,7 @@ Run flex like this: Modify cmDependsFortranLexer.cxx: - remove TABs + - remove use of the 'register' storage class specifier - remove "yyscanner" argument from these methods: yy_fatal_error, cmDependsFortran_yyalloc, cmDependsFortran_yyrealloc, cmDependsFortran_yyfree - remove "yyscanner = NULL" from end of cmDependsFortran_yylex_destroy diff --git a/Source/cmDependsFortranParser.y b/Source/cmDependsFortranParser.y index 5681d698c..d814f3075 100644 --- a/Source/cmDependsFortranParser.y +++ b/Source/cmDependsFortranParser.y @@ -33,6 +33,7 @@ Run bison like this: Modify cmDependsFortranParser.cxx: - remove TABs + - remove use of the 'register' storage class specifier - Remove the yyerrorlab block in range ["goto yyerrlab1", "yyerrlab1:"] */ diff --git a/Source/cmDependsJavaLexer.cxx b/Source/cmDependsJavaLexer.cxx index 63cfebcd7..0af44b02e 100644 --- a/Source/cmDependsJavaLexer.cxx +++ b/Source/cmDependsJavaLexer.cxx @@ -904,9 +904,9 @@ extern int cmDependsJava_yylex (yyscan_t yyscanner); */ YY_DECL { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; #line 88 "cmDependsJavaLexer.in.l" @@ -955,7 +955,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1604,9 +1604,9 @@ return 0; /* this should not happen but it silences a warning*/ static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = yyg->yytext_ptr; - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) @@ -1730,15 +1730,15 @@ static int yy_get_next_buffer (yyscan_t yyscanner) static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { - register yy_state_type yy_current_state; - register char *yy_cp; + yy_state_type yy_current_state; + char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1763,11 +1763,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { - register int yy_is_jam; + int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *yy_cp = yyg->yy_c_buf_p; + char *yy_cp = yyg->yy_c_buf_p; - register YY_CHAR yy_c = 1; + YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -2481,7 +2481,7 @@ int cmDependsJava_yylex_destroy (yyscan_t yyscanner) #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) { - register int i; + int i; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; @@ -2491,7 +2491,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysca #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) { - register int n; + int n; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; for ( n = 0; s[n]; ++n ) ; diff --git a/Source/cmDependsJavaLexer.in.l b/Source/cmDependsJavaLexer.in.l index 9796ad52a..aa2f8a587 100644 --- a/Source/cmDependsJavaLexer.in.l +++ b/Source/cmDependsJavaLexer.in.l @@ -20,6 +20,7 @@ Run flex like this: Modify cmDependsJavaLexer.c: - remove TABs + - remove use of the 'register' storage class specifier - remove "yyscanner" argument from these methods: yy_fatal_error, cmDependsJava_yyalloc, cmDependsJava_yyrealloc, cmDependsJava_yyfree - remove all YY_BREAK lines occurring right after return statements diff --git a/Source/cmDependsJavaParser.cxx b/Source/cmDependsJavaParser.cxx index 7f7c385da..586c0debe 100644 --- a/Source/cmDependsJavaParser.cxx +++ b/Source/cmDependsJavaParser.cxx @@ -446,7 +446,7 @@ union yyalloc # define YYCOPY(To, From, Count) \ do \ { \ - register YYSIZE_T yyi; \ + YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ @@ -1821,7 +1821,7 @@ yystrlen (yystr) const char *yystr; # endif { - register const char *yys = yystr; + const char *yys = yystr; while (*yys++ != '\0') continue; @@ -1846,8 +1846,8 @@ yystpcpy (yydest, yysrc) const char *yysrc; # endif { - register char *yyd = yydest; - register const char *yys = yysrc; + char *yyd = yydest; + const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; @@ -1977,8 +1977,8 @@ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; - register int yystate; - register int yyn; + int yystate; + int yyn; int yyresult; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; @@ -1996,12 +1996,12 @@ int yynerrs; /* The state stack. */ short int yyssa[YYINITDEPTH]; short int *yyss = yyssa; - register short int *yyssp; + short int *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; + YYSTYPE *yyvsp; diff --git a/Source/cmDependsJavaParser.y b/Source/cmDependsJavaParser.y index 53210b8ca..944d4b5ce 100644 --- a/Source/cmDependsJavaParser.y +++ b/Source/cmDependsJavaParser.y @@ -20,6 +20,7 @@ Run bison like this: Modify cmDependsJavaParser.cxx: - remove TABs + - remove use of the 'register' storage class specifier - add __HP_aCC to the #if test for yyerrorlab warning suppression */ diff --git a/Source/cmDocumentCompileDefinitions.h b/Source/cmDocumentCompileDefinitions.h index ef3b3e715..d15bd6dca 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 6cc3f25ae..46cd77eae 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,27 @@ "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" \ + " $<C_COMPILER_VERSION> = The version of the C compiler used.\n" \ + " $<C_COMPILER_VERSION:ver> = '1' if the version of the C " \ + "compiler matches ver, otherwise '0'.\n" \ + " $<CXX_COMPILER_VERSION> = The version of the CXX compiler " \ + "used.\n" \ + " $<CXX_COMPILER_VERSION:ver> = '1' if the version of the CXX " \ + "compiler matches ver, otherwise '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" \ diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index 61f9f5a25..c4f6216b6 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"); @@ -19,7 +19,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "The full path to the cmake executable.", "This is the full path to the CMake executable cmake which is " "useful from custom commands that want to use the cmake -E " - "option for portable system commands. " + "option for portable system commands. " "(e.g. /usr/local/bin/cmake", false, "Variables that Provide Information"); cm->DefineProperty @@ -27,14 +27,14 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "The path to the top level of the build tree.", "This is the full path to the top level of the current CMake " "build tree. For an in-source build, this would be the same " - "as CMAKE_SOURCE_DIR. ", false, + "as CMAKE_SOURCE_DIR.", false, "Variables that Provide Information"); cm->DefineProperty ("CMAKE_SOURCE_DIR", cmProperty::VARIABLE, "The path to the top level of the source tree.", "This is the full path to the top level of the current CMake " "source tree. For an in-source build, this would be the same " - "as CMAKE_BINARY_DIR. ", false, + "as CMAKE_BINARY_DIR.", false, "Variables that Provide Information"); cm->DefineProperty ("CMAKE_CURRENT_BINARY_DIR", cmProperty::VARIABLE, @@ -42,7 +42,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "This the full path to the build directory that is currently " "being processed by cmake. Each directory added by " "add_subdirectory will create a binary directory in the build " - "tree, and as it is being processed this variable will be set. " + "tree, and as it is being processed this variable will be set. " "For in-source builds this is the current source directory " "being processed.", false, "Variables that Provide Information"); @@ -100,7 +100,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_SCRIPT_MODE_FILE", cmProperty::VARIABLE, - "Full path to the -P script file currently being processed. ", + "Full path to the -P script file currently being processed.", "When run in -P script mode, CMake sets this variable to the full " "path of the script file. When run to configure a CMakeLists.txt " "file, this variable is not set.", false, @@ -108,14 +108,14 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_ARGC", cmProperty::VARIABLE, - "Number of command line arguments passed to CMake in script mode. ", + "Number of command line arguments passed to CMake in script mode.", "When run in -P script mode, CMake sets this variable to the number " - "of command line arguments. See also CMAKE_ARGV0, 1, 2 ... ", false, + "of command line arguments. See also CMAKE_ARGV0, 1, 2 ...", false, "Variables that Provide Information"); cm->DefineProperty ("CMAKE_ARGV0", cmProperty::VARIABLE, - "Command line argument passed to CMake in script mode. ", + "Command line argument passed to CMake in script mode.", "When run in -P script mode, CMake sets this variable to " "the first command line argument. It then also sets CMAKE_ARGV1, " "CMAKE_ARGV2, ... and so on, up to the number of command line arguments " @@ -129,11 +129,11 @@ 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, + " on the final build environment.", false, "Variables that Provide Information"); cm->DefineProperty ("CMAKE_CROSSCOMPILING", cmProperty::VARIABLE, @@ -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 @@ -391,7 +393,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_SOURCE_DIR", cmProperty::VARIABLE, "Source directory for project.", - "This is the top level source directory for the project. " + "This is the top level source directory for the project. " "It corresponds to the source directory given to " "cmake-gui or ccmake.",false, "Variables that Provide Information"); @@ -417,7 +419,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("PROJECT_NAME", cmProperty::VARIABLE, "Name of the project given to the project command.", "This is the name given to the most " - "recent PROJECT command. ",false, + "recent PROJECT command.",false, "Variables that Provide Information"); cm->DefineProperty ("PROJECT_SOURCE_DIR", cmProperty::VARIABLE, @@ -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"); @@ -509,6 +514,13 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "analysis of libraries linked by a target.", false, "Variables that Provide Information"); + cm->DefineProperty + ("CMAKE_MINIMUM_REQUIRED_VERSION", cmProperty::VARIABLE, + "Version specified to cmake_minimum_required command", + "Variable containing the VERSION component specified in the " + "cmake_minimum_required command.", + false, + "Variables that Provide Information"); // Variables defined by cmake, that change the behavior @@ -538,7 +550,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "By default, automoc behaves exactly as described in the documentation " "of the AUTOMOC target property. " "When set to TRUE, it accepts more input and tries to find the correct " - "input file for moc even if it differs from the documented behaviour. " + "input file for moc even if it differs from the documented behaviour. " "In this mode it e.g. also checks whether a header file is intended to " "be processed by moc when a \"foo.moc\" file has been included.\n" "Relaxed mode has to be enabled for KDE4 compatibility.", @@ -551,7 +563,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "If an install() command is used without the COMPONENT argument, " "these files will be grouped into a default component. The name of this " "default install component will be taken from this variable. " - "It defaults to \"Unspecified\". ", + "It defaults to \"Unspecified\".", false, "Variables That Change Behavior"); @@ -577,26 +589,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,32 +639,36 @@ 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" - " to relocate the whole installation. " + " to relocate the whole installation. " "DESTDIR means DESTination DIRectory. It is " "commonly used by makefile users " - "in order to install software at non-default location. " + "in order to install software at non-default location. " "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"); cm->DefineProperty ("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY", cmProperty::VARIABLE, "Don't make the install target depend on the all target.", - "By default, the \"install\" target depends on the \"all\" target. " + "By default, the \"install\" target depends on the \"all\" target. " "This has the effect, that when \"make install\" is invoked or INSTALL " "is built, first the \"all\" target is built, then the installation " - "starts. " + "starts. " "If CMAKE_SKIP_INSTALL_ALL_DEPENDENCY is set to TRUE, this dependency " "is not created, so the installation process will start immediately, " "independent from whether the project has been completely built or not." @@ -658,6 +685,23 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "Variables That Change Behavior"); cm->DefineProperty + ("CMAKE_WARN_DEPRECATED", cmProperty::VARIABLE, + "Whether to issue deprecation warnings for macros and functions.", + "If TRUE, this can be used by macros and functions to issue " + "deprecation warnings. This variable is FALSE by default.", + false, + "Variables That Change Behavior"); + + cm->DefineProperty + ("CMAKE_ERROR_DEPRECATED", cmProperty::VARIABLE, + "Whether to issue deprecation errors for macros and functions.", + "If TRUE, this can be used by macros and functions to issue " + "fatal errors when deprecated macros or functions are used. This " + "variable is FALSE by default.", + false, + "Variables That Change Behavior"); + + cm->DefineProperty ("CMAKE_PREFIX_PATH", cmProperty::VARIABLE, "Path used for searching by FIND_XXX(), with appropriate suffixes added.", "Specifies a path which will be used by the FIND_XXX() commands. It " @@ -709,7 +753,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, @@ -724,9 +769,9 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "directories contain incompatible but possibly linkable libraries. For " "example, on cross-compiled cluster environments, this allows a user to " "ignore directories containing libraries meant for the front-end " - "machine that modules like FindX11 (and others) would normally search. " + "machine that modules like FindX11 (and others) would normally search. " "By default this contains a list of directories containing incompatible " - "binaries for the host system. " + "binaries for the host system. " "See also CMAKE_SYSTEM_PREFIX_PATH, CMAKE_SYSTEM_LIBRARY_PATH, " "CMAKE_SYSTEM_INCLUDE_PATH, and CMAKE_SYSTEM_PROGRAM_PATH.", false, "Variables That Change Behavior"); @@ -740,11 +785,11 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "directories contain incompatible but possibly linkable libraries. For " "example, on cross-compiled cluster environments, this allows a user to " "ignore directories containing libraries meant for the front-end " - "machine that modules like FindX11 (and others) would normally search. " - "By default this is empty; it is intended to be set by the project. " + "machine that modules like FindX11 (and others) would normally search. " + "By default this is empty; it is intended to be set by the project. " "Note that CMAKE_IGNORE_PATH takes a list of directory names, NOT a " "list of prefixes. If you want to ignore paths under prefixes (bin, " - "include, lib, etc.), you'll need to specify them explicitly. " + "include, lib, etc.), you'll need to specify them explicitly. " "See also CMAKE_PREFIX_PATH, CMAKE_LIBRARY_PATH, CMAKE_INCLUDE_PATH, " "CMAKE_PROGRAM_PATH.", false, "Variables That Change Behavior"); @@ -791,8 +836,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "although that package is installed.\n" "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 " + "variables which have been stored in the cache will still be there. " + "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"); @@ -878,7 +923,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_COLOR_MAKEFILE", cmProperty::VARIABLE, "Enables color output when using the Makefile generator.", - "When enabled, the generated Makefiles will produce colored output. " + "When enabled, the generated Makefiles will produce colored output. " "Default is ON.",false, "Variables That Change Behavior"); @@ -888,7 +933,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 +943,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 +954,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"); @@ -918,9 +963,10 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "Enables tracing output for target properties.", "This variable can be populated with a list of properties to generate " "debug output for when evaluating target properties. Currently it can " - "only be used when evaluating the INCLUDE_DIRECTORIES target property. " - "In that case, it outputs a backtrace for each include directory in " - "the build. Default is unset.",false,"Variables That Change Behavior"); + "only be used when evaluating the INCLUDE_DIRECTORIES, " + "COMPILE_DEFINITIONS and COMPILE_OPTIONS target properties. " + "In that case, it outputs a backtrace for each entry in the target " + "property. Default is unset.", false, "Variables That Change Behavior"); // Variables defined by CMake that describe the system @@ -929,7 +975,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "Name of system cmake is compiling for.", "This variable is the composite of CMAKE_SYSTEM_NAME " "and CMAKE_SYSTEM_VERSION, like this " - "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_VERSION}. " + "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_VERSION}. " "If CMAKE_SYSTEM_VERSION is not set, then " "CMAKE_SYSTEM is the same as CMAKE_SYSTEM_NAME.",false, "Variables That Describe the System"); @@ -940,7 +986,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 +1045,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 +1159,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 +1174,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 +1196,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. // @@ -1180,7 +1237,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_INSTALL_RPATH", cmProperty::VARIABLE, "The rpath to use for installed targets.", "A semicolon-separated list specifying the rpath " - "to use in installed targets (for platforms that support it). " + "to use in installed targets (for platforms that support it). " "This is used to initialize the target property " "INSTALL_RPATH for all targets.", false, @@ -1191,7 +1248,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "Add paths to linker search and installed rpath.", "CMAKE_INSTALL_RPATH_USE_LINK_PATH is a boolean that if set to true " "will append directories in the linker search path and outside the " - "project to the INSTALL_RPATH. " + "project to the INSTALL_RPATH. " "This is used to initialize the target property " "INSTALL_RPATH_USE_LINK_PATH for all targets.", false, @@ -1199,7 +1256,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.", @@ -1210,7 +1267,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_Fortran_FORMAT", cmProperty::VARIABLE, "Set to FIXED or FREE to indicate the Fortran source layout.", "This variable is used to initialize the Fortran_FORMAT " - "property on all the targets. " + "property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); @@ -1219,7 +1276,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_Fortran_MODULE_DIRECTORY", cmProperty::VARIABLE, "Fortran module output directory.", "This variable is used to initialize the " - "Fortran_MODULE_DIRECTORY property on all the targets. " + "Fortran_MODULE_DIRECTORY property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); @@ -1228,7 +1285,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_LIBRARY_OUTPUT_DIRECTORY", cmProperty::VARIABLE, "Where to put all the LIBRARY targets when built.", "This variable is used to initialize the " - "LIBRARY_OUTPUT_DIRECTORY property on all the targets. " + "LIBRARY_OUTPUT_DIRECTORY property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); @@ -1237,7 +1294,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_ARCHIVE_OUTPUT_DIRECTORY", cmProperty::VARIABLE, "Where to put all the ARCHIVE targets when built.", "This variable is used to initialize the " - "ARCHIVE_OUTPUT_DIRECTORY property on all the targets. " + "ARCHIVE_OUTPUT_DIRECTORY property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); @@ -1246,16 +1303,16 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_RUNTIME_OUTPUT_DIRECTORY", cmProperty::VARIABLE, "Where to put all the RUNTIME targets when built.", "This variable is used to initialize the " - "RUNTIME_OUTPUT_DIRECTORY property on all the targets. " + "RUNTIME_OUTPUT_DIRECTORY property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); 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. " + "PDB_OUTPUT_DIRECTORY property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); @@ -1273,7 +1330,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_AUTOMOC", cmProperty::VARIABLE, "Whether to handle moc automatically for Qt targets.", "This variable is used to initialize the " - "AUTOMOC property on all the targets. " + "AUTOMOC property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); @@ -1282,7 +1339,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_AUTOMOC_MOC_OPTIONS", cmProperty::VARIABLE, "Additional options for moc when using automoc (see CMAKE_AUTOMOC).", "This variable is used to initialize the " - "AUTOMOC_MOC_OPTIONS property on all the targets. " + "AUTOMOC_MOC_OPTIONS property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); @@ -1359,45 +1416,91 @@ 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_MODULE_LINKER_FLAGS", cmProperty::VARIABLE, + "Linker flags to be used to create modules.", + "These flags will be used by the linker when creating a module." + ,false, + "Variables that Control the Build"); + + cm->DefineProperty + ("CMAKE_MODULE_LINKER_FLAGS_<CONFIG>", cmProperty::VARIABLE, + "Flags to be used when linking a module.", + "Same as CMAKE_C_FLAGS_* but used by the linker " + "when creating modules.",false, + "Variables that Control the Build"); + + cm->DefineProperty + ("CMAKE_SHARED_LINKER_FLAGS", cmProperty::VARIABLE, + "Linker flags to be used to create shared libraries.", + "These flags will be used by the linker when creating a shared library." + ,false, + "Variables that Control the Build"); + + cm->DefineProperty + ("CMAKE_SHARED_LINKER_FLAGS_<CONFIG>", cmProperty::VARIABLE, + "Flags to be used when linking a shared library.", + "Same as CMAKE_C_FLAGS_* but used by the linker " + "when creating shared libraries.",false, + "Variables that Control the Build"); + + cm->DefineProperty + ("CMAKE_STATIC_LINKER_FLAGS", cmProperty::VARIABLE, + "Linker flags to be used to create static libraries.", + "These flags will be used by the linker when creating a static library." + ,false, + "Variables that Control the Build"); + + cm->DefineProperty + ("CMAKE_STATIC_LINKER_FLAGS_<CONFIG>", cmProperty::VARIABLE, + "Flags to be used when linking a static library.", + "Same as CMAKE_C_FLAGS_* but used by the linker " + "when creating static libraries.",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 " - "relative paths between the source and binary tree. " + "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. " "In general, it is not possible to move CMake generated" @@ -1431,7 +1534,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_LINK_INTERFACE_LIBRARIES", cmProperty::VARIABLE, "Default value for LINK_INTERFACE_LIBRARIES of targets.", "This variable is used to initialize the " - "LINK_INTERFACE_LIBRARIES property on all the targets. " + "LINK_INTERFACE_LIBRARIES property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); @@ -1439,7 +1542,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_WIN32_EXECUTABLE", cmProperty::VARIABLE, "Default value for WIN32_EXECUTABLE of targets.", "This variable is used to initialize the " - "WIN32_EXECUTABLE property on all the targets. " + "WIN32_EXECUTABLE property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); @@ -1447,7 +1550,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_MACOSX_BUNDLE", cmProperty::VARIABLE, "Default value for MACOSX_BUNDLE of targets.", "This variable is used to initialize the " - "MACOSX_BUNDLE property on all the targets. " + "MACOSX_BUNDLE property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); @@ -1455,7 +1558,23 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_POSITION_INDEPENDENT_CODE", cmProperty::VARIABLE, "Default value for POSITION_INDEPENDENT_CODE of targets.", "This variable is used to initialize the " - "POSITION_INDEPENDENT_CODE property on all the targets. " + "POSITION_INDEPENDENT_CODE property on all the targets. " + "See that target property for additional information.", + false, + "Variables that Control the Build"); + cm->DefineProperty + ("CMAKE_<LANG>_VISIBILITY_PRESET", cmProperty::VARIABLE, + "Default value for <LANG>_VISIBILITY_PRESET of targets.", + "This variable is used to initialize the " + "<LANG>_VISIBILITY_PRESET property on all the targets. " + "See that target property for additional information.", + false, + "Variables that Control the Build"); + cm->DefineProperty + ("CMAKE_VISIBILITY_INLINES_HIDDEN", cmProperty::VARIABLE, + "Default value for VISIBILITY_INLINES_HIDDEN of targets.", + "This variable is used to initialize the " + "VISIBILITY_INLINES_HIDDEN property on all the targets. " "See that target property for additional information.", false, "Variables that Control the Build"); @@ -1476,7 +1595,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_<LANG>_COMPILER", cmProperty::VARIABLE, "The full path to the compiler for LANG.", - "This is the command that will be used as the <LANG> compiler. " + "This is the command that will be used as the <LANG> compiler. " "Once set, you can not change this variable.",false, "Variables for Languages"); @@ -1552,7 +1671,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_COMPILER_IS_GNU<LANG>", cmProperty::VARIABLE, "True if the compiler is GNU.", "If the selected <LANG> compiler is the GNU " - "compiler then this is TRUE, if not it is FALSE. " + "compiler then this is TRUE, if not it is FALSE. " "Unlike the other per-language variables, this uses the GNU syntax for " "identifying languages instead of the CMake syntax. Recognized values of " "the <LANG> suffix are:\n" @@ -1563,6 +1682,12 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "Variables for Languages"); cm->DefineProperty + ("CMAKE_<LANG>_FLAGS", cmProperty::VARIABLE, + "Flags for all build types.", + "<LANG> flags used regardless of the value of CMAKE_BUILD_TYPE.",false, + "Variables for Languages"); + + cm->DefineProperty ("CMAKE_<LANG>_FLAGS_DEBUG", cmProperty::VARIABLE, "Flags for Debug build type or configuration.", "<LANG> flags used when CMAKE_BUILD_TYPE is Debug.",false, @@ -1584,7 +1709,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_<LANG>_FLAGS_RELWITHDEBINFO", cmProperty::VARIABLE, "Flags for RelWithDebInfo type or configuration.", - "<LANG> flags used when CMAKE_BUILD_TYPE is RelWithDebInfo. " + "<LANG> flags used when CMAKE_BUILD_TYPE is RelWithDebInfo. " "Short for Release With Debug Information.",false, "Variables for Languages"); @@ -1592,7 +1717,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 @@ -1647,7 +1773,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_<LANG>_IGNORE_EXTENSIONS", cmProperty::VARIABLE, "File extensions that should be ignored by the build.", "This is a list of file extensions that may be " - "part of a project for a given language but are not compiled. ",false, + "part of a project for a given language but are not compiled.",false, "Variables for Languages"); cm->DefineProperty @@ -1728,8 +1854,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 +1870,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, @@ -1799,8 +1928,6 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cmProperty::VARIABLE,0,0); cm->DefineProperty("CMAKE_<LANG>_CREATE_PREPROCESSED_SOURCE", cmProperty::VARIABLE,0,0); - cm->DefineProperty("CMAKE_<LANG>_FLAGS", - cmProperty::VARIABLE,0,0); cm->DefineProperty("CMAKE_<LANG>_FLAGS_DEBUG_INIT", cmProperty::VARIABLE,0,0); cm->DefineProperty("CMAKE_<LANG>_FLAGS_INIT", diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx index debde3be9..4edacbb1a 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 1158fc0c0..30de9a8a6 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 ee963f920..747448b3e 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 7147f86be..cdc3316c4 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,8 +72,20 @@ 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); + const bool newCMP0022Behavior = + te->GetPolicyStatusCMP0022() != cmPolicies::WARN + && te->GetPolicyStatusCMP0022() != cmPolicies::OLD; + if (newCMP0022Behavior) + { + this->PopulateInterfaceLinkLibrariesProperty(te, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); + } this->PopulateCompatibleInterfaceProperties(te, properties); this->GenerateInterfaceProperties(te, os, properties); @@ -143,7 +155,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 +201,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 +223,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 5e1be1648..3ffdf8b13 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 1cc17545a..f059ceba6 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -30,6 +30,7 @@ cmExportCommand::cmExportCommand() ,Append(&Helper, "APPEND", &ArgumentGroup) ,Namespace(&Helper, "NAMESPACE", &ArgumentGroup) ,Filename(&Helper, "FILE", &ArgumentGroup) +,ExportOld(&Helper, "EXPORT_LINK_INTERFACE_LIBRARIES", &ArgumentGroup) { // at first TARGETS this->Targets.Follows(0); @@ -113,6 +114,15 @@ bool cmExportCommand currentTarget != this->Targets.GetVector().end(); ++currentTarget) { + if (this->Makefile->IsAlias(currentTarget->c_str())) + { + cmOStringStream e; + e << "given ALIAS target \"" << *currentTarget + << "\" which may not be exported."; + this->SetError(e.str().c_str()); + return false; + } + if(cmTarget* target = this->Makefile->GetLocalGenerator()-> GetGlobalGenerator()->FindTarget(0, currentTarget->c_str())) @@ -158,6 +168,7 @@ bool cmExportCommand ebfg.SetAppendMode(this->Append.IsEnabled()); ebfg.SetExports(&targets); ebfg.SetCommand(this); + ebfg.SetExportOld(this->ExportOld.IsEnabled()); // Compute the set of configurations exported. std::vector<std::string> configurationTypes; @@ -210,7 +221,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/cmExportCommand.h b/Source/cmExportCommand.h index ae67b4762..87c345284 100644 --- a/Source/cmExportCommand.h +++ b/Source/cmExportCommand.h @@ -63,7 +63,7 @@ public: { return " export(TARGETS [target1 [target2 [...]]] [NAMESPACE <namespace>]\n" - " [APPEND] FILE <filename>)\n" + " [APPEND] FILE <filename> [EXPORT_LINK_INTERFACE_LIBRARIES])\n" "Create a file <filename> that may be included by outside projects to " "import targets from the current project's build tree. " "This is useful during cross-compiling to build utility executables " @@ -73,6 +73,10 @@ public: "prepended to all target names written to the file. " "If the APPEND option is given the generated code will be appended " "to the file instead of overwriting it. " + "The EXPORT_LINK_INTERFACE_LIBRARIES keyword, if present, causes the " + "contents of the properties matching " + "(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)? to be exported, when " + "policy CMP0022 is NEW. " "If a library target is included in the export but " "a target to which it links is not included the behavior is " "unspecified." @@ -104,6 +108,7 @@ private: cmCAEnabler Append; cmCAString Namespace; cmCAString Filename; + cmCAEnabler ExportOld; friend class cmExportBuildFileGenerator; std::string ErrorMessage; diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 27ec56beb..14be5cd47 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -30,6 +30,7 @@ cmExportFileGenerator::cmExportFileGenerator() { this->AppendMode = false; + this->ExportOld = false; } //---------------------------------------------------------------------------- @@ -168,6 +169,43 @@ void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName, } } +void cmExportFileGenerator::GenerateRequiredCMakeVersion(std::ostream& os, + const char *versionString) +{ + os << "if(CMAKE_VERSION VERSION_LESS " << versionString << ")\n" + " message(FATAL_ERROR \"This file relies on consumers using " + "CMake " << versionString << " or greater.\")\n" + "endif()\n\n"; +} + +//---------------------------------------------------------------------------- +bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty( + cmTarget *target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap &properties, + std::vector<std::string> &missingTargets) +{ + if(!target->IsLinkable()) + { + return false; + } + const char *input = target->GetProperty("INTERFACE_LINK_LIBRARIES"); + if (input) + { + std::string prepro = cmGeneratorExpression::Preprocess(input, + preprocessRule); + if (!prepro.empty()) + { + this->ResolveTargetsInGeneratorExpressions(prepro, target, + missingTargets, + ReplaceFreeTargets); + properties["INTERFACE_LINK_LIBRARIES"] = prepro; + return true; + } + } + return false; +} + //---------------------------------------------------------------------------- static bool isSubDirectory(const char* a, const char* b) { @@ -243,28 +281,55 @@ static bool checkInterfaceDirs(const std::string &prepro, //---------------------------------------------------------------------------- void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( - cmTarget *target, + cmTargetExport *tei, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap &properties, std::vector<std::string> &missingTargets) { + cmTarget *target = tei->Target; assert(preprocessRule == cmGeneratorExpression::InstallInterface); const char *propName = "INTERFACE_INCLUDE_DIRECTORIES"; const char *input = target->GetProperty(propName); - if (!input) + + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + + std::string dirs = tei->InterfaceIncludeDirectories; + this->ReplaceInstallPrefix(dirs); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(dirs); + std::string exportDirs = cge->Evaluate(target->GetMakefile(), 0, + false, target); + + if (cge->GetHadContextSensitiveCondition()) { + cmMakefile* mf = target->GetMakefile(); + cmOStringStream e; + e << "Target \"" << target->GetName() << "\" is installed with " + "INCLUDES DESTINATION set to a context sensitive path. Paths which " + "depend on the configuration, policy values or the link interface are " + "not supported. Consider using target_include_directories instead."; + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } - if (!*input) + + if (!input && exportDirs.empty()) + { + return; + } + if ((input && !*input) && exportDirs.empty()) { // Set to empty properties[propName] = ""; return; } - std::string prepro = cmGeneratorExpression::Preprocess(input, - preprocessRule); + std::string includes = (input?input:""); + const char* sep = input ? ";" : ""; + includes += sep + exportDirs; + std::string prepro = cmGeneratorExpression::Preprocess(includes, + preprocessRule, + true); if (!prepro.empty()) { this->ResolveTargetsInGeneratorExpressions(prepro, target, @@ -315,6 +380,16 @@ void getCompatibleInterfaceProperties(cmTarget *target, { cmComputeLinkInformation *info = target->GetLinkInformation(config); + if (!info) + { + cmMakefile* mf = target->GetMakefile(); + cmOStringStream e; + e << "Exporting the target \"" << target->GetName() << "\" is not " + "allowed since its linker language cannot be determined"; + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } + const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); for(cmComputeLinkInformation::ItemVector::const_iterator li = @@ -376,7 +451,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 +482,7 @@ cmExportFileGenerator::AddTargetNamespace(std::string &input, } if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) { - input = this->Namespace + input; + input = this->Namespace + tgt->GetExportName(); } else { @@ -560,6 +635,7 @@ cmExportFileGenerator if (iface->ImplementationIsInterface) { + // Policy CMP0022 must not be NEW. this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_INTERFACE_LIBRARIES", iface->Libraries, properties, missingTargets); @@ -583,6 +659,22 @@ cmExportFileGenerator return; } + const bool newCMP0022Behavior = + target->GetPolicyStatusCMP0022() != cmPolicies::WARN + && target->GetPolicyStatusCMP0022() != cmPolicies::OLD; + + if(newCMP0022Behavior && !this->ExportOld) + { + cmMakefile *mf = target->GetMakefile(); + cmOStringStream e; + e << "Target \"" << target->GetName() << "\" has policy CMP0022 enabled, " + "but also has old-style LINK_INTERFACE_LIBRARIES properties " + "populated, but it was exported without the " + "EXPORT_LINK_INTERFACE_LIBRARIES to export the old-style properties"; + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } + if (!*propContent) { properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = ""; @@ -624,8 +716,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 { @@ -738,7 +834,9 @@ void cmExportFileGenerator::GenerateImportVersionCode(std::ostream& os) void cmExportFileGenerator::GenerateExpectedTargetsCode(std::ostream& os, const std::string &expectedTargets) { - os << "set(_targetsDefined)\n" + os << "# Protect against multiple inclusion, which would fail when already " + "imported targets are added once more.\n" + "set(_targetsDefined)\n" "set(_targetsNotDefined)\n" "set(_expectedTargets)\n" "foreach(_expectedTarget " << expectedTargets << ")\n" @@ -772,7 +870,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 +934,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 +1054,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 9f958a234..9628b9681 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -15,6 +15,8 @@ #include "cmCommand.h" #include "cmGeneratorExpression.h" +class cmTargetExport; + /** \class cmExportFileGenerator * \brief Generate a file exporting targets from a build or install tree. * @@ -35,6 +37,8 @@ public: /** Set the namespace in which to place exported target names. */ void SetNamespace(const char* ns) { this->Namespace = ns; } + void SetExportOld(bool exportOld) { this->ExportOld = exportOld; } + /** Add a configuration to be exported. */ void AddConfiguration(const char* config); @@ -101,6 +105,10 @@ protected: cmGeneratorExpression::PreprocessContext, ImportPropertyMap &properties, std::vector<std::string> &missingTargets); + bool PopulateInterfaceLinkLibrariesProperty(cmTarget *target, + cmGeneratorExpression::PreprocessContext, + ImportPropertyMap &properties, + std::vector<std::string> &missingTargets); void PopulateInterfaceProperty(const char *propName, cmTarget *target, ImportPropertyMap &properties); void PopulateCompatibleInterfaceProperties(cmTarget *target, @@ -108,7 +116,7 @@ protected: void GenerateInterfaceProperties(cmTarget *target, std::ostream& os, const ImportPropertyMap &properties); void PopulateIncludeDirectoriesInterface( - cmTarget *target, + cmTargetExport *target, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap &properties, std::vector<std::string> &missingTargets); @@ -128,9 +136,14 @@ protected: std::vector<std::string> &missingTargets, FreeTargetsReplace replace = NoReplaceFreeTargets); + void GenerateRequiredCMakeVersion(std::ostream& os, + const char *versionString); + // The namespace in which the exports are placed in the generated file. std::string Namespace; + bool ExportOld; + // The set of configurations to export. std::vector<std::string> Configurations; @@ -159,6 +172,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 ad12b5a13..c8b4a7985 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -39,7 +39,7 @@ std::string cmExportInstallFileGenerator::GetConfigImportFileGlob() //---------------------------------------------------------------------------- bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) { - std::vector<cmTarget*> allTargets; + std::vector<cmTargetExport*> allTargets; { std::string expectedTargets; std::string sep; @@ -47,12 +47,12 @@ 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; + cmTargetExport * te = *tei; if(this->ExportedTargets.insert(te->Target).second) { - allTargets.push_back(te->Target); + allTargets.push_back(te); } else { @@ -113,23 +113,46 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) std::vector<std::string> missingTargets; + bool require2_8_12 = false; // Create all the imported targets. - for(std::vector<cmTarget*>::const_iterator + for(std::vector<cmTargetExport*>::const_iterator tei = allTargets.begin(); tei != allTargets.end(); ++tei) { - cmTarget* te = *tei; + cmTarget* te = (*tei)->Target; this->GenerateImportTargetCode(os, te); ImportPropertyMap properties; - this->PopulateIncludeDirectoriesInterface(te, + this->PopulateIncludeDirectoriesInterface(*tei, + cmGeneratorExpression::InstallInterface, + properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", + te, cmGeneratorExpression::InstallInterface, properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", te, cmGeneratorExpression::InstallInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", + te, + cmGeneratorExpression::InstallInterface, + properties, missingTargets); + + const bool newCMP0022Behavior = + te->GetPolicyStatusCMP0022() != cmPolicies::WARN + && te->GetPolicyStatusCMP0022() != cmPolicies::OLD; + if (newCMP0022Behavior) + { + if (this->PopulateInterfaceLinkLibrariesProperty(te, + cmGeneratorExpression::InstallInterface, + properties, missingTargets) + && !this->ExportOld) + { + require2_8_12 = true; + } + } this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", te, properties); this->PopulateCompatibleInterfaceProperties(te, properties); @@ -137,6 +160,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->GenerateInterfaceProperties(te, os, properties); } + if (require2_8_12) + { + this->GenerateRequiredCMakeVersion(os, "2.8.12"); + } // Now load per-configuration properties for them. os << "# Load information for each installed configuration.\n" @@ -351,27 +378,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 +402,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 +504,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 20dd57ad1..7c634a4d8 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 75f2651ba..819ac371e 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); @@ -91,7 +93,9 @@ cmExportTryCompileFileGenerator::PopulateProperties(cmTarget* target, { properties[i->first] = i->second.GetValue(); - if(i->first.find("IMPORTED_LINK_INTERFACE_LIBRARIES") == 0) + if(i->first.find("IMPORTED_LINK_INTERFACE_LIBRARIES") == 0 + || i->first.find("IMPORTED_LINK_DEPENDENT_LIBRARIES") == 0 + || i->first.find("INTERFACE_LINK_LIBRARIES") == 0) { const std::string libs = i->second.GetValue(); @@ -112,3 +116,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 ed393abf4..91b4a6153 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/cmExprLexer.cxx b/Source/cmExprLexer.cxx index 53dfca7c0..9947c77f1 100644 --- a/Source/cmExprLexer.cxx +++ b/Source/cmExprLexer.cxx @@ -693,9 +693,9 @@ extern int cmExpr_yylex (yyscan_t yyscanner); */ YY_DECL { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; #line 86 "/home/andy/vtk/CMake/Source/cmExprLexer.in.l" @@ -745,7 +745,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -989,9 +989,9 @@ return 0; /* this should not happen but it silences a warning*/ static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = yyg->yytext_ptr; - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) @@ -1116,15 +1116,15 @@ static int yy_get_next_buffer (yyscan_t yyscanner) static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { - register yy_state_type yy_current_state; - register char *yy_cp; + yy_state_type yy_current_state; + char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1149,11 +1149,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { - register int yy_is_jam; + int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *yy_cp = yyg->yy_c_buf_p; + char *yy_cp = yyg->yy_c_buf_p; - register YY_CHAR yy_c = 1; + YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1867,7 +1867,7 @@ int cmExpr_yylex_destroy (yyscan_t yyscanner) #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) { - register int i; + int i; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; @@ -1877,7 +1877,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysca #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) { - register int n; + int n; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; for ( n = 0; s[n]; ++n ) ; diff --git a/Source/cmExprLexer.in.l b/Source/cmExprLexer.in.l index f344b40ff..febd244fe 100644 --- a/Source/cmExprLexer.in.l +++ b/Source/cmExprLexer.in.l @@ -20,6 +20,7 @@ Run flex like this: Modify cmExprLexer.cxx: - remove TABs + - remove use of the 'register' storage class specifier - remove "yyscanner" argument from these methods: yy_fatal_error, cmExpr_yyalloc, cmExpr_yyrealloc, cmExpr_yyfree - remove all YY_BREAK lines occurring right after return statements diff --git a/Source/cmExprParser.cxx b/Source/cmExprParser.cxx index 5c164a081..77880c0a3 100644 --- a/Source/cmExprParser.cxx +++ b/Source/cmExprParser.cxx @@ -267,7 +267,7 @@ union yyalloc # define YYCOPY(To, From, Count) \ do \ { \ - register YYSIZE_T yyi; \ + YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ @@ -696,7 +696,7 @@ yystrlen (yystr) const char *yystr; # endif { - register const char *yys = yystr; + const char *yys = yystr; while (*yys++ != '\0') continue; @@ -721,8 +721,8 @@ yystpcpy (yydest, yysrc) const char *yysrc; # endif { - register char *yyd = yydest; - register const char *yys = yysrc; + char *yyd = yydest; + const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; @@ -852,8 +852,8 @@ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; - register int yystate; - register int yyn; + int yystate; + int yyn; int yyresult; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; @@ -871,12 +871,12 @@ int yynerrs; /* The state stack. */ short int yyssa[YYINITDEPTH]; short int *yyss = yyssa; - register short int *yyssp; + short int *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; + YYSTYPE *yyvsp; diff --git a/Source/cmExprParser.y b/Source/cmExprParser.y index 317b0ba98..12c2e4806 100644 --- a/Source/cmExprParser.y +++ b/Source/cmExprParser.y @@ -20,6 +20,7 @@ Run bison like this: Modify cmExprParser.cxx: - remove TABs + - remove use of the 'register' storage class specifier - add __HP_aCC to the #if test for yyerrorlab warning suppression */ diff --git a/Source/cmExprParserHelper.cxx b/Source/cmExprParserHelper.cxx index 9c1795ec2..cc35f84cd 100644 --- a/Source/cmExprParserHelper.cxx +++ b/Source/cmExprParserHelper.cxx @@ -12,10 +12,10 @@ #include "cmExprParserHelper.h" #include "cmSystemTools.h" -#include "cmExprLexer.h" - #include "cmMakefile.h" +#include "cmExprLexer.h" + int cmExpr_yyparse( yyscan_t yyscanner ); // cmExprParserHelper::cmExprParserHelper() diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index f6f4ceff3..dfbb1c0ad 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -621,19 +621,15 @@ void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout, ->GetGeneratorTarget(target); // the compilerdefines for this target - std::string cdefs = target->GetCompileDefinitions(buildType); + std::vector<std::string> cdefs; + target->GetCompileDefinitions(cdefs, buildType); - if(!cdefs.empty()) + // Expand the list. + for(std::vector<std::string>::const_iterator di = cdefs.begin(); + di != cdefs.end(); ++di) { - // Expand the list. - std::vector<std::string> defs; - cmSystemTools::ExpandListArgument(cdefs.c_str(), defs); - for(std::vector<std::string>::const_iterator di = defs.begin(); - di != defs.end(); ++di) - { - cmXMLSafe safedef(di->c_str()); - fout <<" <Add option=\"-D" << safedef.str() << "\" />\n"; - } + cmXMLSafe safedef(di->c_str()); + fout <<" <Add option=\"-D" << safedef.str() << "\" />\n"; } // the include directories for this target diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 97ab0863c..d80e775bf 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 31ad68da9..b31cce74c 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 e4802d59e..523fca9aa 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -421,7 +421,7 @@ cmExtraSublimeTextGenerator::ComputeFlagsForObject(cmSourceFile* source, std::vector<std::string> includes; lg->GetIncludeDirectories(includes, gtgt, language, config); std::string includeFlags = - lg->GetIncludeFlags(includes, language, true); // full include paths + lg->GetIncludeFlags(includes, gtgt, language, true); // full include paths lg->AppendFlags(flags, includeFlags.c_str()); } @@ -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. @@ -488,7 +463,7 @@ ComputeDefines(cmSourceFile *source, cmLocalGenerator* lg, cmTarget *target, } // Add preprocessor definitions for this target and configuration. - lg->AppendDefines(defines, target->GetCompileDefinitions(config)); + lg->AddCompileDefinitions(defines, target, config); lg->AppendDefines(defines, source->GetProperty("COMPILE_DEFINITIONS")); { std::string defPropName = "COMPILE_DEFINITIONS_"; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 018ce7ecd..4446f7216 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; } @@ -2485,7 +2489,7 @@ namespace { cmWriteToFileCallback(void *ptr, size_t size, size_t nmemb, void *data) { - register int realsize = (int)(size * nmemb); + int realsize = (int)(size * nmemb); std::ofstream* fout = static_cast<std::ofstream*>(data); const char* chPtr = static_cast<char*>(ptr); fout->write(chPtr, realsize); @@ -2497,7 +2501,7 @@ namespace { cmWriteToMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { - register int realsize = (int)(size * nmemb); + int realsize = (int)(size * nmemb); cmFileCommandVectorOfChar *vec = static_cast<cmFileCommandVectorOfChar*>(data); const char* chPtr = static_cast<char*>(ptr); @@ -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 5973fa732..aa755d1f5 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -88,6 +88,9 @@ public: " file(UPLOAD filename url [INACTIVITY_TIMEOUT timeout]\n" " [TIMEOUT timeout] [STATUS status] [LOG log] [SHOW_PROGRESS])\n" " file(TIMESTAMP filename variable [<format string>] [UTC])\n" + " file(GENERATE OUTPUT output_file\n" + " <INPUT input_file|CONTENT input_content>\n" + " [CONDITION expression])\n" "WRITE will write a message into a file called 'filename'. It " "overwrites the file if it already exists, and creates the file " "if it does not exist. (If the file is a build input, use " @@ -231,6 +234,15 @@ public: "it prints status messages, and NO_SOURCE_PERMISSIONS is default. " "Installation scripts generated by the install() command use this " "signature (with some undocumented options for internal use)." + "\n" + "GENERATE will write an <output_file> with content from an " + "<input_file>, or from <input_content>. The output is generated " + "conditionally based on the content of the <condition>. The file is " + "written at CMake generate-time and the input may contain generator " + "expressions. The <condition>, <output_file> and <input_file> may " + "also contain generator expressions. The <condition> must evaluate to " + "either '0' or '1'. The <output_file> must evaluate to a unique name " + "among all configurations and among all invocations of file(GENERATE)." // Undocumented INSTALL options: // - RENAME <name> // - OPTIONAL @@ -269,6 +281,13 @@ protected: bool HandleUploadCommand(std::vector<std::string> const& args); bool HandleTimestampCommand(std::vector<std::string> const& args); + bool HandleGenerateCommand(std::vector<std::string> const& args); + +private: + void AddEvaluationFile(const std::string &inputName, + const std::string &outputExpr, + const std::string &condition, + bool inputIsContent); }; diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 10b47b9e0..a126cd110 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/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index ab8bd137e..d73c72c10 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -192,11 +192,12 @@ static std::string stripAllGeneratorExpressions(const std::string &input) std::string result; std::string::size_type pos = 0; std::string::size_type lastPos = pos; + int nestingLevel = 0; while((pos = input.find("$<", lastPos)) != input.npos) { result += input.substr(lastPos, pos - lastPos); pos += 2; - int nestingLevel = 1; + nestingLevel = 1; const char *c = input.c_str() + pos; const char * const cStart = c; for ( ; *c; ++c) @@ -224,16 +225,42 @@ static std::string stripAllGeneratorExpressions(const std::string &input) pos += traversed; lastPos = pos; } - result += input.substr(lastPos); + if (nestingLevel == 0) + { + result += input.substr(lastPos); + } return cmGeneratorExpression::StripEmptyListElements(result); } //---------------------------------------------------------------------------- +static void prefixItems(const std::string &content, std::string &result, + const std::string &prefix) +{ + std::vector<std::string> entries; + cmGeneratorExpression::Split(content, entries); + const char *sep = ""; + for(std::vector<std::string>::const_iterator ei = entries.begin(); + ei != entries.end(); ++ei) + { + result += sep; + sep = ";"; + if (!cmSystemTools::FileIsFullPath(ei->c_str()) + && cmGeneratorExpression::Find(*ei) == std::string::npos) + { + result += prefix; + } + result += *ei; + } +} + +//---------------------------------------------------------------------------- static std::string stripExportInterface(const std::string &input, - cmGeneratorExpression::PreprocessContext context) + cmGeneratorExpression::PreprocessContext context, + bool resolveRelative) { std::string result; + int nestingLevel = 0; std::string::size_type pos = 0; std::string::size_type lastPos = pos; while (true) @@ -263,7 +290,7 @@ static std::string stripExportInterface(const std::string &input, const bool gotInstallInterface = input[pos + 2] == 'I'; pos += gotInstallInterface ? sizeof("$<INSTALL_INTERFACE:") - 1 : sizeof("$<BUILD_INTERFACE:") - 1; - int nestingLevel = 1; + nestingLevel = 1; const char *c = input.c_str() + pos; const char * const cStart = c; for ( ; *c; ++c) @@ -289,7 +316,15 @@ static std::string stripExportInterface(const std::string &input, else if(context == cmGeneratorExpression::InstallInterface && gotInstallInterface) { - result += input.substr(pos, c - cStart); + const std::string content = input.substr(pos, c - cStart); + if (resolveRelative) + { + prefixItems(content, result, "${_IMPORT_PREFIX}/"); + } + else + { + result += content; + } } break; } @@ -304,7 +339,10 @@ static std::string stripExportInterface(const std::string &input, pos += traversed; lastPos = pos; } - result += input.substr(lastPos); + if (nestingLevel == 0) + { + result += input.substr(lastPos); + } return cmGeneratorExpression::StripEmptyListElements(result); } @@ -380,7 +418,8 @@ void cmGeneratorExpression::Split(const std::string &input, //---------------------------------------------------------------------------- std::string cmGeneratorExpression::Preprocess(const std::string &input, - PreprocessContext context) + PreprocessContext context, + bool resolveRelative) { if (context == StripAllGeneratorExpressions) { @@ -388,7 +427,7 @@ std::string cmGeneratorExpression::Preprocess(const std::string &input, } else if (context == BuildInterface || context == InstallInterface) { - return stripExportInterface(input, context); + return stripExportInterface(input, context, resolveRelative); } assert(!"cmGeneratorExpression::Preprocess called with invalid args"); diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index 86b6f25df..c20f130c9 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -57,7 +57,8 @@ public: }; static std::string Preprocess(const std::string &input, - PreprocessContext context); + PreprocessContext context, + bool resolveRelative = false); static void Split(const std::string &input, std::vector<std::string> &output); diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index 5cb50b9b8..92dc054c9 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -22,7 +22,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( const GeneratorExpressionContent *content, cmGeneratorExpressionDAGChecker *parent) : Parent(parent), Target(target), Property(property), - Content(content), Backtrace(backtrace) + Content(content), Backtrace(backtrace), TransitivePropertiesOnly(false) { const cmGeneratorExpressionDAGChecker *top = this; const cmGeneratorExpressionDAGChecker *p = this->Parent; @@ -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,21 @@ cmGeneratorExpressionDAGChecker::checkGraph() const } //---------------------------------------------------------------------------- -bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries() +bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly() +{ + const cmGeneratorExpressionDAGChecker *top = this; + const cmGeneratorExpressionDAGChecker *parent = this->Parent; + while (parent) + { + top = parent; + parent = parent->Parent; + } + + return top->TransitivePropertiesOnly; +} + +//---------------------------------------------------------------------------- +bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(const char *tgt) { const cmGeneratorExpressionDAGChecker *top = this; const cmGeneratorExpressionDAGChecker *parent = this->Parent; @@ -145,11 +164,18 @@ 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 || strncmp(prop, "LINK_INTERFACE_LIBRARIES_", 25) == 0 - || strncmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_", 34) == 0); + || strncmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_", 34) == 0) + || strcmp(prop, "INTERFACE_LINK_LIBRARIES") == 0; } //---------------------------------------------------------------------------- @@ -161,6 +187,14 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingIncludeDirectories() const } //---------------------------------------------------------------------------- +bool +cmGeneratorExpressionDAGChecker::EvaluatingSystemIncludeDirectories() const +{ + const char *prop = this->Property.c_str(); + return strcmp(prop, "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES") == 0; +} + +//---------------------------------------------------------------------------- bool cmGeneratorExpressionDAGChecker::EvaluatingCompileDefinitions() const { const char *prop = this->Property.c_str(); @@ -168,3 +202,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 62a5cdf38..0b7ef025c 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -16,6 +16,18 @@ #include "cmGeneratorExpressionEvaluator.h" +#define CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(F) \ + F(EvaluatingIncludeDirectories) \ + F(EvaluatingSystemIncludeDirectories) \ + F(EvaluatingCompileDefinitions) \ + F(EvaluatingCompileOptions) + +#define CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(F) \ + F(INTERFACE_INCLUDE_DIRECTORIES) \ + F(INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) \ + F(INTERFACE_COMPILE_DEFINITIONS) \ + F(INTERFACE_COMPILE_OPTIONS) + //---------------------------------------------------------------------------- struct cmGeneratorExpressionDAGChecker { @@ -37,9 +49,16 @@ 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) + + bool GetTransitivePropertiesOnly(); + void SetTransitivePropertiesOnly() + { this->TransitivePropertiesOnly = true; } private: Result checkGraph() const; @@ -52,6 +71,7 @@ private: const GeneratorExpressionContent * const Content; const cmListFileBacktrace Backtrace; Result CheckResult; + bool TransitivePropertiesOnly; }; #endif diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx new file mode 100644 index 000000000..cab99ed04 --- /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 000000000..20ee5cb2d --- /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 a01a0f890..8b3135412 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,269 @@ 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; + +//---------------------------------------------------------------------------- +struct CompilerVersionNode : public cmGeneratorExpressionNode +{ + CompilerVersionNode() {} + + 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 *compilerVersion = context->Makefile ? + context->Makefile->GetSafeDefinition(( + "CMAKE_" + lang + "_COMPILER_VERSION").c_str()) : ""; + if (parameters.size() == 0) + { + return compilerVersion ? compilerVersion : ""; + } + + cmsys::RegularExpression compilerIdValidator; + compilerIdValidator.compile("^[0-9\\.]*$"); + if (!compilerIdValidator.find(parameters.begin()->c_str())) + { + reportError(context, content->GetOriginalExpression(), + "Expression syntax not recognized."); + return std::string(); + } + if (!compilerVersion) + { + return parameters.front().empty() ? "1" : "0"; + } + + return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, + parameters.begin()->c_str(), + compilerVersion) ? "1" : "0"; + } +}; + +//---------------------------------------------------------------------------- +static const struct CCompilerVersionNode : public CompilerVersionNode +{ + CCompilerVersionNode() {} + + 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_VERSION> expression requires one or two parameters"); + return std::string(); + } + if (!context->HeadTarget) + { + reportError(context, content->GetOriginalExpression(), + "$<C_COMPILER_VERSION> may only be used with targets. It may not " + "be used with add_custom_command."); + } + return this->EvaluateWithLanguage(parameters, context, content, + dagChecker, "C"); + } +} cCompilerVersionNode; + +//---------------------------------------------------------------------------- +static const struct CxxCompilerVersionNode : public CompilerVersionNode +{ + CxxCompilerVersionNode() {} + + 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_VERSION> expression requires one or two " + "parameters"); + return std::string(); + } + if (!context->HeadTarget) + { + reportError(context, content->GetOriginalExpression(), + "$<CXX_COMPILER_VERSION> may only be used with targets. It may " + "not be used with add_custom_command."); + } + return this->EvaluateWithLanguage(parameters, context, content, + dagChecker, "CXX"); + } +} cxxCompilerVersionNode; + + +//---------------------------------------------------------------------------- +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 LinkOnlyNode : public cmGeneratorExpressionNode +{ + LinkOnlyNode() {} + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *dagChecker) const + { + if(!dagChecker->GetTransitivePropertiesOnly()) + { + return parameters.front(); + } + return ""; + } +} linkOnlyNode; + +//---------------------------------------------------------------------------- static const struct ConfigurationNode : public cmGeneratorExpressionNode { ConfigurationNode() {} @@ -297,20 +564,67 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode const char* loc = 0; const char* imp = 0; std::string suffix; - return context->CurrentTarget->GetMappedConfig(context->Config, + if (context->CurrentTarget->GetMappedConfig(context->Config, &loc, &imp, - suffix) ? "1" : "0"; + suffix)) + { + // This imported target has an appropriate location + // for this (possibly mapped) config. + // Check if there is a proper config mapping for the tested config. + std::vector<std::string> mappedConfigs; + std::string mapProp = "MAP_IMPORTED_CONFIG_"; + mapProp += cmSystemTools::UpperCase(context->Config); + if(const char* mapValue = + context->CurrentTarget->GetProperty(mapProp.c_str())) + { + cmSystemTools::ExpandListArgument(cmSystemTools::UpperCase(mapValue), + mappedConfigs); + return std::find(mappedConfigs.begin(), mappedConfigs.end(), + cmSystemTools::UpperCase(parameters.front())) + != mappedConfigs.end() ? "1" : "0"; + } + } } return "0"; } } configurationTestNode; +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, @@ -373,7 +687,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, @@ -434,6 +748,18 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode "Target name not supported."); return std::string(); } + if(propertyName == "ALIASED_TARGET") + { + if(context->Makefile->IsAlias(targetName.c_str())) + { + if(cmTarget* tgt = + context->Makefile->FindTargetToUse(targetName.c_str())) + { + return tgt->GetName(); + } + } + return ""; + } target = context->Makefile->FindTargetToUse( targetName.c_str()); @@ -475,6 +801,20 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode assert(target); + if (propertyName == "LINKER_LANGUAGE") + { + if (target->LinkLanguagePropagatesToDependents() && + dagCheckerParent && dagCheckerParent->EvaluatingLinkLibraries()) + { + reportError(context, content->GetOriginalExpression(), + "LINKER_LANGUAGE target property can not be used while evaluating " + "link libraries for a static library"); + return std::string(); + } + const char *lang = target->GetLinkerLanguage(context->Config); + return lang ? lang : ""; + } + cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, target->GetName(), propertyName, @@ -490,7 +830,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) @@ -518,8 +858,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); } } @@ -532,29 +877,39 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode { interfacePropertyName = "INTERFACE_INCLUDE_DIRECTORIES"; } + else if (propertyName == "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES") + { + interfacePropertyName = "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES"; + } else if (propertyName == "INTERFACE_COMPILE_DEFINITIONS" || propertyName == "COMPILE_DEFINITIONS" || strncmp(propertyName.c_str(), "COMPILE_DEFINITIONS_", 20) == 0) { interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS"; } + else if (propertyName == "INTERFACE_COMPILE_OPTIONS" + || propertyName == "COMPILE_OPTIONS") + { + interfacePropertyName = "INTERFACE_COMPILE_OPTIONS"; + } cmTarget *headTarget = context->HeadTarget ? context->HeadTarget : target; - const char **transBegin = targetPropertyTransitiveWhitelist; + 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, - headTarget); - if(iface) + + std::vector<std::string> libs; + target->GetTransitivePropertyLinkLibraries(context->Config, + headTarget, libs); + if (!libs.empty()) { linkedTargetsContent = - getLinkedTargetsContent(iface->Libraries, target, + getLinkedTargetsContent(libs, target, headTarget, context, &dagChecker, interfacePropertyName); @@ -607,7 +962,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) @@ -645,7 +1000,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, @@ -662,10 +1017,13 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode //---------------------------------------------------------------------------- static const char* targetPolicyWhitelist[] = { - "CMP0003" - , "CMP0004" - , "CMP0008" - , "CMP0020" + 0 +#define TARGET_POLICY_STRING(POLICY) \ + , #POLICY + + CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_STRING) + +#undef TARGET_POLICY_STRING }; cmPolicies::PolicyStatus statusForTarget(cmTarget *tgt, const char *policy) @@ -676,10 +1034,7 @@ cmPolicies::PolicyStatus statusForTarget(cmTarget *tgt, const char *policy) return tgt->GetPolicyStatus ## POLICY (); \ } \ - RETURN_POLICY(CMP0003) - RETURN_POLICY(CMP0004) - RETURN_POLICY(CMP0008) - RETURN_POLICY(CMP0020) + CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY) #undef RETURN_POLICY @@ -695,10 +1050,7 @@ cmPolicies::PolicyID policyForString(const char *policy_id) return cmPolicies:: POLICY_ID; \ } \ - RETURN_POLICY_ID(CMP0003) - RETURN_POLICY_ID(CMP0004) - RETURN_POLICY_ID(CMP0008) - RETURN_POLICY_ID(CMP0020) + CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY_ID) #undef RETURN_POLICY_ID @@ -728,7 +1080,7 @@ static const struct TargetPolicyNode : public cmGeneratorExpressionNode context->HadContextSensitiveCondition = true; - for (size_t i = 0; + for (size_t i = 1; i < (sizeof(targetPolicyWhitelist) / sizeof(*targetPolicyWhitelist)); ++i) @@ -754,8 +1106,17 @@ static const struct TargetPolicyNode : public cmGeneratorExpressionNode } reportError(context, content->GetOriginalExpression(), "$<TARGET_POLICY:prop> may only be used with a limited number of " - "policies. Currently it may be used with policies CMP0003, CMP0004, " - "CMP0008 and CMP0020." + "policies. Currently it may be used with the following policies:\n" + +#define STRINGIFY_HELPER(X) #X +#define STRINGIFY(X) STRINGIFY_HELPER(X) + +#define TARGET_POLICY_LIST_ITEM(POLICY) \ + " * " STRINGIFY(POLICY) "\n" + + CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_LIST_ITEM) + +#undef TARGET_POLICY_LIST_ITEM ); return std::string(); } @@ -898,7 +1259,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(); @@ -916,13 +1277,20 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode "No target \"" + name + "\""); return std::string(); } - if(target->GetType() >= cmTarget::UTILITY && + if(target->GetType() >= cmTarget::OBJECT_LIBRARY && target->GetType() != cmTarget::UNKNOWN_LIBRARY) { ::reportError(context, content->GetOriginalExpression(), "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); @@ -974,6 +1342,20 @@ 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 == "C_COMPILER_VERSION") + return &cCompilerVersionNode; + else if (identifier == "CXX_COMPILER_VERSION") + return &cxxCompilerVersionNode; else if (identifier == "CONFIGURATION") return &configurationNode; else if (identifier == "CONFIG") @@ -1018,6 +1400,10 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) return &installInterfaceNode; else if (identifier == "INSTALL_PREFIX") return &installPrefixNode; + else if (identifier == "JOIN") + return &joinNode; + else if (identifier == "LINK_ONLY") + return &linkOnlyNode; return 0; } @@ -1038,6 +1424,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 @@ -1069,7 +1506,8 @@ std::string GeneratorExpressionContent::Evaluate( if (!node->GeneratesContent()) { - if (node->AcceptsSingleArbitraryContentParameter()) + if (node->NumExpectedParameters() == 1 + && node->AcceptsArbitraryContentParameter()) { if (this->ParamChildren.empty()) { @@ -1086,50 +1524,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; @@ -1150,12 +1550,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; @@ -1172,11 +1575,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) { @@ -1201,7 +1615,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."); @@ -1228,7 +1643,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 ce7ad69bb..218abf160 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/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx index a619cecd0..e1fb8f1de 100644 --- a/Source/cmGeneratorExpressionParser.cxx +++ b/Source/cmGeneratorExpressionParser.cxx @@ -126,6 +126,9 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator> commaTokens; std::vector<cmGeneratorExpressionToken>::const_iterator colonToken; + + bool emptyParamTermination = false; + if (this->it != this->Tokens.end() && this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) { @@ -133,6 +136,10 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( parameters.resize(parameters.size() + 1); assert(this->it != this->Tokens.end()); ++this->it; + if(this->it == this->Tokens.end()) + { + emptyParamTermination = true; + } while (this->it != this->Tokens.end() && this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) @@ -141,6 +148,10 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( parameters.resize(parameters.size() + 1); assert(this->it != this->Tokens.end()); ++this->it; + if(this->it == this->Tokens.end()) + { + emptyParamTermination = true; + } } while (this->it != this->Tokens.end() && this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) @@ -164,6 +175,10 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( parameters.resize(parameters.size() + 1); assert(this->it != this->Tokens.end()); ++this->it; + if(this->it == this->Tokens.end()) + { + emptyParamTermination = true; + } } while (this->it != this->Tokens.end() && this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) @@ -203,7 +218,10 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( assert(parameters.size() > commaTokens.size()); for ( ; pit != pend; ++pit, ++commaIt) { - extendResult(result, *pit); + if (!pit->empty() && !emptyParamTermination) + { + extendResult(result, *pit); + } if (commaIt != commaTokens.end()) { extendText(result, *commaIt); diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 335ba0f25..62ac2638d 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -48,6 +48,57 @@ const char *cmGeneratorTarget::GetProperty(const char *prop) } //---------------------------------------------------------------------------- +bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir, + const char *config) +{ + std::string config_upper; + if(config && *config) + { + config_upper = cmSystemTools::UpperCase(config); + } + + typedef std::map<std::string, std::vector<std::string> > IncludeCacheType; + IncludeCacheType::iterator iter = + this->SystemIncludesCache.find(config_upper); + + if (iter == this->SystemIncludesCache.end()) + { + std::vector<std::string> result; + for (std::set<cmStdString>::const_iterator + it = this->Target->GetSystemIncludeDirectories().begin(); + it != this->Target->GetSystemIncludeDirectories().end(); ++it) + { + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", 0, 0); + + cmSystemTools::ExpandListArgument(ge.Parse(*it) + ->Evaluate(this->Makefile, + config, false, this->Target, + &dagChecker), result); + } + for(std::vector<std::string>::iterator li = result.begin(); + li != result.end(); ++li) + { + cmSystemTools::ConvertToUnixSlashes(*li); + } + + IncludeCacheType::value_type entry(config_upper, result); + iter = this->SystemIncludesCache.insert(entry).first; + } + + if (std::find(iter->second.begin(), + iter->second.end(), dir) != iter->second.end()) + { + return true; + } + return false; +} + +//---------------------------------------------------------------------------- bool cmGeneratorTarget::GetPropertyAsBool(const char *prop) { return this->Target->GetPropertyAsBool(prop); @@ -98,6 +149,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 cbcd8a579..dedfa60aa 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. */ @@ -68,10 +72,14 @@ public: /** Get the include directories for this target. */ std::vector<std::string> GetIncludeDirectories(const char *config); + bool IsSystemIncludeDirectory(const char *dir, const char *config); + private: void ClassifySources(); void LookupObjectLibraries(); + std::map<std::string, std::vector<std::string> > SystemIncludesCache; + cmGeneratorTarget(cmGeneratorTarget const&); void operator=(cmGeneratorTarget const&); }; diff --git a/Source/cmGetCMakePropertyCommand.cxx b/Source/cmGetCMakePropertyCommand.cxx index 8bb54877e..e7ad91a36 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 fd1ad601f..1d7fefcee 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 f294daa0d..09af3325a 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 7d3335887..faba7cd35 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" //---------------------------------------------------------------------------- @@ -285,6 +288,18 @@ bool cmGetPropertyCommand::HandleTargetMode() return false; } + if(this->PropertyName == "ALIASED_TARGET") + { + if(this->Makefile->IsAlias(this->Name.c_str())) + { + if(cmTarget* target = + this->Makefile->FindTargetToUse(this->Name.c_str())) + { + return this->StoreResult(target->GetName()); + } + } + return false; + } if(cmTarget* target = this->Makefile->FindTargetToUse(this->Name.c_str())) { return this->StoreResult(target->GetProperty(this->PropertyName.c_str())); diff --git a/Source/cmGetTargetPropertyCommand.cxx b/Source/cmGetTargetPropertyCommand.cxx index 1947139c9..02f00a508 100644 --- a/Source/cmGetTargetPropertyCommand.cxx +++ b/Source/cmGetTargetPropertyCommand.cxx @@ -22,17 +22,30 @@ bool cmGetTargetPropertyCommand } std::string var = args[0].c_str(); const char* targetName = args[1].c_str(); + const char *prop = 0; - if(cmTarget* tgt = this->Makefile->FindTargetToUse(targetName)) + if(args[2] == "ALIASED_TARGET") { - cmTarget& target = *tgt; - const char *prop = target.GetProperty(args[2].c_str()); - if (prop) + if(this->Makefile->IsAlias(targetName)) { - this->Makefile->AddDefinition(var.c_str(), prop); - return true; + if(cmTarget* target = + this->Makefile->FindTargetToUse(targetName)) + { + prop = target->GetName(); + } } } + else if(cmTarget* tgt = this->Makefile->FindTargetToUse(targetName)) + { + cmTarget& target = *tgt; + prop = target.GetProperty(args[2].c_str()); + } + + if (prop) + { + this->Makefile->AddDefinition(var.c_str(), prop); + return true; + } this->Makefile->AddDefinition(var.c_str(), (var+"-NOTFOUND").c_str()); return true; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index df1433105..f297c4abb 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_"; @@ -840,6 +848,14 @@ void cmGlobalGenerator::Configure() delete this->LocalGenerators[i]; } this->LocalGenerators.clear(); + for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator + li = this->EvaluationFiles.begin(); + li != this->EvaluationFiles.end(); + ++li) + { + delete *li; + } + this->EvaluationFiles.clear(); this->TargetDependencies.clear(); this->TotalTargets.clear(); this->ImportedTargets.clear(); @@ -884,12 +900,28 @@ void cmGlobalGenerator::Configure() if ( this->CMakeInstance->GetWorkingMode() == cmake::NORMAL_MODE) { - const char* msg = "Configuring done"; + cmOStringStream msg; if(cmSystemTools::GetErrorOccuredFlag()) { - msg = "Configuring incomplete, errors occurred!"; + msg << "Configuring incomplete, errors occurred!"; + const char* logs[] = {"CMakeOutput.log", "CMakeError.log", 0}; + for(const char** log = logs; *log; ++log) + { + std::string f = this->CMakeInstance->GetHomeOutputDirectory(); + f += this->CMakeInstance->GetCMakeFilesDirectory(); + f += "/"; + f += *log; + if(cmSystemTools::FileExists(f.c_str())) + { + msg << "\nSee also \"" << f << "\"."; + } + } } - this->CMakeInstance->UpdateProgress(msg, -1); + else + { + msg << "Configuring done"; + } + this->CMakeInstance->UpdateProgress(msg.str().c_str(), -1); } } @@ -932,6 +964,8 @@ void cmGlobalGenerator::Generate() return; } + this->FinalizeTargetCompileDefinitions(); + // Iterate through all targets and set up automoc for those which have // the AUTOMOC property set this->CreateAutomocTargets(); @@ -955,7 +989,7 @@ void cmGlobalGenerator::Generate() for ( tit = targets->begin(); tit != targets->end(); ++ tit ) { - tit->second.AppendBuildInterfaceIncludes(); + tit->second.AppendBuildInterfaceIncludes(); } } @@ -981,6 +1015,8 @@ void cmGlobalGenerator::Generate() // Create per-target generator information. this->CreateGeneratorTargets(); + this->ProcessEvaluationFiles(); + // Compute the inter-target dependencies. if(!this->ComputeTargetDepends()) { @@ -991,6 +1027,17 @@ void cmGlobalGenerator::Generate() // it builds by default. this->FillLocalGeneratorToTargetMap(); + for (i = 0; i < this->LocalGenerators.size(); ++i) + { + cmMakefile* mf = this->LocalGenerators[i]->GetMakefile(); + cmTargets* targets = &(mf->GetTargets()); + for ( cmTargets::iterator it = targets->begin(); + it != targets->end(); ++ it ) + { + it->second.FinalizeSystemIncludeDirectories(); + } + } + // Generate project files for (i = 0; i < this->LocalGenerators.size(); ++i) { @@ -1051,6 +1098,7 @@ bool cmGlobalGenerator::CheckTargets() target.GetType() == cmTarget::STATIC_LIBRARY || target.GetType() == cmTarget::SHARED_LIBRARY || target.GetType() == cmTarget::MODULE_LIBRARY || + target.GetType() == cmTarget::OBJECT_LIBRARY || target.GetType() == cmTarget::UTILITY) { if(!target.FindSourceFiles()) @@ -1103,16 +1151,15 @@ void cmGlobalGenerator::CreateAutomocTargets() } //---------------------------------------------------------------------------- -void cmGlobalGenerator::CreateGeneratorTargets() +void cmGlobalGenerator::FinalizeTargetCompileDefinitions() { // Construct per-target generator information. for(unsigned int i=0; i < this->LocalGenerators.size(); ++i) { - cmGeneratorTargetsType generatorTargets; - cmMakefile *mf = this->LocalGenerators[i]->GetMakefile(); - const char *noconfig_compile_definitions = - mf->GetProperty("COMPILE_DEFINITIONS"); + + const std::vector<cmValueWithOrigin> noconfig_compile_definitions = + mf->GetCompileDefinitionsEntries(); std::vector<std::string> configs; mf->GetConfigurations(configs); @@ -1123,8 +1170,13 @@ void cmGlobalGenerator::CreateGeneratorTargets() { cmTarget* t = &ti->second; - { - t->AppendProperty("COMPILE_DEFINITIONS", noconfig_compile_definitions); + for (std::vector<cmValueWithOrigin>::const_iterator it + = noconfig_compile_definitions.begin(); + it != noconfig_compile_definitions.end(); ++it) + { + t->InsertCompileDefinition(*it); + } + for(std::vector<std::string>::const_iterator ci = configs.begin(); ci != configs.end(); ++ci) { @@ -1134,7 +1186,24 @@ void cmGlobalGenerator::CreateGeneratorTargets() mf->GetProperty(defPropName.c_str())); } } + } +} +//---------------------------------------------------------------------------- +void cmGlobalGenerator::CreateGeneratorTargets() +{ + // Construct per-target generator information. + for(unsigned int i=0; i < this->LocalGenerators.size(); ++i) + { + cmGeneratorTargetsType generatorTargets; + + cmMakefile *mf = this->LocalGenerators[i]->GetMakefile(); + + cmTargets& targets = mf->GetTargets(); + for(cmTargets::iterator ti = targets.begin(); + ti != targets.end(); ++ti) + { + cmTarget* t = &ti->second; cmGeneratorTarget* gt = new cmGeneratorTarget(t); this->GeneratorTargets[t] = gt; this->ComputeTargetObjects(gt); @@ -1340,11 +1409,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 +1482,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 +1514,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) @@ -1723,10 +1794,22 @@ cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(const char* start_dir) return 0; } +//---------------------------------------------------------------------------- +void cmGlobalGenerator::AddAlias(const char *name, cmTarget *tgt) +{ + this->AliasTargets[name] = tgt; +} + +//---------------------------------------------------------------------------- +bool cmGlobalGenerator::IsAlias(const char *name) +{ + return this->AliasTargets.find(name) != this->AliasTargets.end(); +} //---------------------------------------------------------------------------- cmTarget* -cmGlobalGenerator::FindTarget(const char* project, const char* name) +cmGlobalGenerator::FindTarget(const char* project, const char* name, + bool excludeAliases) { // if project specific if(project) @@ -1734,7 +1817,8 @@ cmGlobalGenerator::FindTarget(const char* project, const char* name) std::vector<cmLocalGenerator*>* gens = &this->ProjectMap[project]; for(unsigned int i = 0; i < gens->size(); ++i) { - cmTarget* ret = (*gens)[i]->GetMakefile()->FindTarget(name); + cmTarget* ret = (*gens)[i]->GetMakefile()->FindTarget(name, + excludeAliases); if(ret) { return ret; @@ -1744,6 +1828,15 @@ cmGlobalGenerator::FindTarget(const char* project, const char* name) // if all projects/directories else { + if (!excludeAliases) + { + std::map<cmStdString, cmTarget*>::iterator ai + = this->AliasTargets.find(name); + if (ai != this->AliasTargets.end()) + { + return ai->second; + } + } std::map<cmStdString,cmTarget *>::iterator i = this->TotalTargets.find ( name ); if ( i != this->TotalTargets.end() ) @@ -2558,3 +2651,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 11616e0d0..80916ae59 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 @@ -193,7 +196,11 @@ public: void FindMakeProgram(cmMakefile*); ///! Find a target by name by searching the local generators. - cmTarget* FindTarget(const char* project, const char* name); + cmTarget* FindTarget(const char* project, const char* name, + bool excludeAliases = false); + + void AddAlias(const char *name, cmTarget *tgt); + bool IsAlias(const char *name); /** Determine if a name resolves to a framework on disk or a built target that is a framework. */ @@ -278,6 +285,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 @@ -336,7 +351,9 @@ protected: // All targets in the entire project. std::map<cmStdString,cmTarget *> TotalTargets; + std::map<cmStdString,cmTarget *> AliasTargets; std::map<cmStdString,cmTarget *> ImportedTargets; + std::vector<cmGeneratorExpressionEvaluationFile*> EvaluationFiles; virtual const char* GetPredefinedTargetsFolder(); virtual bool UseFolderProperty(); @@ -365,6 +382,7 @@ private: void WriteSummary(); void WriteSummary(cmTarget* target); + void FinalizeTargetCompileDefinitions(); cmExternalMakefileProjectGenerator* ExtraGenerator; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index fa277b1d1..1953546de 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -10,11 +10,12 @@ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more information. ============================================================================*/ +#include "cmGeneratedFileStream.h" +#include "cmGeneratorExpressionEvaluationFile.h" +#include "cmGeneratorTarget.h" #include "cmGlobalNinjaGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" -#include "cmGeneratedFileStream.h" -#include "cmGeneratorTarget.h" #include "cmVersion.h" #include <algorithm> @@ -140,8 +141,15 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, for(cmNinjaDeps::const_iterator i = explicitDeps.begin(); i != explicitDeps.end(); ++i) + { arguments << " " << EncodeIdent(EncodePath(*i), os); + //we need to track every dependency that comes in, since we are trying + //to find dependencies that are side effects of build commands + // + this->CombinedBuildExplicitDependencies.insert( EncodePath(*i) ); + } + // Write implicit dependencies. if(!implicitDeps.empty()) { @@ -170,7 +178,10 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, build << "build"; for(cmNinjaDeps::const_iterator i = outputs.begin(); i != outputs.end(); ++i) + { build << " " << EncodeIdent(EncodePath(*i), os); + this->CombinedBuildOutputs.insert( EncodePath(*i) ); + } build << ":"; // Write the rule. @@ -208,14 +219,14 @@ void cmGlobalNinjaGenerator::WritePhonyBuild(std::ostream& os, const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables) { - cmGlobalNinjaGenerator::WriteBuild(os, - comment, - "phony", - outputs, - explicitDeps, - implicitDeps, - orderOnlyDeps, - variables); + this->WriteBuild(os, + comment, + "phony", + outputs, + explicitDeps, + implicitDeps, + orderOnlyDeps, + variables); } void cmGlobalNinjaGenerator::AddCustomCommandRule() @@ -251,14 +262,14 @@ cmGlobalNinjaGenerator::WriteCustomCommandBuild(const std::string& command, vars["COMMAND"] = cmd; vars["DESC"] = EncodeLiteral(description); - cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream, - comment, - "CUSTOM_COMMAND", - outputs, - deps, - cmNinjaDeps(), - orderOnlyDeps, - vars); + this->WriteBuild(*this->BuildFileStream, + comment, + "CUSTOM_COMMAND", + outputs, + deps, + cmNinjaDeps(), + orderOnlyDeps, + vars); } void @@ -293,14 +304,14 @@ cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input, deps.push_back(input); cmNinjaVars vars; - cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream, - "", - "COPY_OSX_CONTENT", - outputs, - deps, - cmNinjaDeps(), - cmNinjaDeps(), - cmNinjaVars()); + this->WriteBuild(*this->BuildFileStream, + "", + "COPY_OSX_CONTENT", + outputs, + deps, + cmNinjaDeps(), + cmNinjaDeps(), + cmNinjaVars()); } void cmGlobalNinjaGenerator::WriteRule(std::ostream& os, @@ -478,6 +489,7 @@ void cmGlobalNinjaGenerator::Generate() this->WriteAssumedSourceDependencies(); this->WriteTargetAliases(*this->BuildFileStream); + this->WriteUnknownExplicitDependencies(*this->BuildFileStream); this->WriteBuiltinTargets(*this->BuildFileStream); if (cmSystemTools::GetErrorOccuredFlag()) { @@ -523,14 +535,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; @@ -810,13 +824,19 @@ cmGlobalNinjaGenerator cmLocalNinjaGenerator *ng = static_cast<cmLocalNinjaGenerator *>(this->LocalGenerators[0]); + // for frameworks, we want the real name, not smple name + // frameworks always appear versioned, and the build.ninja + // will always attempt to manage symbolic links instead + // of letting cmOSXBundleGenerator do it. + bool realname = target->IsFrameworkOnApple(); + switch (target->GetType()) { case cmTarget::EXECUTABLE: case cmTarget::SHARED_LIBRARY: case cmTarget::STATIC_LIBRARY: case cmTarget::MODULE_LIBRARY: outputs.push_back(ng->ConvertToNinjaPath( - target->GetFullPath(configName).c_str())); + target->GetFullPath(configName, false, realname).c_str())); break; case cmTarget::OBJECT_LIBRARY: @@ -885,7 +905,7 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) cmGlobalNinjaGenerator::WriteDivider(os); os << "# Target aliases.\n\n"; - for (TargetAliasMap::iterator i = TargetAliases.begin(); + for (TargetAliasMap::const_iterator i = TargetAliases.begin(); i != TargetAliases.end(); ++i) { // Don't write ambiguous aliases. if (!i->second) @@ -894,13 +914,128 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) cmNinjaDeps deps; this->AppendTargetOutputs(i->second, deps); - cmGlobalNinjaGenerator::WritePhonyBuild(os, - "", - cmNinjaDeps(1, i->first), - deps); + this->WritePhonyBuild(os, + "", + cmNinjaDeps(1, i->first), + deps); } } +void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os) +{ + //now write out the unknown explicit dependencies. + + //union the configured files, evaluations files and the CombinedBuildOutputs, + //and then difference with CombinedExplicitDependencies to find the explicit + //dependencies that we have no rule for + + cmGlobalNinjaGenerator::WriteDivider(os); + os << "# Unknown Build Time Dependencies.\n" + << "# Tell Ninja that they may appear as side effects of build rules\n" + << "# otherwise ordered by order-only dependencies.\n\n"; + + //get the list of files that cmake itself has generated as a + //product of configuration. + cmLocalNinjaGenerator *ng = + static_cast<cmLocalNinjaGenerator *>(this->LocalGenerators[0]); + + std::set<std::string> knownDependencies; + for (std::vector<cmLocalGenerator *>::const_iterator i = + this->LocalGenerators.begin(); i != this->LocalGenerators.end(); ++i) + { + //get the vector of files created by this makefile and convert them + //to ninja paths, which are all relative in respect to the build directory + const std::vector<std::string>& files = + (*i)->GetMakefile()->GetOutputFiles(); + typedef std::vector<std::string>::const_iterator vect_it; + for(vect_it j = files.begin(); j != files.end(); ++j) + { + knownDependencies.insert( ng->ConvertToNinjaPath( j->c_str() ) ); + } + } + + for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator + li = this->EvaluationFiles.begin(); + li != this->EvaluationFiles.end(); + ++li) + { + //get all the files created by generator expressions and convert them + //to ninja paths + std::vector<std::string> files = (*li)->GetFiles(); + typedef std::vector<std::string>::const_iterator vect_it; + for(vect_it j = files.begin(); j != files.end(); ++j) + { + knownDependencies.insert( ng->ConvertToNinjaPath( j->c_str() ) ); + } + } + + for(TargetAliasMap::const_iterator i= this->TargetAliases.begin(); + i != this->TargetAliases.end(); + ++i) + { + knownDependencies.insert( ng->ConvertToNinjaPath(i->first.c_str()) ); + } + + //remove all source files we know will exist. + typedef std::map<std::string, std::set<std::string> >::const_iterator map_it; + for(map_it i = this->AssumedSourceDependencies.begin(); + i != this->AssumedSourceDependencies.end(); + ++i) + { + knownDependencies.insert( ng->ConvertToNinjaPath(i->first.c_str()) ); + } + + //insert outputs from all WirteBuild commands + for(std::set<std::string>::iterator i = this->CombinedBuildOutputs.begin(); + i != this->CombinedBuildOutputs.end(); ++i) + { + //these paths have already be encoded when added to CombinedBuildOutputs + knownDependencies.insert(*i); + } + + //after we have combined the data into knownDependencies we have no need + //to keep this data around + this->CombinedBuildOutputs.clear(); + + //now we difference with CombinedBuildExplicitDependencies to find + //the list of items we know nothing about. + //We have encoded all the paths in CombinedBuildExplicitDependencies + //and knownDependencies so no matter if unix or windows paths they + //should all match now. + + std::vector<std::string> unkownExplicitDepends; + this->CombinedBuildExplicitDependencies.erase("all"); + + std::set_difference(this->CombinedBuildExplicitDependencies.begin(), + this->CombinedBuildExplicitDependencies.end(), + knownDependencies.begin(), + knownDependencies.end(), + std::back_inserter(unkownExplicitDepends)); + + + std::string const rootBuildDirectory = + this->GetCMakeInstance()->GetHomeOutputDirectory(); + for (std::vector<std::string>::const_iterator + i = unkownExplicitDepends.begin(); + i != unkownExplicitDepends.end(); + ++i) + { + //verify the file is in the build directory + std::string const absDepPath = cmSystemTools::CollapseFullPath( + i->c_str(), rootBuildDirectory.c_str()); + bool const inBuildDir = cmSystemTools::IsSubDirectory(absDepPath.c_str(), + rootBuildDirectory.c_str()); + if(inBuildDir) + { + cmNinjaDeps deps(1,*i); + this->WritePhonyBuild(os, + "", + deps, + deps); + } + } +} + void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os) { // Write headers. @@ -918,10 +1053,10 @@ void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os) cmNinjaDeps outputs; outputs.push_back("all"); - cmGlobalNinjaGenerator::WritePhonyBuild(os, - "The main all target.", - outputs, - this->AllDependencies); + this->WritePhonyBuild(os, + "The main all target.", + outputs, + this->AllDependencies); cmGlobalNinjaGenerator::WriteDefault(os, outputs, @@ -965,19 +1100,19 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) implicitDeps.end()); implicitDeps.push_back("CMakeCache.txt"); - WriteBuild(os, - "Re-run CMake if any of its inputs changed.", - "RERUN_CMAKE", - /*outputs=*/ cmNinjaDeps(1, NINJA_BUILD_FILE), - /*explicitDeps=*/ cmNinjaDeps(), - implicitDeps, - /*orderOnlyDeps=*/ cmNinjaDeps(), - /*variables=*/ cmNinjaVars()); - - WritePhonyBuild(os, - "A missing CMake input file is not an error.", - implicitDeps, - cmNinjaDeps()); + this->WriteBuild(os, + "Re-run CMake if any of its inputs changed.", + "RERUN_CMAKE", + /*outputs=*/ cmNinjaDeps(1, NINJA_BUILD_FILE), + /*explicitDeps=*/ cmNinjaDeps(), + implicitDeps, + /*orderOnlyDeps=*/ cmNinjaDeps(), + /*variables=*/ cmNinjaVars()); + + this->WritePhonyBuild(os, + "A missing CMake input file is not an error.", + implicitDeps, + cmNinjaDeps()); } std::string cmGlobalNinjaGenerator::ninjaCmd() const diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index c3df7d935..e046c7c96 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -77,27 +77,27 @@ public: * It also writes the variables bound to this build statement. * @warning no escaping of any kind is done here. */ - static void WriteBuild(std::ostream& os, - const std::string& comment, - const std::string& rule, - const cmNinjaDeps& outputs, - const cmNinjaDeps& explicitDeps, - const cmNinjaDeps& implicitDeps, - const cmNinjaDeps& orderOnlyDeps, - const cmNinjaVars& variables, - const std::string& rspfile = std::string(), - int cmdLineLimit = -1); + void WriteBuild(std::ostream& os, + const std::string& comment, + const std::string& rule, + const cmNinjaDeps& outputs, + const cmNinjaDeps& explicitDeps, + const cmNinjaDeps& implicitDeps, + const cmNinjaDeps& orderOnlyDeps, + const cmNinjaVars& variables, + const std::string& rspfile = std::string(), + int cmdLineLimit = -1); /** * Helper to write a build statement with the special 'phony' rule. */ - static void WritePhonyBuild(std::ostream& os, - const std::string& comment, - const cmNinjaDeps& outputs, - const cmNinjaDeps& explicitDeps, - const cmNinjaDeps& implicitDeps = cmNinjaDeps(), - const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(), - const cmNinjaVars& variables = cmNinjaVars()); + void WritePhonyBuild(std::ostream& os, + const std::string& comment, + const cmNinjaDeps& outputs, + const cmNinjaDeps& explicitDeps, + const cmNinjaDeps& implicitDeps = cmNinjaDeps(), + const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(), + const cmNinjaVars& variables = cmNinjaVars()); void WriteCustomCommandBuild(const std::string& command, const std::string& description, @@ -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, @@ -320,6 +321,7 @@ private: void WriteAssumedSourceDependencies(); void WriteTargetAliases(std::ostream& os); + void WriteUnknownExplicitDependencies(std::ostream& os); void WriteBuiltinTargets(std::ostream& os); void WriteTargetAll(std::ostream& os); @@ -357,6 +359,12 @@ private: /// The set of custom command outputs we have seen. std::set<std::string> CustomCommandOutputs; + //The combined explicit dependencies of all build commands that the global + //generator has issued. When combined with CombinedBuildOutputs it allows + //us to detect the set of explicit dependencies that have + std::set<std::string> CombinedBuildExplicitDependencies; + std::set<std::string> CombinedBuildOutputs; + /// The mapping from source file to assumed dependencies. std::map<std::string, std::set<std::string> > AssumedSourceDependencies; diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index e26cca940..88cd6e5f8 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 385cdc4a1..5e9dce3a6 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 ee7c56fc6..b2a337cc6 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"; @@ -28,17 +30,17 @@ public: if(!strcmp(name, vs10Win32generatorName)) { return new cmGlobalVisualStudio10Generator( - vs10Win32generatorName, NULL, NULL); + name, NULL, NULL); } if(!strcmp(name, vs10Win64generatorName)) { return new cmGlobalVisualStudio10Generator( - vs10Win64generatorName, "x64", "CMAKE_FORCE_WIN64"); + name, "x64", "CMAKE_FORCE_WIN64"); } if(!strcmp(name, vs10IA64generatorName)) { return new cmGlobalVisualStudio10Generator( - vs10IA64generatorName, "Itanium", "CMAKE_FORCE_IA64"); + name, "Itanium", "CMAKE_FORCE_IA64"); } return 0; } @@ -67,9 +69,9 @@ cmGlobalGeneratorFactory* cmGlobalVisualStudio10Generator::NewFactory() //---------------------------------------------------------------------------- cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator( - const char* name, const char* architectureId, + const char* name, const char* platformName, const char* additionalPlatformDefinition) - : cmGlobalVisualStudio8Generator(name, architectureId, + : cmGlobalVisualStudio8Generator(name, platformName, additionalPlatformDefinition) { this->FindMakeProgramFile = "CMakeVS10FindMake.cmake"; @@ -77,6 +79,7 @@ cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator( this->ExpressEdition = cmSystemTools::ReadRegistryValue( "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\10.0\\Setup\\VC;" "ProductDir", vc10Express, cmSystemTools::KeyWOW64_32); + this->MasmEnabled = false; } //---------------------------------------------------------------------------- @@ -159,13 +162,23 @@ void cmGlobalVisualStudio10Generator ::EnableLanguage(std::vector<std::string>const & lang, cmMakefile *mf, bool optional) { - if(this->ArchitectureId == "Itanium" || this->ArchitectureId == "x64") + if(this->PlatformName == "Itanium" || this->PlatformName == "x64") { if(this->IsExpressEdition() && !this->Find64BitTools(mf)) { return; } } + + for(std::vector<std::string>::const_iterator it = lang.begin(); + it != lang.end(); ++it) + { + if(*it == "ASM_MASM") + { + this->MasmEnabled = true; + } + } + cmGlobalVisualStudio8Generator::EnableLanguage(lang, mf, optional); } @@ -215,7 +228,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 +243,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 +272,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 5926e0f21..31e122efe 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -25,14 +25,14 @@ class cmGlobalVisualStudio10Generator : { public: cmGlobalVisualStudio10Generator(const char* name, - const char* architectureId, const char* additionalPlatformDefinition); + const char* platformName, const char* additionalPlatformDefinition); static cmGlobalGeneratorFactory* NewFactory(); virtual bool SetGeneratorToolset(std::string const& ts); 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); @@ -54,6 +54,9 @@ public: /** Is the installed VS an Express edition? */ bool IsExpressEdition() const { return this->ExpressEdition; } + /** Is the Microsoft Assembler enabled? */ + bool IsMasmEnabled() const { return this->MasmEnabled; } + /** The toolset name for the target platform. */ const char* GetPlatformToolset(); @@ -78,11 +81,15 @@ public: void PathTooLong(cmTarget* target, cmSourceFile* sf, std::string const& sfRel); + + virtual const char* GetToolsVersion() { return "4.0"; } + protected: virtual const char* GetIDEVersion() { return "10.0"; } std::string PlatformToolset; bool ExpressEdition; + bool MasmEnabled; bool UseFolderProperty(); diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx index 624d01d69..8ae733165 100644 --- a/Source/cmGlobalVisualStudio11Generator.cxx +++ b/Source/cmGlobalVisualStudio11Generator.cxx @@ -13,31 +13,56 @@ #include "cmLocalVisualStudio10Generator.h" #include "cmMakefile.h" -static const char vs11Win32generatorName[] = "Visual Studio 11"; -static const char vs11Win64generatorName[] = "Visual Studio 11 Win64"; -static const char vs11ARMgeneratorName[] = "Visual Studio 11 ARM"; +static const char vs11generatorName[] = "Visual Studio 11"; class cmGlobalVisualStudio11Generator::Factory : public cmGlobalGeneratorFactory { public: virtual cmGlobalGenerator* CreateGlobalGenerator(const char* name) const { - if(!strcmp(name, vs11Win32generatorName)) + if(strstr(name, vs11generatorName) != name) + { + return 0; + } + + const char* p = name + sizeof(vs11generatorName) - 1; + if(p[0] == '\0') { return new cmGlobalVisualStudio11Generator( - vs11Win32generatorName, NULL, NULL); + name, NULL, NULL); + } + + if(p[0] != ' ') + { + return 0; } - if(!strcmp(name, vs11Win64generatorName)) + + ++p; + + if(!strcmp(p, "ARM")) { return new cmGlobalVisualStudio11Generator( - vs11Win64generatorName, "x64", "CMAKE_FORCE_WIN64"); + name, "ARM", NULL); } - if(!strcmp(name, vs11ARMgeneratorName)) + + if(!strcmp(p, "Win64")) { return new cmGlobalVisualStudio11Generator( - vs11ARMgeneratorName, "ARM", NULL); + name, "x64", "CMAKE_FORCE_WIN64"); } - return 0; + + std::set<std::string> installedSDKs = + cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs(); + + if(installedSDKs.find(p) == installedSDKs.end()) + { + return 0; + } + + cmGlobalVisualStudio11Generator* ret = + new cmGlobalVisualStudio11Generator(name, p, NULL); + ret->WindowsCEVersion = "8.00"; + return ret; } virtual void GetDocumentation(cmDocumentationEntry& entry) const { @@ -51,9 +76,18 @@ public: } virtual void GetGenerators(std::vector<std::string>& names) const { - names.push_back(vs11Win32generatorName); - names.push_back(vs11Win64generatorName); - names.push_back(vs11ARMgeneratorName); } + names.push_back(vs11generatorName); + names.push_back(vs11generatorName + std::string(" ARM")); + names.push_back(vs11generatorName + std::string(" Win64")); + + std::set<std::string> installedSDKs = + cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs(); + for(std::set<std::string>::const_iterator i = + installedSDKs.begin(); i != installedSDKs.end(); ++i) + { + names.push_back("Visual Studio 11 " + *i); + } + } }; //---------------------------------------------------------------------------- @@ -64,9 +98,9 @@ cmGlobalGeneratorFactory* cmGlobalVisualStudio11Generator::NewFactory() //---------------------------------------------------------------------------- cmGlobalVisualStudio11Generator::cmGlobalVisualStudio11Generator( - const char* name, const char* architectureId, + const char* name, const char* platformName, const char* additionalPlatformDefinition) - : cmGlobalVisualStudio10Generator(name, architectureId, + : cmGlobalVisualStudio10Generator(name, platformName, additionalPlatformDefinition) { this->FindMakeProgramFile = "CMakeVS11FindMake.cmake"; @@ -109,3 +143,36 @@ bool cmGlobalVisualStudio11Generator::UseFolderProperty() // Express editions in VS10 and earlier, but they are in VS11 Express. return cmGlobalVisualStudio8Generator::UseFolderProperty(); } + +//---------------------------------------------------------------------------- +std::set<std::string> +cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs() +{ + const char sdksKey[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" + "Windows CE Tools\\SDKs"; + + std::vector<std::string> subkeys; + cmSystemTools::GetRegistrySubKeys(sdksKey, subkeys, + cmSystemTools::KeyWOW64_32); + + std::set<std::string> ret; + for(std::vector<std::string>::const_iterator i = + subkeys.begin(); i != subkeys.end(); ++i) + { + std::string key = sdksKey; + key += '\\'; + key += *i; + key += ';'; + + std::string path; + if(cmSystemTools::ReadRegistryValue(key.c_str(), + path, + cmSystemTools::KeyWOW64_32) && + !path.empty()) + { + ret.insert(*i); + } + } + + return ret; +} diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h index 174f1ccb0..7cc7e69d9 100644 --- a/Source/cmGlobalVisualStudio11Generator.h +++ b/Source/cmGlobalVisualStudio11Generator.h @@ -21,7 +21,7 @@ class cmGlobalVisualStudio11Generator: { public: cmGlobalVisualStudio11Generator(const char* name, - const char* architectureId, const char* additionalPlatformDefinition); + const char* platformName, const char* additionalPlatformDefinition); static cmGlobalGeneratorFactory* NewFactory(); virtual void WriteSLNHeader(std::ostream& fout); @@ -34,7 +34,9 @@ public: protected: virtual const char* GetIDEVersion() { return "11.0"; } bool UseFolderProperty(); + static std::set<std::string> GetInstalledWindowsCESDKs(); private: class Factory; + friend class Factory; }; #endif diff --git a/Source/cmGlobalVisualStudio12Generator.cxx b/Source/cmGlobalVisualStudio12Generator.cxx index d77b84d2c..c56dfff15 100644 --- a/Source/cmGlobalVisualStudio12Generator.cxx +++ b/Source/cmGlobalVisualStudio12Generator.cxx @@ -25,17 +25,17 @@ public: if(!strcmp(name, vs12Win32generatorName)) { return new cmGlobalVisualStudio12Generator( - vs12Win32generatorName, NULL, NULL); + name, NULL, NULL); } if(!strcmp(name, vs12Win64generatorName)) { return new cmGlobalVisualStudio12Generator( - vs12Win64generatorName, "x64", "CMAKE_FORCE_WIN64"); + name, "x64", "CMAKE_FORCE_WIN64"); } if(!strcmp(name, vs12ARMgeneratorName)) { return new cmGlobalVisualStudio12Generator( - vs12ARMgeneratorName, "ARM", NULL); + name, "ARM", NULL); } return 0; } @@ -64,9 +64,9 @@ cmGlobalGeneratorFactory* cmGlobalVisualStudio12Generator::NewFactory() //---------------------------------------------------------------------------- cmGlobalVisualStudio12Generator::cmGlobalVisualStudio12Generator( - const char* name, const char* architectureId, + const char* name, const char* platformName, const char* additionalPlatformDefinition) - : cmGlobalVisualStudio11Generator(name, architectureId, + : cmGlobalVisualStudio11Generator(name, platformName, additionalPlatformDefinition) { this->FindMakeProgramFile = "CMakeVS12FindMake.cmake"; @@ -100,12 +100,3 @@ cmLocalGenerator *cmGlobalVisualStudio12Generator::CreateLocalGenerator() lg->SetGlobalGenerator(this); return lg; } - -//---------------------------------------------------------------------------- -bool cmGlobalVisualStudio12Generator::UseFolderProperty() -{ - // Intentionally skip over the parent class implementation and call the - // grand-parent class's implementation. Folders are not supported by the - // Express editions in VS10 and earlier, but they are in VS12 Express. - return cmGlobalVisualStudio8Generator::UseFolderProperty(); -} diff --git a/Source/cmGlobalVisualStudio12Generator.h b/Source/cmGlobalVisualStudio12Generator.h index 5844ee01e..8c8aeb1fd 100644 --- a/Source/cmGlobalVisualStudio12Generator.h +++ b/Source/cmGlobalVisualStudio12Generator.h @@ -21,7 +21,7 @@ class cmGlobalVisualStudio12Generator: { public: cmGlobalVisualStudio12Generator(const char* name, - const char* architectureId, const char* additionalPlatformDefinition); + const char* platformName, const char* additionalPlatformDefinition); static cmGlobalGeneratorFactory* NewFactory(); virtual void WriteSLNHeader(std::ostream& fout); @@ -31,9 +31,13 @@ public: /** TODO: VS 12 user macro support. */ virtual std::string GetUserMacrosDirectory() { return ""; } + + //in Visual Studio 2013 they detached the MSBuild tools version + //from the .Net Framework version and instead made it have it's own + //version number + virtual const char* GetToolsVersion() { return "12.0"; } protected: virtual const char* GetIDEVersion() { return "12.0"; } - bool UseFolderProperty(); private: class Factory; }; diff --git a/Source/cmGlobalVisualStudio6Generator.cxx b/Source/cmGlobalVisualStudio6Generator.cxx index 9f3af71bb..b3fabdade 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 40149e911..6bd39ca9a 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/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index 2494f559c..51efc466c 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -16,7 +16,8 @@ #include "cmake.h" //---------------------------------------------------------------------------- -cmGlobalVisualStudio71Generator::cmGlobalVisualStudio71Generator() +cmGlobalVisualStudio71Generator::cmGlobalVisualStudio71Generator( + const char* platformName) : cmGlobalVisualStudio7Generator(platformName) { this->FindMakeProgramFile = "CMakeVS71FindMake.cmake"; this->ProjectConfigurationSectionName = "ProjectConfiguration"; @@ -281,20 +282,20 @@ void cmGlobalVisualStudio71Generator const std::set<std::string>& configsPartOfDefaultBuild, const char* platformMapping) { + const char* platformName = + platformMapping ? platformMapping : this->GetPlatformName(); std::string guid = this->GetGUID(name); for(std::vector<std::string>::iterator i = this->Configurations.begin(); i != this->Configurations.end(); ++i) { fout << "\t\t{" << guid << "}." << *i - << ".ActiveCfg = " << *i << "|" - << (platformMapping ? platformMapping : "Win32") << std::endl; + << ".ActiveCfg = " << *i << "|" << platformName << std::endl; std::set<std::string>::const_iterator ci = configsPartOfDefaultBuild.find(*i); if(!(ci == configsPartOfDefaultBuild.end())) { fout << "\t\t{" << guid << "}." << *i - << ".Build.0 = " << *i << "|" - << (platformMapping ? platformMapping : "Win32") << std::endl; + << ".Build.0 = " << *i << "|" << platformName << std::endl; } } } diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h index 6d91f97fc..e136db7ea 100644 --- a/Source/cmGlobalVisualStudio71Generator.h +++ b/Source/cmGlobalVisualStudio71Generator.h @@ -23,7 +23,7 @@ class cmGlobalVisualStudio71Generator : public cmGlobalVisualStudio7Generator { public: - cmGlobalVisualStudio71Generator(); + cmGlobalVisualStudio71Generator(const char* platformName = NULL); static cmGlobalGeneratorFactory* NewFactory() { return new cmGlobalGeneratorSimpleFactory <cmGlobalVisualStudio71Generator>(); } diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 63cbdb890..b47566561 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -17,9 +17,16 @@ #include "cmMakefile.h" #include "cmake.h" -cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator() +cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator( + const char* platformName) { this->FindMakeProgramFile = "CMakeVS7FindMake.cmake"; + + if (!platformName) + { + platformName = "Win32"; + } + this->PlatformName = platformName; } @@ -31,6 +38,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 +73,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; @@ -132,6 +151,13 @@ cmLocalGenerator *cmGlobalVisualStudio7Generator::CreateLocalGenerator() return lg; } +//---------------------------------------------------------------------------- +void cmGlobalVisualStudio7Generator::AddPlatformDefinitions(cmMakefile* mf) +{ + cmGlobalVisualStudioGenerator::AddPlatformDefinitions(mf); + mf->AddDefinition("CMAKE_VS_PLATFORM_NAME", this->GetPlatformName()); +} + void cmGlobalVisualStudio7Generator::GenerateConfigurations(cmMakefile* mf) { // process the configurations @@ -589,20 +615,20 @@ void cmGlobalVisualStudio7Generator const std::set<std::string>& configsPartOfDefaultBuild, const char* platformMapping) { + const char* platformName = + platformMapping ? platformMapping : this->GetPlatformName(); std::string guid = this->GetGUID(name); for(std::vector<std::string>::iterator i = this->Configurations.begin(); i != this->Configurations.end(); ++i) { fout << "\t\t{" << guid << "}." << *i - << ".ActiveCfg = " << *i << "|" - << (platformMapping ? platformMapping : "Win32") << "\n"; + << ".ActiveCfg = " << *i << "|" << platformName << "\n"; std::set<std::string>::const_iterator ci = configsPartOfDefaultBuild.find(*i); if(!(ci == configsPartOfDefaultBuild.end())) { fout << "\t\t{" << guid << "}." << *i - << ".Build.0 = " << *i << "|" - << (platformMapping ? platformMapping : "Win32") << "\n"; + << ".Build.0 = " << *i << "|" << platformName << "\n"; } } } diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index 6e786201b..4d22cff88 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -26,7 +26,7 @@ struct cmIDEFlagTable; class cmGlobalVisualStudio7Generator : public cmGlobalVisualStudioGenerator { public: - cmGlobalVisualStudio7Generator(); + cmGlobalVisualStudio7Generator(const char* platformName = NULL); static cmGlobalGeneratorFactory* NewFactory() { return new cmGlobalGeneratorSimpleFactory <cmGlobalVisualStudio7Generator>(); } @@ -36,9 +36,14 @@ public: return cmGlobalVisualStudio7Generator::GetActualName();} static const char* GetActualName() {return "Visual Studio 7";} + ///! Get the name for the platform. + const char* GetPlatformName() const { return this->PlatformName.c_str(); } + ///! Create a local generator appropriate to this Global Generator virtual cmLocalGenerator *CreateLocalGenerator(); + virtual void AddPlatformDefinitions(cmMakefile* mf); + /** Get the documentation entry for this generator. */ static void GetDocumentation(cmDocumentationEntry& entry); @@ -55,6 +60,7 @@ public: */ virtual std::string GenerateBuildCommand(const char* makeProgram, const char *projectName, + const char *projectDir, const char* additionalOptions, const char *targetName, const char* config, @@ -152,6 +158,7 @@ protected: // Set during OutputSLNFile with the name of the current project. // There is one SLN file per project. std::string CurrentProject; + std::string PlatformName; }; #define CMAKE_CHECK_BUILD_SYSTEM_TARGET "ZERO_CHECK" diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index 864e8db02..e4244e062 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -57,8 +57,7 @@ public: } cmGlobalVisualStudio8Generator* ret = new cmGlobalVisualStudio8Generator( - name, parser.GetArchitectureFamily(), NULL); - ret->PlatformName = p; + name, p, NULL); ret->WindowsCEVersion = parser.GetOSVersion(); return ret; } @@ -96,16 +95,14 @@ cmGlobalGeneratorFactory* cmGlobalVisualStudio8Generator::NewFactory() //---------------------------------------------------------------------------- cmGlobalVisualStudio8Generator::cmGlobalVisualStudio8Generator( - const char* name, const char* architectureId, + const char* name, const char* platformName, const char* additionalPlatformDefinition) + : cmGlobalVisualStudio71Generator(platformName) { this->FindMakeProgramFile = "CMakeVS8FindMake.cmake"; this->ProjectConfigurationSectionName = "ProjectConfigurationPlatforms"; this->Name = name; - if (architectureId) - { - this->ArchitectureId = architectureId; - } + if (additionalPlatformDefinition) { this->AdditionalPlatformDefinition = additionalPlatformDefinition; @@ -113,20 +110,6 @@ cmGlobalVisualStudio8Generator::cmGlobalVisualStudio8Generator( } //---------------------------------------------------------------------------- -const char* cmGlobalVisualStudio8Generator::GetPlatformName() const -{ - if (!this->PlatformName.empty()) - { - return this->PlatformName.c_str(); - } - if (this->ArchitectureId == "X86") - { - return "Win32"; - } - return this->ArchitectureId.c_str(); -} - -//---------------------------------------------------------------------------- ///! Create a local generator appropriate to this Global Generator cmLocalGenerator *cmGlobalVisualStudio8Generator::CreateLocalGenerator() { @@ -142,7 +125,6 @@ cmLocalGenerator *cmGlobalVisualStudio8Generator::CreateLocalGenerator() void cmGlobalVisualStudio8Generator::AddPlatformDefinitions(cmMakefile* mf) { cmGlobalVisualStudio71Generator::AddPlatformDefinitions(mf); - mf->AddDefinition("CMAKE_VS_PLATFORM_NAME", this->GetPlatformName()); if(this->TargetsWindowsCE()) { diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h index bcbd7a0bd..d18174275 100644 --- a/Source/cmGlobalVisualStudio8Generator.h +++ b/Source/cmGlobalVisualStudio8Generator.h @@ -24,14 +24,12 @@ class cmGlobalVisualStudio8Generator : public cmGlobalVisualStudio71Generator { public: cmGlobalVisualStudio8Generator(const char* name, - const char* architectureId, const char* additionalPlatformDefinition); + const char* platformName, const char* additionalPlatformDefinition); static cmGlobalGeneratorFactory* NewFactory(); ///! Get the name for the generator. virtual const char* GetName() const {return this->Name.c_str();} - const char* GetPlatformName() const; - /** Get the documentation entry for this generator. */ static void GetDocumentation(cmDocumentationEntry& entry); @@ -87,7 +85,6 @@ protected: const char* path, cmTarget &t); std::string Name; - std::string PlatformName; std::string WindowsCEVersion; private: diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx index 2082384e6..fba6ed1ee 100644 --- a/Source/cmGlobalVisualStudio9Generator.cxx +++ b/Source/cmGlobalVisualStudio9Generator.cxx @@ -62,8 +62,7 @@ public: } cmGlobalVisualStudio9Generator* ret = new cmGlobalVisualStudio9Generator( - name, parser.GetArchitectureFamily(), NULL); - ret->PlatformName = p; + name, p, NULL); ret->WindowsCEVersion = parser.GetOSVersion(); return ret; } @@ -102,9 +101,9 @@ cmGlobalGeneratorFactory* cmGlobalVisualStudio9Generator::NewFactory() //---------------------------------------------------------------------------- cmGlobalVisualStudio9Generator::cmGlobalVisualStudio9Generator( - const char* name, const char* architectureId, + const char* name, const char* platformName, const char* additionalPlatformDefinition) - : cmGlobalVisualStudio8Generator(name, architectureId, + : cmGlobalVisualStudio8Generator(name, platformName, additionalPlatformDefinition) { this->FindMakeProgramFile = "CMakeVS9FindMake.cmake"; diff --git a/Source/cmGlobalVisualStudio9Generator.h b/Source/cmGlobalVisualStudio9Generator.h index 1310a93ac..202aa8d12 100644 --- a/Source/cmGlobalVisualStudio9Generator.h +++ b/Source/cmGlobalVisualStudio9Generator.h @@ -25,7 +25,7 @@ class cmGlobalVisualStudio9Generator : { public: cmGlobalVisualStudio9Generator(const char* name, - const char* architectureId, const char* additionalPlatformDefinition); + const char* platformName, const char* additionalPlatformDefinition); static cmGlobalGeneratorFactory* NewFactory(); ///! create the correct local generator diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 808664d44..59310162c 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -21,7 +21,6 @@ //---------------------------------------------------------------------------- cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator() { - this->ArchitectureId = "X86"; this->AdditionalPlatformDefinition = NULL; } @@ -449,7 +448,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) @@ -499,9 +498,6 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(cmTarget& target) //---------------------------------------------------------------------------- void cmGlobalVisualStudioGenerator::AddPlatformDefinitions(cmMakefile* mf) { - mf->AddDefinition("MSVC_C_ARCHITECTURE_ID", this->ArchitectureId.c_str()); - mf->AddDefinition("MSVC_CXX_ARCHITECTURE_ID", this->ArchitectureId.c_str()); - if(this->AdditionalPlatformDefinition) { mf->AddDefinition(this->AdditionalPlatformDefinition, "TRUE"); diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 9d811706b..b665158c6 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -104,7 +104,6 @@ protected: std::string GetUtilityDepend(cmTarget* target); typedef std::map<cmTarget*, cmStdString> UtilityDependsMap; UtilityDependsMap UtilityDepends; - std::string ArchitectureId; const char* AdditionalPlatformDefinition; private: diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 3092abf95..c181c5926 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)) @@ -429,13 +431,16 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root, // Add XCODE depend helper std::string dir = mf->GetCurrentOutputDirectory(); - cmCustomCommandLine makecommand; - makecommand.push_back("make"); - makecommand.push_back("-C"); - makecommand.push_back(dir.c_str()); - makecommand.push_back("-f"); - makecommand.push_back(this->CurrentXCodeHackMakefile.c_str()); - makecommand.push_back(""); // placeholder, see below + cmCustomCommandLine makeHelper; + if(this->XcodeVersion < 50) + { + makeHelper.push_back("make"); + makeHelper.push_back("-C"); + makeHelper.push_back(dir.c_str()); + makeHelper.push_back("-f"); + makeHelper.push_back(this->CurrentXCodeHackMakefile.c_str()); + makeHelper.push_back(""); // placeholder, see below + } // Add ZERO_CHECK bool regenerate = !mf->IsOn("CMAKE_SUPPRESS_REGENERATION"); @@ -475,17 +480,18 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root, // run the depend check makefile as a post build rule // this will make sure that when the next target is built // things are up-to-date - if((target.GetType() == cmTarget::EXECUTABLE || + if(!makeHelper.empty() && + (target.GetType() == cmTarget::EXECUTABLE || // Nope - no post-build for OBJECT_LIRBRARY // target.GetType() == cmTarget::OBJECT_LIBRARY || target.GetType() == cmTarget::STATIC_LIBRARY || target.GetType() == cmTarget::SHARED_LIBRARY || target.GetType() == cmTarget::MODULE_LIBRARY)) { - makecommand[makecommand.size()-1] = + makeHelper[makeHelper.size()-1] = // fill placeholder this->PostBuildMakeTarget(target.GetName(), "$(CONFIGURATION)"); cmCustomCommandLines commandLines; - commandLines.push_back(makecommand); + commandLines.push_back(makeHelper); lg->GetMakefile()->AddCustomCommandToTarget(target.GetName(), no_depends, commandLines, @@ -679,10 +685,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 +748,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 +835,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; @@ -881,8 +877,10 @@ cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( } std::string sourcecode = GetSourcecodeValueFromFileExtension(ext, lang); - - fileRef->AddAttribute("lastKnownFileType", + const char* attribute = (sourcecode == "file.storyboard") ? + "lastKnownFileType" : + "explicitFileType"; + fileRef->AddAttribute(attribute, this->CreateString(sourcecode.c_str())); // Store the file path relative to the top of the source tree. @@ -1003,7 +1001,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); @@ -1035,18 +1033,21 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, } } - // Add object library contents as external objects. (Equivalent to - // the externalObjFiles above, except each one is not a cmSourceFile - // within the target.) - std::vector<std::string> objs; - this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs); - for(std::vector<std::string>::const_iterator - oi = objs.begin(); oi != objs.end(); ++oi) + if(this->XcodeVersion < 50) { - std::string obj = *oi; - cmXCodeObject* xsf = - this->CreateXCodeSourceFileFromPath(obj, cmtarget, ""); - externalObjFiles.push_back(xsf); + // Add object library contents as external objects. (Equivalent to + // the externalObjFiles above, except each one is not a cmSourceFile + // within the target.) + std::vector<std::string> objs; + this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs); + for(std::vector<std::string>::const_iterator + oi = objs.begin(); oi != objs.end(); ++oi) + { + std::string obj = *oi; + cmXCodeObject* xsf = + this->CreateXCodeSourceFileFromPath(obj, cmtarget, ""); + externalObjFiles.push_back(xsf); + } } // some build phases only apply to bundles and/or frameworks @@ -1319,8 +1320,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 +1707,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 +1717,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; } @@ -1709,58 +1750,59 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, this->AppendDefines(ppDefs, exportMacro); } cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target); - this->AppendDefines(ppDefs, - target.GetCompileDefinitions(configName).c_str()); + std::vector<std::string> targetDefines; + target.GetCompileDefinitions(targetDefines, configName); + this->AppendDefines(ppDefs, targetDefines); 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) + { + extraLinkOptionsVar = "CMAKE_SHARED_LINKER_FLAGS"; + } + else if(target.GetType() == cmTarget::MODULE_LIBRARY) { - extraLinkOptions = this->CurrentMakefile-> - GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS"); + extraLinkOptionsVar = "CMAKE_MODULE_LINKER_FLAGS"; } - if(target.GetType() == cmTarget::MODULE_LIBRARY) + if(extraLinkOptionsVar.size()) { - extraLinkOptions = this->CurrentMakefile-> - GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS"); + this->CurrentLocalGenerator + ->AddConfigVariableFlags(extraLinkOptions, + extraLinkOptionsVar.c_str(), + configName); } - const char* linkFlagsProp = "LINK_FLAGS"; if(target.GetType() == cmTarget::OBJECT_LIBRARY || target.GetType() == cmTarget::STATIC_LIBRARY) { - linkFlagsProp = "STATIC_LIBRARY_FLAGS"; + this->CurrentLocalGenerator + ->GetStaticLibraryFlags(extraLinkOptions, + cmSystemTools::UpperCase(configName), + &target); } - const char* targetLinkFlags = target.GetProperty(linkFlagsProp); - if(targetLinkFlags) - { - extraLinkOptions += " "; - extraLinkOptions += targetLinkFlags; - } - if(configName && *configName) + else { - std::string linkFlagsVar = linkFlagsProp; - linkFlagsVar += "_"; - linkFlagsVar += cmSystemTools::UpperCase(configName); - if(const char* linkFlags = target.GetProperty(linkFlagsVar.c_str())) + const char* targetLinkFlags = target.GetProperty("LINK_FLAGS"); + if(targetLinkFlags) { - extraLinkOptions += " "; - extraLinkOptions += linkFlags; + this->CurrentLocalGenerator-> + AppendFlags(extraLinkOptions, targetLinkFlags); + } + if(configName && *configName) + { + std::string linkFlagsVar = "LINK_FLAGS_"; + linkFlagsVar += cmSystemTools::UpperCase(configName); + if(const char* linkFlags = target.GetProperty(linkFlagsVar.c_str())) + { + this->CurrentLocalGenerator-> + AppendFlags(extraLinkOptions, linkFlags); + } } } @@ -1797,9 +1839,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 +1890,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 +1924,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 +2002,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, @@ -2152,25 +2224,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", @@ -2235,8 +2337,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())); + } } } } @@ -2641,13 +2774,6 @@ void cmGlobalXCodeGenerator } } - // Skip link information for static libraries. - if(cmtarget->GetType() == cmTarget::OBJECT_LIBRARY || - cmtarget->GetType() == cmTarget::STATIC_LIBRARY) - { - return; - } - // Loop over configuration types and set per-configuration info. for(std::vector<std::string>::iterator i = this->CurrentConfigurationTypes.begin(); @@ -2660,6 +2786,31 @@ void cmGlobalXCodeGenerator configName = 0; } + if(this->XcodeVersion >= 50) + { + // Add object library contents as link flags. + std::string linkObjs; + const char* sep = ""; + std::vector<std::string> objs; + this->GetGeneratorTarget(cmtarget)->UseObjectLibraries(objs); + for(std::vector<std::string>::const_iterator + oi = objs.begin(); oi != objs.end(); ++oi) + { + linkObjs += sep; + sep = " "; + linkObjs += this->XCodeEscapePath(oi->c_str()); + } + this->AppendBuildSettingAttribute(target, "OTHER_LDFLAGS", + linkObjs.c_str(), configName); + } + + // Skip link information for object libraries. + if(cmtarget->GetType() == cmTarget::OBJECT_LIBRARY || + cmtarget->GetType() == cmTarget::STATIC_LIBRARY) + { + continue; + } + // Compute the link library and directory information. cmComputeLinkInformation* pcli = cmtarget->GetLinkInformation(configName); if(!pcli) @@ -3214,8 +3365,11 @@ void cmGlobalXCodeGenerator cmXCodeObject* t = *i; this->AddDependAndLinkInformation(t); } - // now create xcode depend hack makefile - this->CreateXCodeDependHackTarget(targets); + if(this->XcodeVersion < 50) + { + // now create xcode depend hack makefile + this->CreateXCodeDependHackTarget(targets); + } // now add all targets to the root object cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST); for(std::vector<cmXCodeObject*>::iterator i = targets.begin(); diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 131a6e6d5..c05394346 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/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx index 76a60cfcd..34a9c7c78 100644 --- a/Source/cmIDEOptions.cxx +++ b/Source/cmIDEOptions.cxx @@ -165,6 +165,11 @@ void cmIDEOptions::AddDefines(const char* defines) cmSystemTools::ExpandListArgument(defines, this->Defines); } } +//---------------------------------------------------------------------------- +void cmIDEOptions::AddDefines(const std::vector<std::string> &defines) +{ + this->Defines.insert(this->Defines.end(), defines.begin(), defines.end()); +} //---------------------------------------------------------------------------- void cmIDEOptions::AddFlag(const char* flag, const char* value) diff --git a/Source/cmIDEOptions.h b/Source/cmIDEOptions.h index e556bdeca..e78af3ee4 100644 --- a/Source/cmIDEOptions.h +++ b/Source/cmIDEOptions.h @@ -27,6 +27,7 @@ public: // Store definitions and flags. void AddDefine(const std::string& define); void AddDefines(const char* defines); + void AddDefines(const std::vector<std::string> &defines); void AddFlag(const char* flag, const char* value); void RemoveFlag(const char* flag); const char* GetFlag(const char* flag); diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 56d717031..57cec5bbb 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 0d5f67b78..bb891d6fc 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/cmIncludeCommand.h b/Source/cmIncludeCommand.h index c46c02d71..d97b7c3f5 100644 --- a/Source/cmIncludeCommand.h +++ b/Source/cmIncludeCommand.h @@ -55,7 +55,7 @@ public: */ virtual const char* GetTerseDocumentation() const { - return "Read CMake listfile code from the given file."; + return "Load and run CMake code from a file or module."; } /** @@ -66,9 +66,10 @@ public: return " include(<file|module> [OPTIONAL] [RESULT_VARIABLE <VAR>]\n" " [NO_POLICY_SCOPE])\n" - "Reads CMake listfile code from the given file. Commands in the file " - "are processed immediately as if they were written in place of the " - "include command. If OPTIONAL is present, then no error " + "Load and run CMake code from the file given. " + "Variable reads and writes access the scope of the caller " + "(dynamic scoping). " + "If OPTIONAL is present, then no error " "is raised if the file does not exist. If RESULT_VARIABLE is given " "the variable will be set to the full filename which " "has been included or NOTFOUND if it failed.\n" diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index dcd418b45..3c76bd638 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -219,6 +219,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) cmCAStringVector runtimeArgVector (&argHelper,"RUNTIME",&group); cmCAStringVector frameworkArgVector (&argHelper,"FRAMEWORK",&group); cmCAStringVector bundleArgVector (&argHelper,"BUNDLE",&group); + cmCAStringVector includesArgVector (&argHelper,"INCLUDES",&group); cmCAStringVector privateHeaderArgVector(&argHelper,"PRIVATE_HEADER",&group); cmCAStringVector publicHeaderArgVector (&argHelper,"PUBLIC_HEADER",&group); cmCAStringVector resourceArgVector (&argHelper,"RESOURCE",&group); @@ -247,6 +248,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) cmInstallCommandArguments privateHeaderArgs(this->DefaultComponentName); cmInstallCommandArguments publicHeaderArgs(this->DefaultComponentName); cmInstallCommandArguments resourceArgs(this->DefaultComponentName); + cmInstallCommandIncludesArgument includesArgs; // now parse the args for specific parts of the target (e.g. LIBRARY, // RUNTIME, ARCHIVE etc. @@ -258,6 +260,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs); publicHeaderArgs.Parse (&publicHeaderArgVector.GetVector(), &unknownArgs); resourceArgs.Parse (&resourceArgVector.GetVector(), &unknownArgs); + includesArgs.Parse (&includesArgVector.GetVector(), &unknownArgs); if(!unknownArgs.empty()) { @@ -359,6 +362,15 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) targetIt!=targetList.GetVector().end(); ++targetIt) { + + if (this->Makefile->IsAlias(targetIt->c_str())) + { + cmOStringStream e; + e << "TARGETS given target \"" << (*targetIt) + << "\" which is an alias."; + this->SetError(e.str().c_str()); + return false; + } // Lookup this target in the current directory. if(cmTarget* target=this->Makefile->FindTarget(targetIt->c_str())) { @@ -747,6 +759,20 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) te->RuntimeGenerator = runtimeGenerator; this->Makefile->GetLocalGenerator()->GetGlobalGenerator() ->GetExportSets()[exports.GetString()]->AddTargetExport(te); + + std::vector<std::string> dirs = includesArgs.GetIncludeDirs(); + if(!dirs.empty()) + { + std::string dirString; + const char *sep = ""; + for (std::vector<std::string>::const_iterator it = dirs.begin(); + it != dirs.end(); ++it) + { + te->InterfaceIncludeDirectories += sep; + te->InterfaceIncludeDirectories += *it; + sep = ";"; + } + } } } @@ -1196,6 +1222,8 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args) cmInstallCommandArguments ica(this->DefaultComponentName); cmCAString exp(&ica.Parser, "EXPORT"); cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup); + cmCAEnabler exportOld(&ica.Parser, "EXPORT_LINK_INTERFACE_LIBRARIES", + &ica.ArgumentGroup); cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup); exp.Follows(0); @@ -1268,15 +1296,40 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args) } } + cmExportSet *exportSet = this->Makefile->GetLocalGenerator() + ->GetGlobalGenerator()->GetExportSets()[exp.GetString()]; + if (exportOld.IsEnabled()) + { + for(std::vector<cmTargetExport*>::const_iterator + tei = exportSet->GetTargetExports()->begin(); + tei != exportSet->GetTargetExports()->end(); ++tei) + { + cmTargetExport const* te = *tei; + const bool newCMP0022Behavior = + te->Target->GetPolicyStatusCMP0022() != cmPolicies::WARN + && te->Target->GetPolicyStatusCMP0022() != cmPolicies::OLD; + + if(!newCMP0022Behavior) + { + cmOStringStream e; + e << "INSTALL(EXPORT) given keyword \"" + << "EXPORT_LINK_INTERFACE_LIBRARIES" << "\", but target \"" + << te->Target->GetName() + << "\" does not have policy CMP0022 set to NEW."; + this->SetError(e.str().c_str()); + return false; + } + } + } + // Create the export install generator. cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator( - this->Makefile->GetLocalGenerator() - ->GetGlobalGenerator()->GetExportSets()[exp.GetString()], + exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(), ica.GetConfigurations(), ica.GetComponent().c_str(), fname.c_str(), - name_space.GetCString(), this->Makefile); + name_space.GetCString(), exportOld.IsEnabled(), this->Makefile); this->Makefile->AddInstallGenerator(exportGenerator); return true; diff --git a/Source/cmInstallCommand.h b/Source/cmInstallCommand.h index 7c060090d..65095011f 100644 --- a/Source/cmInstallCommand.h +++ b/Source/cmInstallCommand.h @@ -102,6 +102,7 @@ public: " [[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|\n" " PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]\n" " [DESTINATION <dir>]\n" + " [INCLUDES DESTINATION [<dir> ...]]\n" " [PERMISSIONS permissions...]\n" " [CONFIGURATIONS [Debug|Release|...]]\n" " [COMPONENT <component>]\n" @@ -130,6 +131,10 @@ public: "all target types. If only one is given then only targets of that " "type will be installed (which can be used to install just a DLL or " "just an import library)." + "The INCLUDES DESTINATION specifies a list of directories which will " + "be added to the INTERFACE_INCLUDE_DIRECTORIES of the <targets> when " + "exported by install(EXPORT). If a relative path is specified, it is " + "treated as relative to the $<INSTALL_PREFIX>." "\n" "The PRIVATE_HEADER, PUBLIC_HEADER, and RESOURCE arguments cause " "subsequent properties to be applied to installing a FRAMEWORK " @@ -291,6 +296,7 @@ public: " [NAMESPACE <namespace>] [FILE <name>.cmake]\n" " [PERMISSIONS permissions...]\n" " [CONFIGURATIONS [Debug|Release|...]]\n" + " [EXPORT_LINK_INTERFACE_LIBRARIES]\n" " [COMPONENT <component>])\n" "The EXPORT form generates and installs a CMake file containing code " "to import targets from the installation tree into another project. " @@ -306,6 +312,10 @@ public: "installed when one of the named configurations is installed. " "Additionally, the generated import file will reference only the " "matching target configurations. " + "The EXPORT_LINK_INTERFACE_LIBRARIES keyword, if present, causes the " + "contents of the properties matching " + "(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)? to be exported, when " + "policy CMP0022 is NEW. " "If a COMPONENT option is specified that does not match that given " "to the targets associated with <export-name> the behavior is " "undefined. " diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx index 8e48f08e6..91ea861a4 100644 --- a/Source/cmInstallCommandArguments.cxx +++ b/Source/cmInstallCommandArguments.cxx @@ -203,3 +203,37 @@ bool cmInstallCommandArguments::CheckPermissions( // This is not a valid permission. return false; } + +cmInstallCommandIncludesArgument::cmInstallCommandIncludesArgument() +{ + +} + +const std::vector<std::string>& +cmInstallCommandIncludesArgument::GetIncludeDirs() const +{ + return this->IncludeDirs; +} + +void cmInstallCommandIncludesArgument::Parse( + const std::vector<std::string>* args, + std::vector<std::string>*) +{ + if(args->empty()) + { + return; + } + std::vector<std::string>::const_iterator it = args->begin(); + ++it; + for ( ; it != args->end(); ++it) + { + std::string dir = *it; + if (!cmSystemTools::FileIsFullPath(it->c_str()) + && cmGeneratorExpression::Find(*it) == std::string::npos) + { + dir = "$<INSTALL_PREFIX>/" + dir; + } + cmSystemTools::ConvertToUnixSlashes(dir); + this->IncludeDirs.push_back(dir); + } +} diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h index 01f7d5679..90347e668 100644 --- a/Source/cmInstallCommandArguments.h +++ b/Source/cmInstallCommandArguments.h @@ -65,4 +65,17 @@ class cmInstallCommandArguments bool CheckPermissions(); }; +class cmInstallCommandIncludesArgument +{ + public: + cmInstallCommandIncludesArgument(); + void Parse(const std::vector<std::string>* args, + std::vector<std::string>* unconsumedArgs); + + const std::vector<std::string>& GetIncludeDirs() const; + + private: + std::vector<std::string> IncludeDirs; +}; + #endif diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 0a645a8fa..3e9e6ac02 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -33,12 +33,14 @@ cmInstallExportGenerator::cmInstallExportGenerator( std::vector<std::string> const& configurations, const char* component, const char* filename, const char* name_space, + bool exportOld, cmMakefile* mf) :cmInstallGenerator(destination, configurations, component) ,ExportSet(exportSet) ,FilePermissions(file_permissions) ,FileName(filename) ,Namespace(name_space) + ,ExportOld(exportOld) ,Makefile(mf) { this->EFGen = new cmExportInstallFileGenerator(this); @@ -137,6 +139,7 @@ void cmInstallExportGenerator::GenerateScript(std::ostream& os) // Generate the import file for this export set. this->EFGen->SetExportFile(this->MainImportFile.c_str()); this->EFGen->SetNamespace(this->Namespace.c_str()); + this->EFGen->SetExportOld(this->ExportOld); if(this->ConfigurationTypes->empty()) { if(this->ConfigurationName && *this->ConfigurationName) diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h index 7aff7314c..37b55932f 100644 --- a/Source/cmInstallExportGenerator.h +++ b/Source/cmInstallExportGenerator.h @@ -31,7 +31,7 @@ public: const std::vector<std::string>& configurations, const char* component, const char* filename, const char* name_space, - cmMakefile* mf); + bool exportOld, cmMakefile* mf); ~cmInstallExportGenerator(); cmExportSet* GetExportSet() {return this->ExportSet;} @@ -52,6 +52,7 @@ protected: std::string FilePermissions; std::string FileName; std::string Namespace; + bool ExportOld; cmMakefile* Makefile; std::string TempDir; diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 5f9b6585e..c9624c8e0 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"; + } } } @@ -681,9 +717,9 @@ cmInstallTargetGenerator::AddStripRule(std::ostream& os, const std::string& toDestDirPath) { - // don't strip static libraries, because it removes the only symbol table - // they have so you can't link to them anymore - if(this->Target->GetType() == cmTarget::STATIC_LIBRARY) + // don't strip static and import libraries, because it removes the only + // symbol table they have so you can't link to them anymore + if(this->Target->GetType()==cmTarget::STATIC_LIBRARY || this->ImportLibrary) { return; } diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 36d84f3be..898f379ad 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -22,45 +22,58 @@ # pragma warn -8060 /* possibly incorrect assignment */ #endif -bool cmListFileCacheParseFunction(cmListFileLexer* lexer, - cmListFileFunction& function, - const char* filename); +//---------------------------------------------------------------------------- +struct cmListFileParser +{ + cmListFileParser(cmListFile* lf, cmMakefile* mf, const char* filename); + ~cmListFileParser(); + bool ParseFile(); + bool ParseFunction(const char* name, long line); + void AddArgument(cmListFileLexer_Token* token, + cmListFileArgument::Delimiter delim); + cmListFile* ListFile; + cmMakefile* Makefile; + const char* FileName; + cmListFileLexer* Lexer; + cmListFileFunction Function; + enum { SeparationOkay, SeparationWarning } Separation; +}; -bool cmListFile::ParseFile(const char* filename, - bool topLevel, - cmMakefile *mf) +//---------------------------------------------------------------------------- +cmListFileParser::cmListFileParser(cmListFile* lf, cmMakefile* mf, + const char* filename): + ListFile(lf), Makefile(mf), FileName(filename), + Lexer(cmListFileLexer_New()) { - if(!cmSystemTools::FileExists(filename)) - { - return false; - } +} - // Create the scanner. - cmListFileLexer* lexer = cmListFileLexer_New(); - if(!lexer) - { - cmSystemTools::Error("cmListFileCache: error allocating lexer "); - return false; - } +//---------------------------------------------------------------------------- +cmListFileParser::~cmListFileParser() +{ + cmListFileLexer_Delete(this->Lexer); +} +//---------------------------------------------------------------------------- +bool cmListFileParser::ParseFile() +{ // Open the file. - if(!cmListFileLexer_SetFileName(lexer, filename)) + if(!cmListFileLexer_SetFileName(this->Lexer, this->FileName)) { - cmListFileLexer_Delete(lexer); cmSystemTools::Error("cmListFileCache: error can not open file ", - filename); + this->FileName); return false; } // Use a simple recursive-descent parser to process the token // stream. - this->ModifiedTime = cmSystemTools::ModifiedTime(filename); - bool parseError = false; bool haveNewline = true; - cmListFileLexer_Token* token; - while(!parseError && (token = cmListFileLexer_Scan(lexer))) + while(cmListFileLexer_Token* token = + cmListFileLexer_Scan(this->Lexer)) { - if(token->type == cmListFileLexer_Token_Newline) + if(token->type == cmListFileLexer_Token_Space) + { + } + else if(token->type == cmListFileLexer_Token_Newline) { haveNewline = true; } @@ -69,51 +82,66 @@ bool cmListFile::ParseFile(const char* filename, if(haveNewline) { haveNewline = false; - cmListFileFunction inFunction; - inFunction.Name = token->text; - inFunction.FilePath = filename; - inFunction.Line = token->line; - if(cmListFileCacheParseFunction(lexer, inFunction, filename)) + if(this->ParseFunction(token->text, token->line)) { - this->Functions.push_back(inFunction); + this->ListFile->Functions.push_back(this->Function); } else { - parseError = true; + return false; } } else { cmOStringStream error; error << "Error in cmake code at\n" - << filename << ":" << token->line << ":\n" + << this->FileName << ":" << token->line << ":\n" << "Parse error. Expected a newline, got " - << cmListFileLexer_GetTypeAsString(lexer, token->type) + << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; cmSystemTools::Error(error.str().c_str()); - parseError = true; + return false; } } else { cmOStringStream error; error << "Error in cmake code at\n" - << filename << ":" << token->line << ":\n" + << this->FileName << ":" << token->line << ":\n" << "Parse error. Expected a command name, got " - << cmListFileLexer_GetTypeAsString(lexer, token->type) + << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; cmSystemTools::Error(error.str().c_str()); - parseError = true; + return false; } } - if (parseError) + return true; +} + +//---------------------------------------------------------------------------- +bool cmListFile::ParseFile(const char* filename, + bool topLevel, + cmMakefile *mf) +{ + if(!cmSystemTools::FileExists(filename)) + { + return false; + } + + bool parseError = false; + this->ModifiedTime = cmSystemTools::ModifiedTime(filename); + + { + cmListFileParser parser(this, mf, filename); + parseError = !parser.ParseFile(); + } + + if(parseError) { this->ModifiedTime = 0; } - cmListFileLexer_Delete(lexer); - // do we need a cmake_policy(VERSION call? if(topLevel) { @@ -196,7 +224,8 @@ bool cmListFile::ParseFile(const char* filename, { cmListFileFunction project; project.Name = "PROJECT"; - cmListFileArgument prj("Project", false, filename, 0); + cmListFileArgument prj("Project", cmListFileArgument::Unquoted, + filename, 0); project.Arguments.push_back(prj); this->Functions.insert(this->Functions.begin(),project); } @@ -208,17 +237,24 @@ bool cmListFile::ParseFile(const char* filename, return true; } -bool cmListFileCacheParseFunction(cmListFileLexer* lexer, - cmListFileFunction& function, - const char* filename) +//---------------------------------------------------------------------------- +bool cmListFileParser::ParseFunction(const char* name, long line) { + // Inintialize a new function call. + this->Function = cmListFileFunction(); + this->Function.FilePath = this->FileName; + this->Function.Name = name; + this->Function.Line = line; + // Command name has already been parsed. Read the left paren. cmListFileLexer_Token* token; - if(!(token = cmListFileLexer_Scan(lexer))) + while((token = cmListFileLexer_Scan(this->Lexer)) && + token->type == cmListFileLexer_Token_Space) {} + if(!token) { cmOStringStream error; - error << "Error in cmake code at\n" - << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n" + error << "Error in cmake code at\n" << this->FileName << ":" + << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n" << "Parse error. Function missing opening \"(\"."; cmSystemTools::Error(error.str().c_str()); return false; @@ -226,26 +262,33 @@ bool cmListFileCacheParseFunction(cmListFileLexer* lexer, if(token->type != cmListFileLexer_Token_ParenLeft) { cmOStringStream error; - error << "Error in cmake code at\n" - << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n" + error << "Error in cmake code at\n" << this->FileName << ":" + << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n" << "Parse error. Expected \"(\", got " - << cmListFileLexer_GetTypeAsString(lexer, token->type) + << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; cmSystemTools::Error(error.str().c_str()); return false; } // Arguments. - unsigned long lastLine = cmListFileLexer_GetCurrentLine(lexer); + unsigned long lastLine; unsigned long parenDepth = 0; - while((token = cmListFileLexer_Scan(lexer))) + this->Separation = SeparationOkay; + while((lastLine = cmListFileLexer_GetCurrentLine(this->Lexer), + token = cmListFileLexer_Scan(this->Lexer))) { + if(token->type == cmListFileLexer_Token_Space || + token->type == cmListFileLexer_Token_Newline) + { + this->Separation = SeparationOkay; + continue; + } if(token->type == cmListFileLexer_Token_ParenLeft) { parenDepth++; - cmListFileArgument a("(", - false, filename, token->line); - function.Arguments.push_back(a); + this->Separation = SeparationOkay; + this->AddArgument(token, cmListFileArgument::Unquoted); } else if(token->type == cmListFileLexer_Token_ParenRight) { @@ -254,43 +297,39 @@ bool cmListFileCacheParseFunction(cmListFileLexer* lexer, return true; } parenDepth--; - cmListFileArgument a(")", - false, filename, token->line); - function.Arguments.push_back(a); + this->Separation = SeparationOkay; + this->AddArgument(token, cmListFileArgument::Unquoted); + this->Separation = SeparationWarning; } else if(token->type == cmListFileLexer_Token_Identifier || token->type == cmListFileLexer_Token_ArgumentUnquoted) { - cmListFileArgument a(token->text, - false, filename, token->line); - function.Arguments.push_back(a); + this->AddArgument(token, cmListFileArgument::Unquoted); + this->Separation = SeparationWarning; } else if(token->type == cmListFileLexer_Token_ArgumentQuoted) { - cmListFileArgument a(token->text, - true, filename, token->line); - function.Arguments.push_back(a); + this->AddArgument(token, cmListFileArgument::Quoted); + this->Separation = SeparationWarning; } - else if(token->type != cmListFileLexer_Token_Newline) + else { // Error. cmOStringStream error; - error << "Error in cmake code at\n" - << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) - << ":\n" + error << "Error in cmake code at\n" << this->FileName << ":" + << cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n" << "Parse error. Function missing ending \")\". " << "Instead found " - << cmListFileLexer_GetTypeAsString(lexer, token->type) + << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) << " with text \"" << token->text << "\"."; cmSystemTools::Error(error.str().c_str()); return false; } - lastLine = cmListFileLexer_GetCurrentLine(lexer); } cmOStringStream error; error << "Error in cmake code at\n" - << filename << ":" << lastLine << ":\n" + << this->FileName << ":" << lastLine << ":\n" << "Parse error. Function missing ending \")\". " << "End of file reached."; cmSystemTools::Error(error.str().c_str()); @@ -299,6 +338,45 @@ bool cmListFileCacheParseFunction(cmListFileLexer* lexer, } //---------------------------------------------------------------------------- +void cmListFileParser::AddArgument(cmListFileLexer_Token* token, + cmListFileArgument::Delimiter delim) +{ + cmListFileArgument a(token->text, delim, this->FileName, token->line); + this->Function.Arguments.push_back(a); + if(delim == cmListFileArgument::Unquoted) + { + // Warn about a future behavior change. + const char* c = a.Value.c_str(); + if(*c++ == '[') + { + while(*c == '=') + { ++c; } + if(*c == '[') + { + cmOStringStream m; + m << "Syntax Warning in cmake code at\n" + << " " << this->FileName << ":" << token->line << ":" + << token->column << "\n" + << "A future version of CMake may treat unquoted argument:\n" + << " " << a.Value << "\n" + << "as an opening long bracket. Double-quote the argument."; + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str().c_str()); + } + } + } + if(this->Separation == SeparationOkay) + { + return; + } + cmOStringStream m; + m << "Syntax Warning in cmake code at\n" + << " " << this->FileName << ":" << token->line << ":" + << token->column << "\n" + << "Argument not separated from preceding token by whitespace."; + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str().c_str()); +} + +//---------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc) { os << lfc.FilePath; diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index fec3d07d8..7bb3b346c 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -25,22 +25,27 @@ class cmMakefile; struct cmListFileArgument { - cmListFileArgument(): Value(), Quoted(false), FilePath(0), Line(0) {} + enum Delimiter + { + Unquoted, + Quoted + }; + cmListFileArgument(): Value(), Delim(Unquoted), FilePath(0), Line(0) {} cmListFileArgument(const cmListFileArgument& r): - Value(r.Value), Quoted(r.Quoted), FilePath(r.FilePath), Line(r.Line) {} - cmListFileArgument(const std::string& v, bool q, const char* file, - long line): Value(v), Quoted(q), + Value(r.Value), Delim(r.Delim), FilePath(r.FilePath), Line(r.Line) {} + cmListFileArgument(const std::string& v, Delimiter d, const char* file, + long line): Value(v), Delim(d), FilePath(file), Line(line) {} bool operator == (const cmListFileArgument& r) const { - return (this->Value == r.Value) && (this->Quoted == r.Quoted); + return (this->Value == r.Value) && (this->Delim == r.Delim); } bool operator != (const cmListFileArgument& r) const { return !(*this == r); } std::string Value; - bool Quoted; + Delimiter Delim; const char* FilePath; long Line; }; diff --git a/Source/cmListFileLexer.c b/Source/cmListFileLexer.c index b6424d60e..2841fe511 100644 --- a/Source/cmListFileLexer.c +++ b/Source/cmListFileLexer.c @@ -9,7 +9,7 @@ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 31 +#define YY_FLEX_SUBMINOR_VERSION 35 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif @@ -31,7 +31,15 @@ /* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ -#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + #include <inttypes.h> typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; @@ -46,7 +54,6 @@ typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; -#endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN @@ -77,6 +84,8 @@ typedef unsigned int flex_uint32_t; #define UINT32_MAX (4294967295U) #endif +#endif /* ! C99 */ + #endif /* ! FLEXINT_H */ #ifdef __cplusplus @@ -86,11 +95,12 @@ typedef unsigned int flex_uint32_t; #else /* ! __cplusplus */ -#if __STDC__ +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) #define YY_USE_CONST -#endif /* __STDC__ */ +#endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST @@ -126,8 +136,6 @@ typedef void* yyscan_t; #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r -int cmListFileLexer_yylex_init (yyscan_t* scanner); - /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. @@ -151,9 +159,21 @@ int cmListFileLexer_yylex_init (yyscan_t* scanner); /* Size of default input buffer. */ #ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else #define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ #endif +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; @@ -192,14 +212,9 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE; } \ while ( 0 ) -/* The following is because we cannot portably get our hands on size_t - * (without autoconf's help, which isn't available because we want - * flex-generated scanners to compile on their own). - */ - #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T -typedef unsigned int yy_size_t; +typedef size_t yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE @@ -354,8 +369,8 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 14 -#define YY_END_OF_BUFFER 15 +#define YY_NUM_RULES 16 +#define YY_END_OF_BUFFER 17 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -363,12 +378,13 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[39] = +static yyconst flex_int16_t yy_accept[45] = { 0, - 0, 0, 0, 0, 15, 6, 12, 1, 7, 2, - 6, 3, 4, 6, 13, 8, 9, 10, 11, 6, - 0, 6, 0, 2, 0, 5, 6, 8, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 17, 6, 14, 1, 8, 2, + 6, 3, 4, 6, 15, 9, 11, 12, 13, 6, + 0, 6, 0, 14, 2, 0, 5, 6, 9, 0, + 10, 0, 7, 0, 0, 0, 7, 0, 7, 0, + 0, 0, 0, 0 } ; static yyconst flex_int32_t yy_ec[256] = @@ -405,64 +421,70 @@ static yyconst flex_int32_t yy_ec[256] = static yyconst flex_int32_t yy_meta[13] = { 0, - 1, 1, 2, 1, 3, 1, 1, 1, 4, 4, - 4, 1 + 1, 2, 3, 2, 4, 1, 1, 1, 5, 5, + 5, 1 } ; -static yyconst flex_int16_t yy_base[48] = +static yyconst flex_int16_t yy_base[56] = { 0, - 0, 0, 10, 20, 34, 32, 89, 89, 89, 0, - 23, 89, 89, 35, 0, 18, 89, 89, 44, 0, - 49, 21, 0, 0, 19, 0, 0, 15, 59, 0, - 18, 0, 15, 12, 11, 10, 9, 89, 64, 68, - 72, 76, 80, 13, 84, 12, 10 + 0, 0, 10, 20, 38, 32, 0, 109, 109, 0, + 28, 109, 109, 35, 0, 23, 109, 109, 44, 0, + 49, 26, 0, 0, 0, 22, 0, 0, 18, 24, + 109, 0, 61, 20, 0, 18, 0, 17, 16, 0, + 12, 11, 10, 109, 73, 16, 78, 83, 88, 93, + 12, 98, 11, 103, 9 } ; -static yyconst flex_int16_t yy_def[48] = +static yyconst flex_int16_t yy_def[56] = { 0, - 38, 1, 39, 39, 38, 38, 38, 38, 38, 40, - 6, 38, 38, 6, 41, 42, 38, 38, 42, 6, - 38, 6, 43, 40, 44, 14, 6, 42, 42, 21, - 21, 45, 46, 44, 47, 46, 47, 0, 38, 38, - 38, 38, 38, 38, 38, 38, 38 + 44, 1, 45, 45, 44, 44, 46, 44, 44, 47, + 6, 44, 44, 6, 48, 49, 44, 44, 49, 6, + 44, 6, 50, 46, 47, 51, 14, 6, 49, 49, + 44, 21, 44, 21, 52, 53, 33, 51, 33, 54, + 55, 53, 55, 0, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44 } ; -static yyconst flex_int16_t yy_nxt[102] = +static yyconst flex_int16_t yy_nxt[122] = { 0, 6, 7, 8, 7, 9, 10, 11, 12, 13, 6, - 14, 15, 17, 37, 18, 36, 34, 30, 20, 30, - 27, 19, 17, 20, 18, 35, 29, 27, 33, 29, - 25, 19, 20, 38, 38, 38, 21, 38, 22, 38, - 38, 20, 20, 23, 26, 26, 28, 38, 28, 30, - 30, 38, 38, 20, 38, 31, 38, 38, 30, 30, - 32, 28, 38, 28, 16, 16, 16, 16, 24, 38, - 24, 24, 27, 38, 27, 27, 28, 38, 38, 28, - 20, 38, 20, 20, 30, 38, 30, 30, 5, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - - 38 + 14, 15, 17, 43, 18, 42, 38, 24, 32, 33, + 32, 19, 17, 36, 18, 37, 33, 41, 29, 30, + 37, 19, 20, 36, 30, 26, 21, 44, 22, 44, + 44, 20, 20, 23, 27, 27, 31, 44, 29, 32, + 32, 44, 44, 33, 44, 34, 44, 44, 32, 32, + 35, 33, 44, 44, 44, 21, 44, 39, 44, 44, + 33, 33, 40, 16, 16, 16, 16, 16, 25, 25, + 44, 25, 25, 28, 28, 44, 28, 28, 29, 29, + 44, 44, 29, 20, 20, 44, 20, 20, 32, 32, + + 44, 32, 32, 33, 33, 44, 33, 33, 5, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44 } ; -static yyconst flex_int16_t yy_chk[102] = +static yyconst flex_int16_t yy_chk[122] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 3, 47, 3, 46, 44, 37, 36, 35, - 34, 3, 4, 33, 4, 31, 28, 25, 22, 16, - 11, 4, 6, 5, 0, 0, 6, 0, 6, 0, + 1, 1, 3, 55, 3, 53, 51, 46, 43, 42, + 41, 3, 4, 39, 4, 38, 36, 34, 30, 29, + 26, 4, 6, 22, 16, 11, 6, 5, 6, 0, 0, 6, 6, 6, 14, 14, 19, 0, 19, 21, 21, 0, 0, 21, 0, 21, 0, 0, 21, 21, - 21, 29, 0, 29, 39, 39, 39, 39, 40, 0, - 40, 40, 41, 0, 41, 41, 42, 0, 0, 42, - 43, 0, 43, 43, 45, 0, 45, 45, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - - 38 + 21, 33, 0, 0, 0, 33, 0, 33, 0, 0, + 33, 33, 33, 45, 45, 45, 45, 45, 47, 47, + 0, 47, 47, 48, 48, 0, 48, 48, 49, 49, + 0, 0, 49, 50, 50, 0, 50, 50, 52, 52, + + 0, 52, 52, 54, 54, 0, 54, 54, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44 } ; /* Table of booleans, true if rule could match eol. */ -static yyconst flex_int32_t yy_rule_can_match_eol[15] = +static yyconst flex_int32_t yy_rule_can_match_eol[17] = { 0, -1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, }; +1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, }; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. @@ -494,9 +516,11 @@ Run flex like this: Modify cmListFileLexer.c: - remove TABs + - remove use of the 'register' storage class specifier - remove the yyunput function - add a statement "(void)yyscanner;" to the top of these methods: yy_fatal_error, cmListFileLexer_yyalloc, cmListFileLexer_yyrealloc, cmListFileLexer_yyfree + - remove statement "yyscanner = NULL;" from cmListFileLexer_yylex_destroy - remove all YY_BREAK lines occurring right after return statements - remove the isatty forward declaration @@ -540,7 +564,7 @@ static void cmListFileLexerDestroy(cmListFileLexer* lexer); /*--------------------------------------------------------------------------*/ -#line 568 "cmListFileLexer.c" +#line 570 "cmListFileLexer.c" #define INITIAL 0 #define STRING 1 @@ -591,6 +615,12 @@ struct yyguts_t }; /* end struct yyguts_t */ +static int yy_init_globals (yyscan_t yyscanner ); + +int cmListFileLexer_yylex_init (yyscan_t* scanner); + +int cmListFileLexer_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ @@ -620,6 +650,10 @@ int cmListFileLexer_yyget_lineno (yyscan_t yyscanner ); void cmListFileLexer_yyset_lineno (int line_number ,yyscan_t yyscanner ); +int cmListFileLexer_yyget_column (yyscan_t yyscanner ); + +void cmListFileLexer_yyset_column (int column_no ,yyscan_t yyscanner ); + /* Macros after this point can all be overridden by user definitions in * section 1. */ @@ -652,7 +686,12 @@ static int input (yyscan_t yyscanner ); /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else #define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ @@ -660,7 +699,7 @@ static int input (yyscan_t yyscanner ); /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, @@ -749,19 +788,19 @@ extern int cmListFileLexer_yylex (yyscan_t yyscanner); */ YY_DECL { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; -#line 100 "cmListFileLexer.in.l" +#line 82 "cmListFileLexer.in.l" -#line 787 "cmListFileLexer.c" +#line 804 "cmListFileLexer.c" - if ( yyg->yy_init ) + if ( !yyg->yy_init ) { - yyg->yy_init = 0; + yyg->yy_init = 1; #ifdef YY_USER_INIT YY_USER_INIT; @@ -801,7 +840,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -810,13 +849,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 39 ) + if ( yy_current_state >= 45 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 89 ); + while ( yy_base[yy_current_state] != 109 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -855,7 +894,7 @@ do_action: /* This label is used only to access EOF actions. */ case 1: /* rule 1 can match eol */ YY_RULE_SETUP -#line 102 "cmListFileLexer.in.l" +#line 84 "cmListFileLexer.in.l" { lexer->token.type = cmListFileLexer_Token_Newline; cmListFileLexerSetToken(lexer, yytext, yyleng); @@ -865,14 +904,14 @@ YY_RULE_SETUP } case 2: YY_RULE_SETUP -#line 110 "cmListFileLexer.in.l" +#line 92 "cmListFileLexer.in.l" { lexer->column += yyleng; } YY_BREAK case 3: YY_RULE_SETUP -#line 114 "cmListFileLexer.in.l" +#line 96 "cmListFileLexer.in.l" { lexer->token.type = cmListFileLexer_Token_ParenLeft; cmListFileLexerSetToken(lexer, yytext, yyleng); @@ -881,7 +920,7 @@ YY_RULE_SETUP } case 4: YY_RULE_SETUP -#line 121 "cmListFileLexer.in.l" +#line 103 "cmListFileLexer.in.l" { lexer->token.type = cmListFileLexer_Token_ParenRight; cmListFileLexerSetToken(lexer, yytext, yyleng); @@ -890,7 +929,7 @@ YY_RULE_SETUP } case 5: YY_RULE_SETUP -#line 128 "cmListFileLexer.in.l" +#line 110 "cmListFileLexer.in.l" { lexer->token.type = cmListFileLexer_Token_Identifier; cmListFileLexerSetToken(lexer, yytext, yyleng); @@ -899,7 +938,7 @@ YY_RULE_SETUP } case 6: YY_RULE_SETUP -#line 135 "cmListFileLexer.in.l" +#line 117 "cmListFileLexer.in.l" { lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted; cmListFileLexerSetToken(lexer, yytext, yyleng); @@ -908,7 +947,16 @@ YY_RULE_SETUP } case 7: YY_RULE_SETUP -#line 142 "cmListFileLexer.in.l" +#line 124 "cmListFileLexer.in.l" +{ + lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} +case 8: +YY_RULE_SETUP +#line 131 "cmListFileLexer.in.l" { lexer->token.type = cmListFileLexer_Token_ArgumentQuoted; cmListFileLexerSetToken(lexer, "", 0); @@ -916,58 +964,69 @@ YY_RULE_SETUP BEGIN(STRING); } YY_BREAK -case 8: -/* rule 8 can match eol */ +case 9: YY_RULE_SETUP -#line 149 "cmListFileLexer.in.l" +#line 138 "cmListFileLexer.in.l" { cmListFileLexerAppend(lexer, yytext, yyleng); lexer->column += yyleng; } YY_BREAK -case 9: -/* rule 9 can match eol */ +case 10: +/* rule 10 can match eol */ YY_RULE_SETUP -#line 154 "cmListFileLexer.in.l" +#line 143 "cmListFileLexer.in.l" { cmListFileLexerAppend(lexer, yytext, yyleng); ++lexer->line; lexer->column = 1; } YY_BREAK -case 10: +case 11: +/* rule 11 can match eol */ +YY_RULE_SETUP +#line 149 "cmListFileLexer.in.l" +{ + cmListFileLexerAppend(lexer, yytext, yyleng); + ++lexer->line; + lexer->column = 1; +} + YY_BREAK +case 12: YY_RULE_SETUP -#line 160 "cmListFileLexer.in.l" +#line 155 "cmListFileLexer.in.l" { lexer->column += yyleng; BEGIN(INITIAL); return 1; } -case 11: +case 13: YY_RULE_SETUP -#line 166 "cmListFileLexer.in.l" +#line 161 "cmListFileLexer.in.l" { cmListFileLexerAppend(lexer, yytext, yyleng); lexer->column += yyleng; } YY_BREAK case YY_STATE_EOF(STRING): -#line 171 "cmListFileLexer.in.l" +#line 166 "cmListFileLexer.in.l" { lexer->token.type = cmListFileLexer_Token_BadString; BEGIN(INITIAL); return 1; } -case 12: +case 14: YY_RULE_SETUP -#line 177 "cmListFileLexer.in.l" +#line 172 "cmListFileLexer.in.l" { + lexer->token.type = cmListFileLexer_Token_Space; + cmListFileLexerSetToken(lexer, yytext, yyleng); lexer->column += yyleng; + return 1; } - YY_BREAK -case 13: +case 15: YY_RULE_SETUP -#line 181 "cmListFileLexer.in.l" +#line 179 "cmListFileLexer.in.l" { lexer->token.type = cmListFileLexer_Token_BadCharacter; cmListFileLexerSetToken(lexer, yytext, yyleng); @@ -975,18 +1034,18 @@ YY_RULE_SETUP return 1; } case YY_STATE_EOF(INITIAL): -#line 188 "cmListFileLexer.in.l" +#line 186 "cmListFileLexer.in.l" { lexer->token.type = cmListFileLexer_Token_None; cmListFileLexerSetToken(lexer, 0, 0); return 0; } -case 14: +case 16: YY_RULE_SETUP -#line 194 "cmListFileLexer.in.l" +#line 192 "cmListFileLexer.in.l" ECHO; YY_BREAK -#line 1025 "cmListFileLexer.c" +#line 1064 "cmListFileLexer.c" case YY_END_OF_BUFFER: { @@ -1127,9 +1186,9 @@ ECHO; static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = yyg->yytext_ptr; - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) @@ -1171,7 +1230,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) else { - size_t num_to_read = + int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) @@ -1216,7 +1275,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - yyg->yy_n_chars, num_to_read ); + yyg->yy_n_chars, (size_t) num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } @@ -1240,6 +1299,14 @@ static int yy_get_next_buffer (yyscan_t yyscanner) else ret_val = EOB_ACT_CONTINUE_SCAN; + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) cmListFileLexer_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + yyg->yy_n_chars += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; @@ -1253,15 +1320,15 @@ static int yy_get_next_buffer (yyscan_t yyscanner) static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { - register yy_state_type yy_current_state; - register char *yy_cp; + yy_state_type yy_current_state; + char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1270,7 +1337,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 39 ) + if ( yy_current_state >= 45 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1286,11 +1353,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { - register int yy_is_jam; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *yy_cp = yyg->yy_c_buf_p; + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; - register YY_CHAR yy_c = 1; + YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1299,11 +1366,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 39 ) + if ( yy_current_state >= 45 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 38); + yy_is_jam = (yy_current_state == 44); return yy_is_jam ? 0 : yy_current_state; } @@ -1633,6 +1700,8 @@ static void cmListFileLexer_yyensure_buffer_stack (yyscan_t yyscanner) yyg->yy_buffer_stack = (struct yy_buffer_state**)cmListFileLexer_yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in cmListFileLexer_yyensure_buffer_stack()" ); memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); @@ -1651,6 +1720,8 @@ static void cmListFileLexer_yyensure_buffer_stack (yyscan_t yyscanner) (yyg->yy_buffer_stack, num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in cmListFileLexer_yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); @@ -1695,26 +1766,26 @@ YY_BUFFER_STATE cmListFileLexer_yy_scan_buffer (char * base, yy_size_t size , /** Setup the input buffer state to scan a string. The next call to cmListFileLexer_yylex() will * scan from a @e copy of @a str. - * @param str a NUL-terminated string to scan + * @param yystr a NUL-terminated string to scan * @param yyscanner The scanner object. * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * cmListFileLexer_yy_scan_bytes() instead. */ -YY_BUFFER_STATE cmListFileLexer_yy_scan_string (yyconst char * yy_str , yyscan_t yyscanner) +YY_BUFFER_STATE cmListFileLexer_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) { - return cmListFileLexer_yy_scan_bytes(yy_str,strlen(yy_str) ,yyscanner); + return cmListFileLexer_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); } /** Setup the input buffer state to scan the given bytes. The next call to cmListFileLexer_yylex() will * scan from a @e copy of @a bytes. - * @param bytes the byte buffer to scan - * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ -YY_BUFFER_STATE cmListFileLexer_yy_scan_bytes (yyconst char * bytes, int len , yyscan_t yyscanner) +YY_BUFFER_STATE cmListFileLexer_yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; @@ -1722,15 +1793,15 @@ YY_BUFFER_STATE cmListFileLexer_yy_scan_bytes (yyconst char * bytes, int len , int i; /* Get memory for full buffer, including space for trailing EOB's. */ - n = len + 2; + n = _yybytes_len + 2; buf = (char *) cmListFileLexer_yyalloc(n ,yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in cmListFileLexer_yy_scan_bytes()" ); - for ( i = 0; i < len; ++i ) - buf[i] = bytes[i]; + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; - buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = cmListFileLexer_yy_scan_buffer(buf,n ,yyscanner); if ( ! b ) @@ -1918,21 +1989,87 @@ void cmListFileLexer_yyset_debug (int bdebug , yyscan_t yyscanner) /* Accessor methods for yylval and yylloc */ +/* User-visible API */ + +/* cmListFileLexer_yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int cmListFileLexer_yylex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) cmListFileLexer_yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* cmListFileLexer_yylex_init_extra has the same functionality as cmListFileLexer_yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to cmListFileLexer_yyalloc in + * the yyextra field. + */ + +int cmListFileLexer_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + cmListFileLexer_yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) cmListFileLexer_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + cmListFileLexer_yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + static int yy_init_globals (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Initialization is the same as for the non-reentrant scanner. - This function is called once per scanner lifetime. */ + * This function is called from cmListFileLexer_yylex_destroy(), so don't allocate here. + */ yyg->yy_buffer_stack = 0; yyg->yy_buffer_stack_top = 0; yyg->yy_buffer_stack_max = 0; yyg->yy_c_buf_p = (char *) 0; - yyg->yy_init = 1; + yyg->yy_init = 0; yyg->yy_start = 0; + yyg->yy_start_stack_ptr = 0; yyg->yy_start_stack_depth = 0; - yyg->yy_start_stack = (int *) 0; + yyg->yy_start_stack = NULL; /* Defined in main.c */ #ifdef YY_STDINIT @@ -1949,33 +2086,6 @@ static int yy_init_globals (yyscan_t yyscanner) return 0; } -/* User-visible API */ - -/* cmListFileLexer_yylex_init is special because it creates the scanner itself, so it is - * the ONLY reentrant function that doesn't take the scanner as the last argument. - * That's why we explicitly handle the declaration, instead of using our macros. - */ - -int cmListFileLexer_yylex_init(yyscan_t* ptr_yy_globals) - -{ - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) cmListFileLexer_yyalloc ( sizeof( struct yyguts_t ), NULL ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - memset(*ptr_yy_globals,0,sizeof(struct yyguts_t)); - - return yy_init_globals ( *ptr_yy_globals ); -} - /* cmListFileLexer_yylex_destroy is for both reentrant and non-reentrant scanners. */ int cmListFileLexer_yylex_destroy (yyscan_t yyscanner) { @@ -1996,6 +2106,10 @@ int cmListFileLexer_yylex_destroy (yyscan_t yyscanner) cmListFileLexer_yyfree(yyg->yy_start_stack ,yyscanner ); yyg->yy_start_stack = NULL; + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * cmListFileLexer_yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + /* Destroy the main struct (reentrant only). */ cmListFileLexer_yyfree ( yyscanner , yyscanner ); return 0; @@ -2008,8 +2122,7 @@ int cmListFileLexer_yylex_destroy (yyscan_t yyscanner) #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) { - register int i; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } @@ -2018,8 +2131,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysca #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) { - register int n; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + int n; for ( n = 0; s[n]; ++n ) ; @@ -2054,19 +2166,7 @@ void cmListFileLexer_yyfree (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#undef YY_NEW_FILE -#undef YY_FLUSH_BUFFER -#undef yy_set_bol -#undef yy_new_buffer -#undef yy_set_interactive -#undef yytext_ptr -#undef YY_DO_BEFORE_ACTION - -#ifdef YY_DECL_IS_OURS -#undef YY_DECL_IS_OURS -#undef YY_DECL -#endif -#line 194 "cmListFileLexer.in.l" +#line 192 "cmListFileLexer.in.l" @@ -2122,7 +2222,7 @@ static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text, } /* We need to extend the buffer. */ - temp = (char*)malloc(newSize); + temp = malloc(newSize); if(lexer->token.text) { memcpy(temp, lexer->token.text, lexer->token.length); @@ -2303,6 +2403,7 @@ const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer, switch(type) { case cmListFileLexer_Token_None: return "nothing"; + case cmListFileLexer_Token_Space: return "space"; case cmListFileLexer_Token_Newline: return "newline"; case cmListFileLexer_Token_Identifier: return "identifier"; case cmListFileLexer_Token_ParenLeft: return "left paren"; diff --git a/Source/cmListFileLexer.h b/Source/cmListFileLexer.h index 5f4db33c4..cc78b5c2f 100644 --- a/Source/cmListFileLexer.h +++ b/Source/cmListFileLexer.h @@ -15,6 +15,7 @@ typedef enum cmListFileLexer_Type_e { cmListFileLexer_Token_None, + cmListFileLexer_Token_Space, cmListFileLexer_Token_Newline, cmListFileLexer_Token_Identifier, cmListFileLexer_Token_ParenLeft, diff --git a/Source/cmListFileLexer.in.l b/Source/cmListFileLexer.in.l index 41e817b1a..12b53eef6 100644 --- a/Source/cmListFileLexer.in.l +++ b/Source/cmListFileLexer.in.l @@ -20,9 +20,11 @@ Run flex like this: Modify cmListFileLexer.c: - remove TABs + - remove use of the 'register' storage class specifier - remove the yyunput function - add a statement "(void)yyscanner;" to the top of these methods: yy_fatal_error, cmListFileLexer_yyalloc, cmListFileLexer_yyrealloc, cmListFileLexer_yyfree + - remove statement "yyscanner = NULL;" from cmListFileLexer_yylex_destroy - remove all YY_BREAK lines occurring right after return statements - remove the isatty forward declaration @@ -74,6 +76,8 @@ static void cmListFileLexerDestroy(cmListFileLexer* lexer); %x STRING MAKEVAR \$\([A-Za-z0-9_]*\) +UNQUOTED ([^ \t\r\n\(\)#\\\"]|\\.) +LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t])*\" %% @@ -110,7 +114,14 @@ MAKEVAR \$\([A-Za-z0-9_]*\) return 1; } -({MAKEVAR}|[^ \t\r\n\(\)#\\\"]|\\.)({MAKEVAR}|[^ \t\r\n\(\)#\\\"]|\\.|\"({MAKEVAR}|[^\r\n\(\)#\\\"]|\\.)*\")* { +({UNQUOTED})({UNQUOTED})* { + lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + +({MAKEVAR}|{UNQUOTED})({LEGACY})* { lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted; cmListFileLexerSetToken(lexer, yytext, yyleng); lexer->column += yyleng; @@ -124,11 +135,17 @@ MAKEVAR \$\([A-Za-z0-9_]*\) BEGIN(STRING); } -<STRING>([^\\\n\"]|\\(.|\n))+ { +<STRING>([^\\\n\"]|\\.)+ { cmListFileLexerAppend(lexer, yytext, yyleng); lexer->column += yyleng; } +<STRING>\\\n { + cmListFileLexerAppend(lexer, yytext, yyleng); + ++lexer->line; + lexer->column = 1; +} + <STRING>\n { cmListFileLexerAppend(lexer, yytext, yyleng); ++lexer->line; @@ -152,8 +169,11 @@ MAKEVAR \$\([A-Za-z0-9_]*\) return 1; } -[ \t\r] { +[ \t\r]+ { + lexer->token.type = cmListFileLexer_Token_Space; + cmListFileLexerSetToken(lexer, yytext, yyleng); lexer->column += yyleng; + return 1; } . { @@ -404,6 +424,7 @@ const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer, switch(type) { case cmListFileLexer_Token_None: return "nothing"; + case cmListFileLexer_Token_Space: return "space"; case cmListFileLexer_Token_Newline: return "newline"; case cmListFileLexer_Token_Identifier: return "identifier"; case cmListFileLexer_Token_ParenLeft: return "left paren"; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index ee5b9d812..9c0410965 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -55,7 +55,6 @@ cmLocalGenerator::cmLocalGenerator() this->UseRelativePaths = false; this->Configured = false; this->EmitUniversalBinaryFlags = true; - this->IsMakefileGenerator = false; this->RelativePathsConfigured = false; this->PathConversionsSetup = false; this->BackwardsCompatibility = 0; @@ -260,12 +259,7 @@ void cmLocalGenerator::TraceDependencies() cmTargets& targets = this->Makefile->GetTargets(); for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t) { - const char* projectFilename = 0; - if (this->IsMakefileGenerator == false) // only use of this variable - { - projectFilename = t->second.GetName(); - } - t->second.TraceDependencies(projectFilename); + t->second.TraceDependencies(); } } @@ -294,7 +288,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; @@ -577,7 +571,7 @@ void cmLocalGenerator::AddCustomCommandToCreateObject(const char* ofname, { std::vector<std::string> includes; this->GetIncludeDirectories(includes, &target, lang); - flags += this->GetIncludeFlags(includes, lang); + flags += this->GetIncludeFlags(includes, &target, lang); } flags += this->Makefile->GetDefineFlags(); @@ -761,7 +755,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; } @@ -1084,8 +1078,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('<'); @@ -1212,6 +1204,7 @@ cmLocalGenerator::ConvertToIncludeReference(std::string const& path) //---------------------------------------------------------------------------- std::string cmLocalGenerator::GetIncludeFlags( const std::vector<std::string> &includes, + cmGeneratorTarget* target, const char* lang, bool forResponseFile, const char *config) { @@ -1282,11 +1275,10 @@ std::string cmLocalGenerator::GetIncludeFlags( continue; } - std::string include = *i; if(!flagUsed || repeatFlag) { - if(sysIncludeFlag && - this->Makefile->IsSystemIncludeDirectory(i->c_str(), config)) + if(sysIncludeFlag && target && + target->IsSystemIncludeDirectory(i->c_str(), config)) { includeFlags << sysIncludeFlag; } @@ -1327,6 +1319,65 @@ std::string cmLocalGenerator::GetIncludeFlags( } //---------------------------------------------------------------------------- +void cmLocalGenerator::AddCompileDefinitions(std::set<std::string>& defines, + cmTarget* target, + const char* config) +{ + std::vector<std::string> targetDefines; + target->GetCompileDefinitions(targetDefines, + config); + this->AppendDefines(defines, targetDefines); +} + +//---------------------------------------------------------------------------- +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; + 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, @@ -1476,6 +1527,25 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, } } +void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags, + std::string const& config, + cmTarget* target) +{ + this->AppendFlags(flags, + this->Makefile->GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS")); + if(!config.empty()) + { + std::string name = "CMAKE_STATIC_LINKER_FLAGS_" + config; + this->AppendFlags(flags, this->Makefile->GetSafeDefinition(name.c_str())); + } + this->AppendFlags(flags, target->GetProperty("STATIC_LIBRARY_FLAGS")); + if(!config.empty()) + { + std::string name = "STATIC_LIBRARY_FLAGS_" + config; + this->AppendFlags(flags, target->GetProperty(name.c_str())); + } +} + void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, std::string& flags, std::string& linkFlags, @@ -1492,26 +1562,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, switch(target->GetType()) { case cmTarget::STATIC_LIBRARY: - { - const char* targetLinkFlags = - target->GetProperty("STATIC_LIBRARY_FLAGS"); - if(targetLinkFlags) - { - linkFlags += targetLinkFlags; - linkFlags += " "; - } - if(!buildType.empty()) - { - std::string build = "STATIC_LIBRARY_FLAGS_"; - build += buildType; - targetLinkFlags = target->GetProperty(build.c_str()); - if(targetLinkFlags) - { - linkFlags += targetLinkFlags; - linkFlags += " "; - } - } - } + this->GetStaticLibraryFlags(linkFlags, buildType, target->Target); break; case cmTarget::MODULE_LIBRARY: libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS"; @@ -1582,7 +1633,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 +2045,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 +2137,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 +2231,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 +2269,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) { @@ -2155,7 +2288,13 @@ void cmLocalGenerator::AppendDefines(std::set<std::string>& defines, // Expand the list of definitions. std::vector<std::string> defines_vec; cmSystemTools::ExpandListArgument(defines_list, defines_vec); + this->AppendDefines(defines, defines_vec); +} +//---------------------------------------------------------------------------- +void cmLocalGenerator::AppendDefines(std::set<std::string>& defines, + const std::vector<std::string> &defines_vec) +{ for(std::vector<std::string>::const_iterator di = defines_vec.begin(); di != defines_vec.end(); ++di) { @@ -2248,7 +2387,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 a1c34f076..10f0b1a6c 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -143,12 +143,16 @@ 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, + cmGeneratorTarget* target, const char* lang, bool forResponseFile = false, const char *config = 0); @@ -163,6 +167,9 @@ public: { this->AppendDefines(defines, defines_list.c_str()); } + void AppendDefines(std::set<std::string>& defines, + const std::vector<std::string> &defines_vec); + /** * Join a set of defines into a definesString with a space separator. */ @@ -215,6 +222,10 @@ 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); + void AddCompileDefinitions(std::set<std::string>& defines, cmTarget* target, + const char* config); /** Compute the language used to compile the given source file. */ const char* GetSourceFileLanguage(const cmSourceFile& source); @@ -337,6 +348,11 @@ public: std::string const& dir_max, bool* hasSourceExtension = 0); + /** Fill out the static linker flags for the given target. */ + void GetStaticLibraryFlags(std::string& flags, + std::string const& config, + cmTarget* target); + /** Fill out these strings for the given target. Libraries to link, * flags, and linkflags. */ void GetTargetFlags(std::string& linkLibs, @@ -430,8 +446,6 @@ protected: bool IgnoreLibPrefix; bool Configured; bool EmitUniversalBinaryFlags; - // A type flag is not nice. It's used only in TraceDependencies(). - bool IsMakefileGenerator; // Hack for ExpandRuleVariable until object-oriented version is // committed. std::string TargetImplib; diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index d902f4ef7..a522e37e2 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -27,7 +27,6 @@ cmLocalNinjaGenerator::cmLocalNinjaGenerator() , ConfigName("") , HomeRelativeOutputPath("") { - this->IsMakefileGenerator = true; #ifdef _WIN32 this->WindowsShell = true; #endif @@ -302,7 +301,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) { @@ -335,14 +339,15 @@ cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( this->AppendCustomCommandLines(cc, cmdLines); if (cmdLines.empty()) { - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "Phony custom command for " + - ninjaOutputs[0], - ninjaOutputs, - ninjaDeps, - cmNinjaDeps(), - orderOnlyDeps, - cmNinjaVars()); + this->GetGlobalNinjaGenerator()->WritePhonyBuild( + this->GetBuildFileStream(), + "Phony custom command for " + + ninjaOutputs[0], + ninjaOutputs, + ninjaDeps, + cmNinjaDeps(), + orderOnlyDeps, + cmNinjaVars()); } else { this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild( this->BuildCommandLine(cmdLines), diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 0f680f6a1..56da1f936 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -92,7 +92,6 @@ cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3() this->SkipPreprocessedSourceRules = false; this->SkipAssemblySourceRules = false; this->MakeCommandEscapeTargetTwice = false; - this->IsMakefileGenerator = true; this->BorlandMakeCurlyHack = false; } @@ -1304,7 +1303,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 +1344,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 +1352,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); @@ -1962,8 +1961,8 @@ void cmLocalUnixMakefileGenerator3 // Build a list of preprocessor definitions for the target. std::set<std::string> defines; - this->AppendDefines(defines, target.GetCompileDefinitions( - this->ConfigurationName.c_str())); + this->AddCompileDefinitions(defines, &target, + this->ConfigurationName.c_str()); if(!defines.empty()) { cmakefileStream diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index dc94476c8..e5b4057d2 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -573,22 +573,20 @@ cmLocalVisualStudio6Generator // Add the rule with the given dependencies and commands. const char* no_main_dependency = 0; - this->Makefile->AddCustomCommandToOutput(output, - depends, - no_main_dependency, - origCommand.GetCommandLines(), - comment.c_str(), - origCommand.GetWorkingDirectory()); + if(cmSourceFile* outsf = + this->Makefile->AddCustomCommandToOutput( + output, depends, no_main_dependency, + origCommand.GetCommandLines(), comment.c_str(), + origCommand.GetWorkingDirectory())) + { + target.AddSourceFile(outsf); + } // Replace the dependencies with the output of this rule so that the // next rule added will run after this one. depends.clear(); depends.push_back(output); - // Add a source file representing this output to the project. - cmSourceFile* outsf = this->Makefile->GetSourceFileWithOutput(output); - target.AddSourceFile(outsf); - // Free the fake output name. delete [] output; } @@ -1171,18 +1169,42 @@ void cmLocalVisualStudio6Generator std::string extraLinkOptionsRelWithDebInfo; if(target.GetType() == cmTarget::EXECUTABLE) { - extraLinkOptions = - this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS"); + extraLinkOptions = this->Makefile-> + GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS"); + extraLinkOptionsDebug = this->Makefile-> + GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS_DEBUG"); + extraLinkOptionsRelease = this->Makefile-> + GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS_RELEASE"); + extraLinkOptionsMinSizeRel = this->Makefile-> + GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS_MINSIZEREL"); + extraLinkOptionsRelWithDebInfo = this->Makefile-> + GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO"); } if(target.GetType() == cmTarget::SHARED_LIBRARY) { - extraLinkOptions = - this->Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS"); + extraLinkOptions = this->Makefile-> + GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS"); + extraLinkOptionsDebug = this->Makefile-> + GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS_DEBUG"); + extraLinkOptionsRelease = this->Makefile-> + GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS_RELEASE"); + extraLinkOptionsMinSizeRel = this->Makefile-> + GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL"); + extraLinkOptionsRelWithDebInfo = this->Makefile-> + GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO"); } if(target.GetType() == cmTarget::MODULE_LIBRARY) { - extraLinkOptions = - this->Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS"); + extraLinkOptions = this->Makefile-> + GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS"); + extraLinkOptionsDebug = this->Makefile-> + GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS_DEBUG"); + extraLinkOptionsRelease = this->Makefile-> + GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS_RELEASE"); + extraLinkOptionsMinSizeRel = this->Makefile-> + GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL"); + extraLinkOptionsRelWithDebInfo = this->Makefile-> + GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO"); } // Get extra linker options for this target. @@ -1228,7 +1250,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; } @@ -1435,38 +1457,39 @@ void cmLocalVisualStudio6Generator std::string staticLibOptionsRelWithDebInfo; if(target.GetType() == cmTarget::STATIC_LIBRARY ) { - if(const char* libflags = target.GetProperty("STATIC_LIBRARY_FLAGS")) - { - staticLibOptions = libflags; - staticLibOptionsDebug = libflags; - staticLibOptionsRelease = libflags; - staticLibOptionsMinSizeRel = libflags; - staticLibOptionsRelWithDebInfo = libflags; - } - if(const char* libflagsDebug = - target.GetProperty("STATIC_LIBRARY_FLAGS_DEBUG")) - { - staticLibOptionsDebug += " "; - staticLibOptionsDebug = libflagsDebug; - } - if(const char* libflagsRelease = - target.GetProperty("STATIC_LIBRARY_FLAGS_RELEASE")) - { - staticLibOptionsRelease += " "; - staticLibOptionsRelease = libflagsRelease; - } - if(const char* libflagsMinSizeRel = - target.GetProperty("STATIC_LIBRARY_FLAGS_MINSIZEREL")) - { - staticLibOptionsMinSizeRel += " "; - staticLibOptionsMinSizeRel = libflagsMinSizeRel; - } - if(const char* libflagsRelWithDebInfo = - target.GetProperty("STATIC_LIBRARY_FLAGS_RELWITHDEBINFO")) - { - staticLibOptionsRelWithDebInfo += " "; - staticLibOptionsRelWithDebInfo = libflagsRelWithDebInfo; - } + const char *libflagsGlobal = + this->Makefile->GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS"); + this->AppendFlags(staticLibOptions, libflagsGlobal); + this->AppendFlags(staticLibOptionsDebug, libflagsGlobal); + this->AppendFlags(staticLibOptionsRelease, libflagsGlobal); + this->AppendFlags(staticLibOptionsMinSizeRel, libflagsGlobal); + this->AppendFlags(staticLibOptionsRelWithDebInfo, libflagsGlobal); + + this->AppendFlags(staticLibOptionsDebug, this->Makefile-> + GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS_DEBUG")); + this->AppendFlags(staticLibOptionsRelease, this->Makefile-> + GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS_RELEASE")); + this->AppendFlags(staticLibOptionsMinSizeRel, this->Makefile-> + GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL")); + this->AppendFlags(staticLibOptionsRelWithDebInfo, this->Makefile-> + GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO")); + + const char *libflags = target.GetProperty("STATIC_LIBRARY_FLAGS"); + this->AppendFlags(staticLibOptions, libflags); + this->AppendFlags(staticLibOptionsDebug, libflags); + this->AppendFlags(staticLibOptionsRelease, libflags); + this->AppendFlags(staticLibOptionsMinSizeRel, libflags); + this->AppendFlags(staticLibOptionsRelWithDebInfo, libflags); + + this->AppendFlags(staticLibOptionsDebug, + target.GetProperty("STATIC_LIBRARY_FLAGS_DEBUG")); + this->AppendFlags(staticLibOptionsRelease, + target.GetProperty("STATIC_LIBRARY_FLAGS_RELEASE")); + this->AppendFlags(staticLibOptionsMinSizeRel, + target.GetProperty("STATIC_LIBRARY_FLAGS_MINSIZEREL")); + this->AppendFlags(staticLibOptionsRelWithDebInfo, + target.GetProperty("STATIC_LIBRARY_FLAGS_RELWITHDEBINFO")); + std::string objects; this->OutputObjects(target, "LIB", objects); if(!objects.empty()) @@ -1639,9 +1662,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 +1672,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 +1687,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 +1717,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; @@ -1700,21 +1724,11 @@ void cmLocalVisualStudio6Generator std::set<std::string> minsizeDefinesSet; std::set<std::string> debugrelDefinesSet; - this->AppendDefines( - definesSet, - target.GetCompileDefinitions(0)); - this->AppendDefines( - debugDefinesSet, - target.GetCompileDefinitions("DEBUG")); - this->AppendDefines( - releaseDefinesSet, - target.GetCompileDefinitions("RELEASE")); - this->AppendDefines( - minsizeDefinesSet, - target.GetCompileDefinitions("MINSIZEREL")); - this->AppendDefines( - debugrelDefinesSet, - target.GetCompileDefinitions("RELWITHDEBINFO")); + this->AddCompileDefinitions(definesSet, &target, 0); + this->AddCompileDefinitions(debugDefinesSet, &target, "DEBUG"); + this->AddCompileDefinitions(releaseDefinesSet, &target, "RELEASE"); + this->AddCompileDefinitions(minsizeDefinesSet, &target, "MINSIZEREL"); + this->AddCompileDefinitions(debugrelDefinesSet, &target, "RELWITHDEBINFO"); std::string defines = " "; std::string debugDefines = " "; @@ -1731,19 +1745,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 7d0bc67ed..8ffd96eb1 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -146,11 +146,10 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets() force += "/"; force += tgt.GetName(); force += "_force"; - this->Makefile->AddCustomCommandToOutput(force.c_str(), no_depends, - no_main_dependency, - force_commands, " ", 0, true); if(cmSourceFile* file = - this->Makefile->GetSourceFileWithOutput(force.c_str())) + this->Makefile->AddCustomCommandToOutput( + force.c_str(), no_depends, no_main_dependency, + force_commands, " ", 0, true)) { tgt.AddSourceFile(file); } @@ -202,7 +201,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 +442,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 +475,11 @@ cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[] = {"ForcedIncludeFiles", "FI", "Forced include files", "", cmVS7FlagTable::UserValueRequired | cmVS7FlagTable::SemicolonAppendable}, + {"AssemblerListingLocation", "Fa", "ASM List Location", "", + cmVS7FlagTable::UserValue}, + {"ProgramDataBaseFileName", "Fd", "Program Database File Name", "", + cmVS7FlagTable::UserValue}, + // boolean flags {"BufferSecurityCheck", "GS", "Buffer security check", "TRUE", 0}, {"BufferSecurityCheck", "GS-", "Turn off Buffer security check", "FALSE", 0}, @@ -683,7 +687,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 +712,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 +727,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,12 +740,16 @@ 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(); cmGeneratorTarget* gt = this->GlobalGenerator->GetGeneratorTarget(&target); - targetOptions.AddDefines(target.GetCompileDefinitions(configName).c_str()); + std::vector<std::string> targetDefines; + target.GetCompileDefinitions(targetDefines, configName); + targetOptions.AddDefines(targetDefines); targetOptions.SetVerboseMakefile( this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")); @@ -836,18 +840,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) @@ -928,7 +921,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, } this->OutputTargetRules(fout, configName, target, libName); - this->OutputBuildTool(fout, configName, target, targetOptions.IsDebug()); + this->OutputBuildTool(fout, configName, target, targetOptions); fout << "\t\t</Configuration>\n"; } @@ -949,9 +942,7 @@ cmLocalVisualStudio7Generator } void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, - const char* configName, - cmTarget &target, - bool isDebug) + const char* configName, cmTarget &target, const Options& targetOptions) { cmGlobalVisualStudio7Generator* gg = static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator); @@ -1047,17 +1038,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, } } std::string libflags; - if(const char* flags = target.GetProperty("STATIC_LIBRARY_FLAGS")) - { - libflags += flags; - } - std::string libFlagsConfig = "STATIC_LIBRARY_FLAGS_"; - libFlagsConfig += configTypeUpper; - if(const char* flagsConfig = target.GetProperty(libFlagsConfig.c_str())) - { - libflags += " "; - libflags += flagsConfig; - } + this->GetStaticLibraryFlags(libflags, configTypeUpper, &target); if(!libflags.empty()) { fout << "\t\t\t\tAdditionalOptions=\"" << libflags << "\"\n"; @@ -1129,7 +1110,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, temp += targetNamePDB; fout << "\t\t\t\tProgramDatabaseFile=\"" << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n"; - if(isDebug) + if(targetOptions.IsDebug()) { fout << "\t\t\t\tGenerateDebugInformation=\"TRUE\"\n"; } @@ -1227,7 +1208,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/" << targetNamePDB << "\"\n"; - if(isDebug) + if(targetOptions.IsDebug()) { fout << "\t\t\t\tGenerateDebugInformation=\"TRUE\"\n"; } @@ -1241,9 +1222,14 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, { fout << "\t\t\t\tSubSystem=\"8\"\n"; } - fout << "\t\t\t\tEntryPointSymbol=\"" - << (isWin32Executable ? "WinMainCRTStartup" : "mainACRTStartup") - << "\"\n"; + + if(!linkOptions.GetFlag("EntryPointSymbol")) + { + const char* entryPointSymbol = targetOptions.UsingUnicode() ? + (isWin32Executable ? "wWinMainCRTStartup" : "mainWCRTStartup") : + (isWin32Executable ? "WinMainCRTStartup" : "mainACRTStartup"); + fout << "\t\t\t\tEntryPointSymbol=\"" << entryPointSymbol << "\"\n"; + } } else if ( this->FortranProject ) { @@ -1970,23 +1956,27 @@ cmLocalVisualStudio7Generator // Compute the version of the Intel plugin to the VS IDE. // If the key does not exist then use a default guess. - std::string intelVersion = "9.10"; + std::string intelVersion; std::string vskey = gg->GetRegistryBase(); vskey += "\\Packages\\" CM_INTEL_PLUGIN_GUID ";ProductVersion"; cmSystemTools::ReadRegistryValue(vskey.c_str(), intelVersion, cmSystemTools::KeyWOW64_32); - if (intelVersion.find("13") == 0 || - intelVersion.find("12") == 0 || - intelVersion.find("11") == 0) + unsigned int intelVersionNumber = ~0u; + sscanf(intelVersion.c_str(), "%u", &intelVersionNumber); + if(intelVersionNumber >= 11) { - // Version 11.x, 12.x, and 13.x actually use 11.0 in project files! - intelVersion = "11.0" ; + // Default to latest known project file version. + intelVersion = "11.0"; } - else if(intelVersion.find("10") == 0) + else if(intelVersionNumber == 10) { // Version 10.x actually uses 9.10 in project files! intelVersion = "9.10"; } + else + { + // Version <= 9: use ProductVersion from registry. + } fout << "<?xml version=\"1.0\" encoding = \"Windows-1252\"?>\n" << "<VisualStudioProject\n" diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index d9e2ef0dd..92e4d3c12 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -90,7 +90,7 @@ private: void OutputTargetRules(std::ostream& fout, const char* configName, cmTarget &target, const char *libName); void OutputBuildTool(std::ostream& fout, const char* configName, - cmTarget& t, bool debug); + cmTarget& t, const Options& targetOptions); void OutputLibraryDirectories(std::ostream& fout, std::vector<std::string> const& dirs); void WriteProjectSCC(std::ostream& fout, cmTarget& target); diff --git a/Source/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx index 551ebd30a..7c5f69df5 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 eab228f6b..d97a41cea 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/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index bd7ec004b..8ba612cc9 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -227,7 +227,7 @@ bool cmMacroHelperCommand::InvokeInitialPass } arg.Value = tmps; - arg.Quoted = k->Quoted; + arg.Delim = k->Delim; arg.FilePath = k->FilePath; arg.Line = k->Line; newLFF.Arguments.push_back(arg); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 47a6d2e66..34541e996 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" @@ -40,6 +41,7 @@ #include <stack> #include <ctype.h> // for isspace +#include <assert.h> class cmMakefile::Internals { @@ -148,6 +150,7 @@ cmMakefile::cmMakefile(const cmMakefile& mf): Internal(new Internals) this->Initialize(); this->CheckSystemVars = mf.CheckSystemVars; this->ListFileStack = mf.ListFileStack; + this->OutputToSource = mf.OutputToSource; } //---------------------------------------------------------------------------- @@ -813,6 +816,19 @@ bool cmMakefile::NeedBackwardsCompatibility(unsigned int major, } } + +namespace +{ + struct file_not_persistent + { + bool operator()(const std::string& path) const + { + return !(path.find("CMakeTmp") == path.npos && + cmSystemTools::FileExists(path.c_str())); + } + }; +} + void cmMakefile::FinalPass() { // do all the variable expansions here @@ -826,6 +842,29 @@ void cmMakefile::FinalPass() (*i)->FinalPass(); } + //go through all configured files and see which ones still exist. + //we don't want cmake to re-run if a configured file is created and deleted + //during processing as that would make it a transient file that can't + //influence the build process + + //remove_if will move all items that don't have a valid file name to the + //back of the vector + std::vector<std::string>::iterator new_output_files_end = std::remove_if( + this->OutputFiles.begin(), + this->OutputFiles.end(), + file_not_persistent() ); + //we just have to erase all items at the back + this->OutputFiles.erase(new_output_files_end, this->OutputFiles.end() ); + + //if a configured file is used as input for another configured file, + //and then deleted it will show up in the input list files so we + //need to scan those too + std::vector<std::string>::iterator new_list_files_end = std::remove_if( + this->ListFiles.begin(), + this->ListFiles.end(), + file_not_persistent() ); + + this->ListFiles.erase(new_list_files_end, this->ListFiles.end() ); } // Generate the output file @@ -1008,11 +1047,45 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs, cc->SetEscapeOldStyle(escapeOldStyle); cc->SetEscapeAllowMakeVars(true); file->SetCustomCommand(cc); + this->UpdateOutputToSourceMap(outputs, file); } return file; } //---------------------------------------------------------------------------- +void +cmMakefile::UpdateOutputToSourceMap(std::vector<std::string> const& outputs, + cmSourceFile* source) +{ + for(std::vector<std::string>::const_iterator o = outputs.begin(); + o != outputs.end(); ++o) + { + this->UpdateOutputToSourceMap(*o, source); + } +} + +//---------------------------------------------------------------------------- +void +cmMakefile::UpdateOutputToSourceMap(std::string const& output, + cmSourceFile* source) +{ + OutputToSourceMap::iterator i = this->OutputToSource.find(output); + if(i != this->OutputToSource.end()) + { + // Multiple custom commands produce the same output but may + // be attached to a different source file (MAIN_DEPENDENCY). + // LinearGetSourceFileWithOutput would return the first one, + // so keep the mapping for the first one. + // + // TODO: Warn the user about this case. However, the VS 8 generator + // triggers it for separate generate.stamp rules in ZERO_CHECK and + // individual targets. + return; + } + this->OutputToSource[output] = source; +} + +//---------------------------------------------------------------------------- cmSourceFile* cmMakefile::AddCustomCommandToOutput(const char* output, const std::vector<std::string>& depends, @@ -1270,6 +1343,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. @@ -1431,12 +1509,20 @@ void cmMakefile::AddLinkDirectoryForTarget(const char *target, cmTargets::iterator i = this->Targets.find(target); if ( i != this->Targets.end()) { + if(this->IsAlias(target)) + { + cmOStringStream e; + e << "ALIAS target \"" << target << "\" " + << "may not be linked into another target."; + this->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); + return; + } i->second.AddLinkDirectory( d ); } 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 +1579,18 @@ void cmMakefile::InitializeFromParent() parentIncludes.begin(), parentIncludes.end()); + const std::vector<cmValueWithOrigin> parentOptions = + parent->GetCompileOptionsEntries(); + this->CompileOptionsEntries.insert(this->CompileOptionsEntries.end(), + parentOptions.begin(), + parentOptions.end()); + + const std::vector<cmValueWithOrigin> parentDefines = + parent->GetCompileDefinitionsEntries(); + this->CompileDefinitionsEntries.insert(this->CompileDefinitionsEntries.end(), + parentDefines.begin(), + parentDefines.end()); + this->SystemIncludeDirectories = parent->SystemIncludeDirectories; // define flags @@ -1663,27 +1761,13 @@ cmMakefile::AddSystemIncludeDirectories(const std::set<cmStdString> &incs) { this->SystemIncludeDirectories.insert(*li); } -} -//---------------------------------------------------------------------------- -bool cmMakefile::IsSystemIncludeDirectory(const char* dir, const char *config) -{ - for (std::set<cmStdString>::const_iterator - it = this->SystemIncludeDirectories.begin(); - it != this->SystemIncludeDirectories.end(); ++it) + for (cmTargets::iterator l = this->Targets.begin(); + l != this->Targets.end(); ++l) { - cmListFileBacktrace lfbt; - cmGeneratorExpression ge(lfbt); - - std::vector<std::string> incs; - cmSystemTools::ExpandListArgument(ge.Parse(*it) - ->Evaluate(this, config, false), incs); - if (std::find(incs.begin(), incs.end(), dir) != incs.end()) - { - return true; - } + cmTarget &t = l->second; + t.AddSystemIncludeDirectories(incs); } - return false; } void cmMakefile::AddDefinition(const char* name, const char* value) @@ -1919,6 +2003,12 @@ void cmMakefile::AddGlobalLinkInformation(const char* name, cmTarget& target) } +void cmMakefile::AddAlias(const char* lname, cmTarget *tgt) +{ + this->AliasTargets[lname] = tgt; + this->LocalGenerator->GetGlobalGenerator()->AddAlias(lname, tgt); +} + cmTarget* cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type, const std::vector<std::string> &srcs, bool excludeFromAll) @@ -1975,7 +2065,7 @@ cmMakefile::AddNewTarget(cmTarget::TargetType type, const char* name) return &it->second; } -cmSourceFile *cmMakefile::GetSourceFileWithOutput(const char *cname) +cmSourceFile *cmMakefile::LinearGetSourceFileWithOutput(const char *cname) { std::string name = cname; std::string out; @@ -2011,6 +2101,25 @@ cmSourceFile *cmMakefile::GetSourceFileWithOutput(const char *cname) return 0; } +cmSourceFile *cmMakefile::GetSourceFileWithOutput(const char *cname) +{ + std::string name = cname; + + // If the queried path is not absolute we use the backward compatible + // linear-time search for an output with a matching suffix. + if(!cmSystemTools::FileIsFullPath(cname)) + { + return LinearGetSourceFileWithOutput(cname); + } + // Otherwise we use an efficient lookup map. + OutputToSourceMap::iterator o = this->OutputToSource.find(name); + if (o != this->OutputToSource.end()) + { + return (*o).second; + } + return 0; +} + #if defined(CMAKE_BUILD_WITH_CMAKE) cmSourceGroup* cmMakefile::GetSourceGroup(const std::vector<std::string>&name) { @@ -2086,7 +2195,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); @@ -2780,7 +2889,7 @@ bool cmMakefile::ExpandArguments( // If the argument is quoted, it should be one argument. // Otherwise, it may be a list of arguments. - if(i->Quoted) + if(i->Delim == cmListFileArgument::Quoted) { outArgs.push_back(value); } @@ -3357,8 +3466,14 @@ 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); + + // Re-generate if non-temporary outputs are missing. + //when we finalize the configuration we will remove all + //output files that now don't exist. + this->AddCMakeOutputFile(soutfile); + mode_t perm = 0; cmSystemTools::GetPermissions(sinfile.c_str(), perm); std::string::size_type pos = soutfile.rfind('/'); @@ -3468,6 +3583,31 @@ 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 == "COMPILE_DEFINITIONS") + { + this->CompileDefinitionsEntries.clear(); + if (!value) + { + return; + } + cmListFileBacktrace lfbt; + this->GetBacktrace(lfbt); + cmValueWithOrigin entry(value, lfbt); + this->CompileDefinitionsEntries.push_back(entry); + return; + } if ( propname == "INCLUDE_REGULAR_EXPRESSION" ) { @@ -3507,6 +3647,22 @@ 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 == "COMPILE_DEFINITIONS") + { + cmListFileBacktrace lfbt; + this->GetBacktrace(lfbt); + this->CompileDefinitionsEntries.push_back( + cmValueWithOrigin(value, lfbt)); + return; + } if ( propname == "LINK_DIRECTORIES" ) { std::vector<std::string> varArgsExpanded; @@ -3632,6 +3788,34 @@ 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(); + } + else if (!strcmp("COMPILE_DEFINITIONS",prop)) + { + std::string sep; + for (std::vector<cmValueWithOrigin>::const_iterator + it = this->CompileDefinitionsEntries.begin(), + end = this->CompileDefinitionsEntries.end(); + it != end; ++it) + { + output += sep; + output += it->Value; + sep = ";"; + } + return output.c_str(); + } bool chain = false; const char *retVal = @@ -3680,8 +3864,17 @@ const char* cmMakefile::GetFeature(const char* feature, const char* config) return 0; } -cmTarget* cmMakefile::FindTarget(const char* name) +cmTarget* cmMakefile::FindTarget(const char* name, bool excludeAliases) { + if (!excludeAliases) + { + std::map<std::string, cmTarget*>::iterator i + = this->AliasTargets.find(name); + if (i != this->AliasTargets.end()) + { + return i->second; + } + } cmTargets& tgts = this->GetTargets(); cmTargets::iterator i = tgts.find ( name ); @@ -3986,23 +4179,36 @@ 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->DefineProperty ("LINK_DIRECTORIES", cmProperty::DIRECTORY, "List of linker search directories.", "This read-only property specifies the list of directories given " @@ -4043,7 +4249,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 +4265,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 " @@ -4093,7 +4299,7 @@ cmMakefile::AddImportedTarget(const char* name, cmTarget::TargetType type, } //---------------------------------------------------------------------------- -cmTarget* cmMakefile::FindTargetToUse(const char* name) +cmTarget* cmMakefile::FindTargetToUse(const char* name, bool excludeAliases) { // Look for an imported target. These take priority because they // are more local in scope and do not have to be globally unique. @@ -4105,15 +4311,25 @@ cmTarget* cmMakefile::FindTargetToUse(const char* name) } // Look for a target built in this directory. - if(cmTarget* t = this->FindTarget(name)) + if(cmTarget* t = this->FindTarget(name, excludeAliases)) { return t; } // Look for a target built in this project. - return this->LocalGenerator->GetGlobalGenerator()->FindTarget(0, name); + return this->LocalGenerator->GetGlobalGenerator()->FindTarget(0, name, + excludeAliases); } +//---------------------------------------------------------------------------- +bool cmMakefile::IsAlias(const char *name) +{ + if (this->AliasTargets.find(name) != this->AliasTargets.end()) + return true; + return this->GetLocalGenerator()->GetGlobalGenerator()->IsAlias(name); +} + +//---------------------------------------------------------------------------- cmGeneratorTarget* cmMakefile::FindGeneratorTargetToUse(const char* name) { cmTarget *t = this->FindTargetToUse(name); @@ -4124,6 +4340,14 @@ cmGeneratorTarget* cmMakefile::FindGeneratorTargetToUse(const char* name) bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg, bool isCustom) { + if(this->IsAlias(name.c_str())) + { + cmOStringStream e; + e << "cannot create target \"" << name + << "\" because an alias with the same name already exists."; + msg = e.str(); + return false; + } if(cmTarget* existing = this->FindTargetToUse(name.c_str())) { // The name given conflicts with an existing target. Produce an diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 74a731d5b..8bce9fd65 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -29,6 +29,9 @@ #include <cmsys/auto_ptr.hxx> #include <cmsys/RegularExpression.hxx> +#if defined(CMAKE_BUILD_WITH_CMAKE) +# include <cmsys/hash_map.hxx> +#endif class cmFunctionBlocker; class cmCommand; @@ -206,6 +209,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, @@ -336,6 +340,7 @@ public: cmTarget* AddLibrary(const char *libname, cmTarget::TargetType type, const std::vector<std::string> &srcs, bool excludeFromAll = false); + void AddAlias(const char *libname, cmTarget *tgt); #if defined(CMAKE_BUILD_WITH_CMAKE) /** @@ -535,11 +540,12 @@ public: this->GeneratorTargets = targets; } - cmTarget* FindTarget(const char* name); + cmTarget* FindTarget(const char* name, bool excludeAliases = false); /** Find a target to use in place of the given name. The target returned may be imported or built within the project. */ - cmTarget* FindTargetToUse(const char* name); + cmTarget* FindTargetToUse(const char* name, bool excludeAliases = false); + bool IsAlias(const char *name); cmGeneratorTarget* FindGeneratorTargetToUse(const char* name); /** @@ -647,7 +653,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 +671,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,10 +872,21 @@ public: { return this->IncludeDirectoriesEntries; } + std::vector<cmValueWithOrigin> GetCompileOptionsEntries() const + { + return this->CompileOptionsEntries; + } + std::vector<cmValueWithOrigin> GetCompileDefinitionsEntries() const + { + return this->CompileDefinitionsEntries; + } bool IsGeneratingBuildSystem(){ return this->GeneratingBuildSystem; } void SetGeneratingBuildSystem(){ this->GeneratingBuildSystem = true; } + std::set<cmStdString> const & GetSystemIncludeDirectories() const + { return this->SystemIncludeDirectories; } + protected: // add link libraries and directories to the target void AddGlobalLinkInformation(const char* name, cmTarget& target); @@ -890,6 +907,7 @@ protected: // libraries, classes, and executables cmTargets Targets; + std::map<std::string, cmTarget*> AliasTargets; cmGeneratorTargetsType GeneratorTargets; std::vector<cmSourceFile*> SourceFiles; @@ -919,6 +937,8 @@ protected: std::string DefineFlags; std::vector<cmValueWithOrigin> IncludeDirectoriesEntries; + std::vector<cmValueWithOrigin> CompileOptionsEntries; + std::vector<cmValueWithOrigin> CompileDefinitionsEntries; // Track the value of the computed DEFINITIONS property. void AddDefineFlag(const char*, std::string&); @@ -1022,6 +1042,26 @@ private: bool GeneratingBuildSystem; + /** + * Old version of GetSourceFileWithOutput(const char*) kept for + * backward-compatibility. It implements a linear search and support + * relative file paths. It is used as a fall back by + * GetSourceFileWithOutput(const char*). + */ + cmSourceFile *LinearGetSourceFileWithOutput(const char *cname); + + // A map for fast output to input look up. +#if defined(CMAKE_BUILD_WITH_CMAKE) + typedef cmsys::hash_map<std::string, cmSourceFile*> OutputToSourceMap; +#else + typedef std::map<std::string, cmSourceFile*> OutputToSourceMap; +#endif + OutputToSourceMap OutputToSource; + + void UpdateOutputToSourceMap(std::vector<std::string> const& outputs, + cmSourceFile* source); + void UpdateOutputToSourceMap(std::string const& output, + cmSourceFile* source); }; //---------------------------------------------------------------------------- diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index b7a454b17..3a71bd6eb 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) { @@ -341,13 +338,11 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.CMTarget = this->Target; vars.Language = linkLanguage; vars.Objects = buildObjs.c_str(); - std::string objdir = cmake::GetCMakeFilesDirectoryPostSlash(); - objdir += this->Target->GetName(); - objdir += ".dir"; - objdir = this->Convert(objdir.c_str(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL); - vars.ObjectDir = objdir.c_str(); + std::string objectDir = this->Target->GetSupportDirectory(); + objectDir = this->Convert(objectDir.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); + vars.ObjectDir = objectDir.c_str(); vars.Target = targetOutPathReal.c_str(); vars.TargetPDB = targetOutPathPDB.c_str(); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 5b4e4d774..ffe68e5b2 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(); } //---------------------------------------------------------------------------- @@ -149,12 +144,8 @@ void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules() } std::string extraFlags; - this->LocalGenerator->AppendFlags - (extraFlags,this->Target->GetProperty("STATIC_LIBRARY_FLAGS")); - std::string staticLibraryFlagsConfig = "STATIC_LIBRARY_FLAGS_"; - staticLibraryFlagsConfig += cmSystemTools::UpperCase(this->ConfigName); - this->LocalGenerator->AppendFlags - (extraFlags, this->Target->GetProperty(staticLibraryFlagsConfig.c_str())); + this->LocalGenerator->GetStaticLibraryFlags(extraFlags, + cmSystemTools::UpperCase(this->ConfigName), this->Target); this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), false); } @@ -292,14 +283,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) { @@ -585,13 +577,11 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules vars.CMTarget = this->Target; vars.Language = linkLanguage; vars.Objects = buildObjs.c_str(); - std::string objdir = cmake::GetCMakeFilesDirectoryPostSlash(); - objdir += this->Target->GetName(); - objdir += ".dir"; - objdir = this->Convert(objdir.c_str(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL); - vars.ObjectDir = objdir.c_str(); + std::string objectDir = this->Target->GetSupportDirectory(); + objectDir = this->Convert(objectDir.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); + vars.ObjectDir = objectDir.c_str(); vars.Target = targetOutPathReal.c_str(); vars.LinkLibraries = linkLibs.c_str(); vars.ObjectsQuoted = buildObjs.c_str(); @@ -727,7 +717,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 4220ae148..5e6c54822 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; } @@ -302,9 +309,8 @@ std::string cmMakefileTargetGenerator::GetDefines(const std::string &l) } // Add preprocessor definitions for this target and configuration. - this->LocalGenerator->AppendDefines - (defines, this->Target->GetCompileDefinitions( - this->LocalGenerator->ConfigurationName.c_str())); + this->LocalGenerator->AddCompileDefinitions(defines, this->Target, + this->LocalGenerator->ConfigurationName.c_str()); std::string definesString; this->LocalGenerator->JoinDefines(defines, definesString, lang); @@ -339,15 +345,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 +354,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 +529,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 +562,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 = @@ -672,7 +638,7 @@ cmMakefileTargetGenerator cmLocalGenerator::NONE, cmLocalGenerator::SHELL).c_str(); vars.Object = shellObj.c_str(); - std::string objectDir = cmSystemTools::GetFilenamePath(obj); + std::string objectDir = this->Target->GetSupportDirectory(); objectDir = this->Convert(objectDir.c_str(), cmLocalGenerator::START_OUTPUT, cmLocalGenerator::SHELL); @@ -1869,7 +1835,8 @@ void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags, lang, config); std::string includeFlags = - this->LocalGenerator->GetIncludeFlags(includes, lang, useResponseFile); + this->LocalGenerator->GetIncludeFlags(includes, this->GeneratorTarget, + lang, useResponseFile); if(includeFlags.empty()) { return; diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 2798e5462..f7a1e2e56 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 4456aa794..1fa4e95b6 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 7e48cd716..57adeba23 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; } @@ -267,7 +265,8 @@ cmNinjaNormalTargetGenerator rspcontent); } - if (this->TargetNameOut != this->TargetNameReal) { + if (this->TargetNameOut != this->TargetNameReal && + !this->GetTarget()->IsFrameworkOnApple()) { std::string cmakeCommand = this->GetLocalGenerator()->ConvertToOutputFormat( this->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND"), @@ -383,24 +382,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 +512,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() const std::string objPath = GetTarget()->GetSupportDirectory(); vars["OBJECT_DIR"] = ConvertToNinjaPath(objPath.c_str()); EnsureDirectoryExists(objPath); - // ar.exe can't handle backslashes in rsp files (implictly used by gcc) + // ar.exe can't handle backslashes in rsp files (implicitly used by gcc) std::string& linkLibraries = vars["LINK_LIBRARIES"]; std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/'); } @@ -572,32 +579,38 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() #endif } + //Get the global generator as we are going to be call WriteBuild numerous + //times in the following section + cmGlobalNinjaGenerator* globalGenerator = this->GetGlobalGenerator(); + + const std::string rspfile = std::string (cmake::GetCMakeFilesDirectoryPostSlash()) + this->GetTarget()->GetName() + ".rsp"; // Write the build statement for this target. - cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), - comment.str(), - this->LanguageLinkerRule(), - outputs, - explicitDeps, - implicitDeps, - emptyDeps, - vars, - rspfile, - commandLineLengthLimit); - - if (targetOutput != targetOutputReal) { + globalGenerator->WriteBuild(this->GetBuildFileStream(), + comment.str(), + this->LanguageLinkerRule(), + outputs, + explicitDeps, + implicitDeps, + emptyDeps, + vars, + rspfile, + commandLineLengthLimit); + + if (targetOutput != targetOutputReal && + !this->GetTarget()->IsFrameworkOnApple()) { if (targetType == cmTarget::EXECUTABLE) { - cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), + globalGenerator->WriteBuild(this->GetBuildFileStream(), "Create executable symlink " + targetOutput, - "CMAKE_SYMLINK_EXECUTABLE", - cmNinjaDeps(1, targetOutput), - cmNinjaDeps(1, targetOutputReal), - emptyDeps, - emptyDeps, - symlinkVars); + "CMAKE_SYMLINK_EXECUTABLE", + cmNinjaDeps(1, targetOutput), + cmNinjaDeps(1, targetOutputReal), + emptyDeps, + emptyDeps, + symlinkVars); } else { cmNinjaDeps symlinks; const std::string soName = this->GetTargetFilePath(this->TargetNameSO); @@ -609,30 +622,30 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() symlinks.push_back(soName); } symlinks.push_back(targetOutput); - cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), - "Create library symlink " + targetOutput, - "CMAKE_SYMLINK_LIBRARY", - symlinks, - cmNinjaDeps(1, targetOutputReal), - emptyDeps, - emptyDeps, - symlinkVars); + globalGenerator->WriteBuild(this->GetBuildFileStream(), + "Create library symlink " + targetOutput, + "CMAKE_SYMLINK_LIBRARY", + symlinks, + cmNinjaDeps(1, targetOutputReal), + emptyDeps, + emptyDeps, + symlinkVars); } } if (!this->TargetNameImport.empty()) { // Since using multiple outputs would mess up the $out variable, use an // alias for the import library. - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "Alias for import library.", - cmNinjaDeps(1, targetOutputImplib), - cmNinjaDeps(1, targetOutputReal)); + globalGenerator->WritePhonyBuild(this->GetBuildFileStream(), + "Alias for import library.", + cmNinjaDeps(1, targetOutputImplib), + cmNinjaDeps(1, targetOutputReal)); } // Add aliases for the file name and the target name. - this->GetGlobalGenerator()->AddTargetAlias(this->TargetNameOut, + globalGenerator->AddTargetAlias(this->TargetNameOut, this->GetTarget()); - this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), + globalGenerator->AddTargetAlias(this->GetTargetName(), this->GetTarget()); } @@ -643,11 +656,11 @@ void cmNinjaNormalTargetGenerator::WriteObjectLibStatement() cmNinjaDeps outputs; this->GetLocalGenerator()->AppendTargetOutputs(this->GetTarget(), outputs); cmNinjaDeps depends = this->GetObjects(); - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "Object library " - + this->GetTargetName(), - outputs, - depends); + this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(), + "Object library " + + this->GetTargetName(), + outputs, + depends); // Add aliases for the target name. this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 3fb823cb0..9c8b4810b 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -150,15 +150,19 @@ 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); std::string includeFlags = - this->LocalGenerator->GetIncludeFlags(includes, language.c_str(), + this->LocalGenerator->GetIncludeFlags(includes, this->GeneratorTarget, + language.c_str(), language == "RC" ? true : false); // full include paths for RC // needed by cmcldeps if(cmGlobalNinjaGenerator::IsMinGW()) @@ -171,36 +175,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, @@ -226,9 +202,8 @@ ComputeDefines(cmSourceFile *source, const std::string& language) } // Add preprocessor definitions for this target and configuration. - this->LocalGenerator->AppendDefines - (defines, - this->Target->GetCompileDefinitions(this->GetConfigName())); + this->LocalGenerator->AddCompileDefinitions(defines, this->Target, + this->GetConfigName()); this->LocalGenerator->AppendDefines (defines, source->GetProperty("COMPILE_DEFINITIONS")); @@ -568,12 +543,10 @@ cmNinjaTargetGenerator vars["DEP_FILE"] = objectFileName + ".d";; EnsureParentDirectoryExists(objectFileName); - std::string objectDir = cmSystemTools::GetFilenamePath(objectFileName); - objectDir = this->GetLocalGenerator()->Convert(objectDir.c_str(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL); - vars["OBJECT_DIR"] = objectDir; - + std::string objectDir = this->Target->GetSupportDirectory(); + vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat( + ConvertToNinjaPath(objectDir.c_str()).c_str(), + cmLocalGenerator::SHELL); this->SetMsvcTargetPdbVariable(vars); @@ -623,24 +596,24 @@ cmNinjaTargetGenerator sourceFileName); } - cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), - comment, - rule, - outputs, - explicitDeps, - implicitDeps, - orderOnlyDeps, - vars); + this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), + comment, + rule, + outputs, + explicitDeps, + implicitDeps, + orderOnlyDeps, + vars); if(const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) { std::vector<std::string> outputList; cmSystemTools::ExpandListArgument(objectOutputs, outputList); std::transform(outputList.begin(), outputList.end(), outputList.begin(), MapToNinjaPath()); - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "Additional output files.", - outputList, - outputs); + this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(), + "Additional output files.", + outputList, + outputs); } } @@ -701,7 +674,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/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index 9c2fd13dd..755ce6edc 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -61,11 +61,11 @@ void cmNinjaUtilityTargetGenerator::Generate() this->GetLocalGenerator()->AppendTargetDepends(this->GetTarget(), deps); if (commands.empty()) { - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "Utility command for " - + this->GetTargetName(), - outputs, - deps); + this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(), + "Utility command for " + + this->GetTargetName(), + outputs, + deps); } else { std::string command = this->GetLocalGenerator()->BuildCommandLine(commands); @@ -105,10 +105,11 @@ void cmNinjaUtilityTargetGenerator::Generate() cmNinjaDeps(1, utilCommandName), deps); - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "", - outputs, - cmNinjaDeps(1, utilCommandName)); + this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(), + "", + outputs, + cmNinjaDeps(1, utilCommandName) + ); } this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx index 42fad0742..a475c7cfa 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 01e3cbeb4..ec82b9a15 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 6e41768b0..022082519 100644 --- a/Source/cmOrderDirectories.cxx +++ b/Source/cmOrderDirectories.cxx @@ -36,8 +36,26 @@ 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) && + (std::string::npos != + splitFramework.match(3).find(splitFramework.match(2)))) + { + 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() {} @@ -305,6 +323,19 @@ void cmOrderDirectories::AddRuntimeLibrary(std::string const& fullPath, 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) && + (std::string::npos != + splitFramework.match(3).find(splitFramework.match(2)))) + { + dir = splitFramework.match(1); + } + } + if(this->ImplicitDirectories.find(dir) != this->ImplicitDirectories.end()) { diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 831e92e92..a823f0595 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,77 @@ 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,12,0, cmPolicies::WARN); + + this->DefinePolicy( + CMP0022, "CMP0022", + "INTERFACE_LINK_LIBRARIES defines the link interface.", + "CMake 2.8.11 constructed the 'link interface' of a target from " + "properties matching (IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?. " + "The modern way to specify config-sensitive content is to use generator " + "expressions and the IMPORTED_ prefix makes uniform processing of the " + "link interface with generator expressions impossible. The " + "INTERFACE_LINK_LIBRARIES target property was introduced as a " + "replacement in CMake 2.8.12. This new property is named consistently " + "with the INTERFACE_COMPILE_DEFINITIONS, INTERFACE_INCLUDE_DIRECTORIES " + "and INTERFACE_COMPILE_OPTIONS properties. For in-build targets, CMake " + "will use the INTERFACE_LINK_LIBRARIES property as the source of the " + "link interface only if policy CMP0022 is NEW. " + "When exporting a target which has this policy set to NEW, only the " + "INTERFACE_LINK_LIBRARIES property will be processed and generated for " + "the IMPORTED target by default. A new option to the install(EXPORT) " + "and export commands allows export of the old-style properties for " + "compatibility with downstream users of CMake versions older than " + "2.8.12. " + "The target_link_libraries command will no longer populate the " + "properties matching LINK_INTERFACE_LIBRARIES(_<CONFIG>)? if this policy " + "is NEW." + "\n" + "The OLD behavior for this policy is to ignore the " + "INTERFACE_LINK_LIBRARIES property for in-build targets. " + "The NEW behavior for this policy is to use the INTERFACE_LINK_LIBRARIES " + "property for in-build targets, and ignore the old properties matching " + "(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?.", + 2,8,12,0, cmPolicies::WARN); + + this->DefinePolicy( + CMP0023, "CMP0023", + "Plain and keyword target_link_libraries signatures cannot be mixed.", + "CMake 2.8.12 introduced the target_link_libraries signature using " + "the PUBLIC, PRIVATE, and INTERFACE keywords to generalize the " + "LINK_PUBLIC and LINK_PRIVATE keywords introduced in CMake 2.8.7. " + "Use of signatures with any of these keywords sets the link interface " + "of a target explicitly, even if empty. " + "This produces confusing behavior when used in combination with the " + "historical behavior of the plain target_link_libraries signature. " + "For example, consider the code:\n" + " target_link_libraries(mylib A)\n" + " target_link_libraries(mylib PRIVATE B)\n" + "After the first line the link interface has not been set explicitly " + "so CMake would use the link implementation, A, as the link interface. " + "However, the second line sets the link interface to empty. " + "In order to avoid this subtle behavior CMake now prefers to disallow " + "mixing the plain and keyword signatures of target_link_libraries for " + "a single target." + "\n" + "The OLD behavior for this policy is to allow keyword and plain " + "target_link_libraries signatures to be mixed. " + "The NEW behavior for this policy is to not to allow mixing of the " + "keyword and plain signatures.", + 2,8,12,0, cmPolicies::WARN); } cmPolicies::~cmPolicies() @@ -770,7 +842,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 c11af0714..5b843a9ad 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -70,6 +70,10 @@ 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 + CMP0022, ///< INTERFACE_LINK_LIBRARIES defines the link interface + CMP0023, ///< Disallow mixing keyword and plain tll signatures /** \brief Always the last entry. * diff --git a/Source/cmProjectCommand.h b/Source/cmProjectCommand.h index a53cb3fb8..9547c4c8f 100644 --- a/Source/cmProjectCommand.h +++ b/Source/cmProjectCommand.h @@ -71,7 +71,13 @@ public: "language \"NONE\" all checks for any language can be disabled. " "If a variable exists called CMAKE_PROJECT_<projectName>_INCLUDE, " "the file pointed to by that variable will be included as the last step " - "of the project command."; + "of the project command." + "\n" + "The top-level CMakeLists.txt file for a project must contain a " + "literal, direct call to the project() command; loading one through " + "the include() command is not sufficient. " + "If no such call exists CMake will implicitly add one to the top that " + "enables the default languages (C and CXX)."; } cmTypeMacro(cmProjectCommand, cmCommand); diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index a1fa31f2a..93e39abeb 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -152,10 +152,46 @@ 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; + } + + std::set<std::string> defines; + localGen->AddCompileDefinitions(defines, target, config); + + sep = ""; + for(std::set<std::string>::const_iterator defIt = defines.begin(); + defIt != defines.end(); + ++defIt) + { + defs += sep; + sep = ";"; + defs += *defIt; + } +} + +void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) +{ + cmMakefile* makefile = target->GetMakefile(); const char* targetName = target->GetName(); bool relaxedMode = makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE"); @@ -175,6 +211,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 +225,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")) { @@ -219,8 +257,18 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) automocTargetName.c_str(), true, workingDirectory.c_str(), depends, commandLines, false, automocComment.c_str()); - // inherit FOLDER property from target (#13688) - copyTargetProperty(automocTarget, target, "FOLDER"); + // Set target folder + const char* automocFolder = makefile->GetCMakeInstance()->GetProperty( + "AUTOMOC_TARGETS_FOLDER"); + if (automocFolder && *automocFolder) + { + automocTarget->SetProperty("FOLDER", automocFolder); + } + else + { + // inherit FOLDER property from target (#13688) + copyTargetProperty(automocTarget, target, "FOLDER"); + } target->AddUtility(automocTargetName.c_str()); } @@ -263,36 +311,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 +320,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 +328,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 +418,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 +498,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 +507,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 +524,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 +845,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 +1019,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 01b68fc54..ebeeb0eee 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/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx index cc10840fd..42078605a 100644 --- a/Source/cmSetPropertyCommand.cxx +++ b/Source/cmSetPropertyCommand.cxx @@ -84,12 +84,14 @@ bool cmSetPropertyCommand { doing = DoingNone; this->AppendMode = true; + this->Remove = false; this->AppendAsString = false; } else if(*arg == "APPEND_STRING") { doing = DoingNone; this->AppendMode = true; + this->Remove = false; this->AppendAsString = true; } else if(doing == DoingNames) @@ -160,7 +162,7 @@ bool cmSetPropertyCommand::HandleGlobalMode() } if(this->AppendMode) { - cm->AppendProperty(name, value, this->AppendAsString); + cm->AppendProperty(name, value ? value : "", this->AppendAsString); } else { @@ -226,7 +228,7 @@ bool cmSetPropertyCommand::HandleDirectoryMode() } if(this->AppendMode) { - mf->AppendProperty(name, value, this->AppendAsString); + mf->AppendProperty(name, value ? value : "", this->AppendAsString); } else { @@ -242,6 +244,11 @@ bool cmSetPropertyCommand::HandleTargetMode() for(std::set<cmStdString>::const_iterator ni = this->Names.begin(); ni != this->Names.end(); ++ni) { + if (this->Makefile->IsAlias(ni->c_str())) + { + this->SetError("can not be used on an ALIAS target."); + return false; + } if(cmTarget* target = this->Makefile->FindTargetToUse(ni->c_str())) { // Handle the current target. diff --git a/Source/cmSetTargetPropertiesCommand.cxx b/Source/cmSetTargetPropertiesCommand.cxx index a2b50a8ef..78ef393cc 100644 --- a/Source/cmSetTargetPropertiesCommand.cxx +++ b/Source/cmSetTargetPropertiesCommand.cxx @@ -72,6 +72,11 @@ bool cmSetTargetPropertiesCommand int i; for(i = 0; i < numFiles; ++i) { + if (this->Makefile->IsAlias(args[i].c_str())) + { + this->SetError("can not be used on an ALIAS target."); + return false; + } bool ret = cmSetTargetPropertiesCommand::SetOneTarget (args[i].c_str(),propertyPairs,this->Makefile); if (!ret) diff --git a/Source/cmSetTargetPropertiesCommand.h b/Source/cmSetTargetPropertiesCommand.h index 9dd7848d3..cf9c19350 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 1d4b0c8b4..8bb7d96f5 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 e49edd878..68ba13f62 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 802e0b850..f584cfdbf 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 0cfe7722d..e497b4642 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 67f302391..9ec49382a 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -638,6 +638,12 @@ bool cmSystemTools::RunSingleCommand(std::vector<cmStdString>const& command, cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); } + if (outputflag == OUTPUT_PASSTHROUGH) + { + cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1); + cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1); + } + cmsysProcess_SetTimeout(cp, timeout); cmsysProcess_Execute(cp); @@ -645,7 +651,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<cmStdString>const& command, char* data; int length; int pipe; - if ( output || outputflag != OUTPUT_NONE ) + if(outputflag != OUTPUT_PASSTHROUGH && (output || outputflag != OUTPUT_NONE)) { while((pipe = cmsysProcess_WaitForData(cp, &data, &length, 0)) > 0) { @@ -1594,6 +1600,40 @@ std::string cmSystemTools::RelativePath(const char* local, const char* remote) return cmsys::SystemTools::RelativePath(local, remote); } +std::string cmSystemTools::CollapseCombinedPath(std::string const& dir, + std::string const& file) +{ + if(dir.empty() || dir == ".") + { + return file; + } + + std::vector<std::string> dirComponents; + std::vector<std::string> fileComponents; + cmSystemTools::SplitPath(dir.c_str(), dirComponents); + cmSystemTools::SplitPath(file.c_str(), fileComponents); + + if(fileComponents.empty()) + { + return dir; + } + if(fileComponents[0] != "") + { + // File is not a relative path. + return file; + } + + std::vector<std::string>::iterator i = fileComponents.begin()+1; + while(i != fileComponents.end() && *i == ".." && dirComponents.size() > 1) + { + ++i; // Remove ".." file component. + dirComponents.pop_back(); // Remove last dir component. + } + + dirComponents.insert(dirComponents.end(), i, fileComponents.end()); + return cmSystemTools::JoinPath(dirComponents); +} + #ifdef CMAKE_BUILD_WITH_CMAKE //---------------------------------------------------------------------- bool cmSystemTools::UnsetEnv(const char* value) @@ -1662,6 +1702,7 @@ cmSystemTools::SaveRestoreEnvironment::~SaveRestoreEnvironment() void cmSystemTools::EnableVSConsoleOutput() { +#ifdef _WIN32 // Visual Studio 8 2005 (devenv.exe or VCExpress.exe) will not // display output to the console unless this environment variable is // set. We need it to capture the output of these build tools. @@ -1669,8 +1710,15 @@ void cmSystemTools::EnableVSConsoleOutput() // either of these executables where NAME is created with // CreateNamedPipe. This would bypass the internal buffering of the // output and allow it to be captured on the fly. -#ifdef _WIN32 cmSystemTools::PutEnv("vsconsoleoutput=1"); + +# ifdef CMAKE_BUILD_WITH_CMAKE + // VS sets an environment variable to tell MS tools like "cl" to report + // output through a backdoor pipe instead of stdout/stderr. Unset the + // environment variable to close this backdoor for any path of process + // invocations that passes through CMake so we can capture the output. + cmSystemTools::UnsetEnv("VS_UNICODE_OUTPUT"); +# endif #endif } @@ -1951,7 +1999,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 +2461,38 @@ 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; + if(!RunSingleCommand(cmds, &output, 0, 0, OUTPUT_NONE)) + { + cmds.insert(cmds.begin(), "-r"); + cmds.insert(cmds.begin(), "xcrun"); + if(!RunSingleCommand(cmds, &output, 0, 0, OUTPUT_NONE)) + { + return false; + } + } + + 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 +2739,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 0b2def216..9d7dae9ef 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). @@ -211,7 +211,7 @@ public: * user-viewable output from the program being run will be generated. * OUTPUT_MERGE is the legacy behaviour where stdout and stderr are merged * into stdout. OUTPUT_NORMAL passes through the output to stdout/stderr as - * it was received. + * it was received. OUTPUT_PASSTHROUGH passes through the original handles. * * If timeout is specified, the command will be terminated after * timeout expires. Timeout is specified in seconds. @@ -230,7 +230,8 @@ public: { OUTPUT_NONE = 0, OUTPUT_MERGE, - OUTPUT_NORMAL + OUTPUT_NORMAL, + OUTPUT_PASSTHROUGH }; static bool RunSingleCommand(const char* command, std::string* output = 0, int* retVal = 0, const char* dir = 0, @@ -274,7 +275,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, @@ -365,6 +366,12 @@ public: */ static std::string RelativePath(const char* local, const char* remote); + /** Joins two paths while collapsing x/../ parts + * For example CollapseCombinedPath("a/b/c", "../../d") results in "a/d" + */ + static std::string CollapseCombinedPath(std::string const& dir, + std::string const& file); + #ifdef CMAKE_BUILD_WITH_CMAKE /** Remove an environment variable */ static bool UnsetEnv(const char* value); @@ -439,6 +446,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 d14bfcaf6..4ba6c1981 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -83,10 +83,12 @@ class cmTargetInternals public: cmTargetInternals() { + this->PolicyWarnedCMP0022 = false; this->SourceFileFlagsConstructed = false; } cmTargetInternals(cmTargetInternals const& r) { + this->PolicyWarnedCMP0022 = false; this->SourceFileFlagsConstructed = false; // Only some of these entries are part of the object state. // Others not copied here are result caches. @@ -109,6 +111,7 @@ public: typedef std::map<TargetConfigPair, OptionalLinkInterface> LinkInterfaceMapType; LinkInterfaceMapType LinkInterfaceMap; + bool PolicyWarnedCMP0022; typedef std::map<cmStdString, cmTarget::OutputInfo> OutputInfoMapType; OutputInfoMapType OutputInfoMap; @@ -130,31 +133,37 @@ 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<TargetPropertyEntry*> CompileDefinitionsEntries; + std::vector<cmValueWithOrigin> LinkInterfacePropertyEntries; - std::map<std::string, std::vector<IncludeDirectoriesEntry*> > + std::map<std::string, std::vector<TargetPropertyEntry*> > CachedLinkInterfaceIncludeDirectoriesEntries; - std::map<std::string, std::string> CachedLinkInterfaceCompileDefinitions; + std::map<std::string, std::vector<TargetPropertyEntry*> > + CachedLinkInterfaceCompileOptionsEntries; + std::map<std::string, std::vector<TargetPropertyEntry*> > + CachedLinkInterfaceCompileDefinitionsEntries; 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 +176,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,17 +189,22 @@ void deleteAndClear( //---------------------------------------------------------------------------- cmTargetInternals::~cmTargetInternals() { - deleteAndClear(CachedLinkInterfaceIncludeDirectoriesEntries); + deleteAndClear(this->CachedLinkInterfaceIncludeDirectoriesEntries); + deleteAndClear(this->CachedLinkInterfaceCompileOptionsEntries); + deleteAndClear(this->CachedLinkInterfaceCompileDefinitionsEntries); } //---------------------------------------------------------------------------- cmTarget::cmTarget() { +#define INITIALIZE_TARGET_POLICY_MEMBER(POLICY) \ + this->PolicyStatus ## POLICY = cmPolicies::WARN; + + CM_FOR_EACH_TARGET_POLICY(INITIALIZE_TARGET_POLICY_MEMBER) + +#undef INITIALIZE_TARGET_POLICY_MEMBER + this->Makefile = 0; - this->PolicyStatusCMP0003 = cmPolicies::WARN; - this->PolicyStatusCMP0004 = cmPolicies::WARN; - this->PolicyStatusCMP0008 = cmPolicies::WARN; - this->PolicyStatusCMP0020 = cmPolicies::WARN; this->LinkLibrariesAnalyzed = false; this->HaveInstallRule = false; this->DLLPlatform = false; @@ -198,6 +212,8 @@ cmTarget::cmTarget() this->IsImportedTarget = false; this->BuildInterfaceIncludesAppended = false; this->DebugIncludesDone = false; + this->DebugCompileOptionsDone = false; + this->DebugCompileDefinitionsDone = false; } //---------------------------------------------------------------------------- @@ -229,7 +245,9 @@ void cmTarget::DefineProperties(cmake *cm) "AUTOMOC_MOC_OPTIONS property.\n" "By setting the CMAKE_AUTOMOC_RELAXED_MODE variable to TRUE the rules " "for searching the files which will be processed by moc can be relaxed. " - "See the documentation for this variable for more details."); + "See the documentation for this variable for more details.\n" + "The global property AUTOMOC_TARGETS_FOLDER can be used to group the " + "automoc targets together in an IDE, e.g. in MSVS."); cm->DefineProperty ("AUTOMOC_MOC_OPTIONS", cmProperty::TARGET, @@ -285,6 +303,30 @@ 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->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->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 +334,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 @@ -438,7 +480,7 @@ void cmTarget::DefineProperties(cmake *cm) "imported library. " "The list " "should be disjoint from the list of interface libraries in the " - "IMPORTED_LINK_INTERFACE_LIBRARIES property. On platforms requiring " + "INTERFACE_LINK_LIBRARIES property. On platforms requiring " "dependent shared libraries to be found at link time CMake uses this " "list to add appropriate files or paths to the link command line. " "Ignored for non-imported targets."); @@ -459,7 +501,10 @@ void cmTarget::DefineProperties(cmake *cm) "The libraries will be included on the link line for the target. " "Unlike the LINK_INTERFACE_LIBRARIES property, this property applies " "to all imported target types, including STATIC libraries. " - "This property is ignored for non-imported targets."); + "This property is ignored for non-imported targets.\n" + "This property is ignored if the target also has a non-empty " + "INTERFACE_LINK_LIBRARIES property.\n" + "This property is deprecated. Use INTERFACE_LINK_LIBRARIES instead."); cm->DefineProperty ("IMPORTED_LINK_INTERFACE_LIBRARIES_<CONFIG>", cmProperty::TARGET, @@ -467,7 +512,10 @@ void cmTarget::DefineProperties(cmake *cm) "Configuration names correspond to those provided by the project " "from which the target is imported. " "If set, this property completely overrides the generic property " - "for the named configuration."); + "for the named configuration.\n" + "This property is ignored if the target also has a non-empty " + "INTERFACE_LINK_LIBRARIES property.\n" + "This property is deprecated. Use INTERFACE_LINK_LIBRARIES instead."); cm->DefineProperty ("IMPORTED_LINK_INTERFACE_LANGUAGES", cmProperty::TARGET, @@ -700,7 +748,11 @@ void cmTarget::DefineProperties(cmake *cm) "file providing the program entry point (main). " "If not set, the language with the highest linker preference " "value is the default. " - "See documentation of CMAKE_<LANG>_LINKER_PREFERENCE variables."); + "See documentation of CMAKE_<LANG>_LINKER_PREFERENCE variables." + "\n" + "If this property is not set by the user, it will be calculated at " + "generate-time by CMake." + ); cm->DefineProperty ("LOCATION", cmProperty::TARGET, @@ -783,7 +835,10 @@ void cmTarget::DefineProperties(cmake *cm) "This property is initialized by the value of the variable " "CMAKE_LINK_INTERFACE_LIBRARIES if it is set when a target is " "created. " - "This property is ignored for STATIC libraries."); + "This property is ignored for STATIC libraries.\n" + "This property is overridden by the INTERFACE_LINK_LIBRARIES property if " + "policy CMP0022 is NEW.\n" + "This property is deprecated. Use INTERFACE_LINK_LIBRARIES instead."); cm->DefineProperty ("LINK_INTERFACE_LIBRARIES_<CONFIG>", cmProperty::TARGET, @@ -791,7 +846,23 @@ void cmTarget::DefineProperties(cmake *cm) "This is the configuration-specific version of " "LINK_INTERFACE_LIBRARIES. " "If set, this property completely overrides the generic property " - "for the named configuration."); + "for the named configuration.\n" + "This property is overridden by the INTERFACE_LINK_LIBRARIES property if " + "policy CMP0022 is NEW.\n" + "This property is deprecated. Use INTERFACE_LINK_LIBRARIES instead."); + + cm->DefineProperty + ("INTERFACE_LINK_LIBRARIES", cmProperty::TARGET, + "List public interface libraries for a library.", + "This property contains the list of transitive link dependencies. " + "When the target is linked into another target the libraries " + "listed (and recursively their link interface libraries) will be " + "provided to the other target also. " + "This property is overridden by the LINK_INTERFACE_LIBRARIES or " + "LINK_INTERFACE_LIBRARIES_<CONFIG> property if " + "policy CMP0022 is OLD or unset.\n" + "\n" + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); cm->DefineProperty ("INTERFACE_INCLUDE_DIRECTORIES", cmProperty::TARGET, @@ -805,6 +876,16 @@ void cmTarget::DefineProperties(cmake *cm) CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); cm->DefineProperty + ("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", cmProperty::TARGET, + "List of public system include directories for a library.", + "Targets may populate this property to publish the include directories " + "which contain system headers, and therefore should not result in " + "compiler warnings. Consuming targets will then mark the same include " + "directories as system headers." + "\n" + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); + + cm->DefineProperty ("INTERFACE_COMPILE_DEFINITIONS", cmProperty::TARGET, "List of public compile definitions for a library.", "Targets may populate this property to publish the compile definitions " @@ -867,6 +948,18 @@ void cmTarget::DefineProperties(cmake *cm) "OSX_ARCHITECTURES."); cm->DefineProperty + ("NAME", cmProperty::TARGET, + "Logical name for the target.", + "Read-only logical name for the target as used by CMake."); + + 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 " @@ -879,6 +972,12 @@ void cmTarget::DefineProperties(cmake *cm) "This is the configuration-specific version of OUTPUT_NAME."); cm->DefineProperty + ("ALIASED_TARGET", cmProperty::TARGET, + "Name of target aliased by this target.", + "If this is an ALIAS target, this property contains the name of the " + "target aliased."); + + cm->DefineProperty ("<CONFIG>_OUTPUT_NAME", cmProperty::TARGET, "Old per-configuration target file base name.", "This is a configuration-specific version of OUTPUT_NAME. " @@ -886,9 +985,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 +1015,26 @@ void cmTarget::DefineProperties(cmake *cm) "(such as \"lib\") on a library name."); cm->DefineProperty + ("<LANG>_VISIBILITY_PRESET", cmProperty::TARGET, + "Value for symbol visibility compile flags", + "The <LANG>_VISIBILITY_PRESET property determines the value passed in " + "a visibility related compile option, such as -fvisibility= for <LANG>. " + "This property only has an affect for libraries and executables with " + "exports. This property is initialized by the value of the variable " + "CMAKE_<LANG>_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 +1173,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 +1211,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 +1275,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 +1293,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 +1375,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 +1444,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 +1535,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" @@ -1482,7 +1620,7 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->IsApple = this->Makefile->IsOn("APPLE"); // Setup default property values. - this->SetPropertyDefault("INSTALL_NAME_DIR", ""); + this->SetPropertyDefault("INSTALL_NAME_DIR", 0); this->SetPropertyDefault("INSTALL_RPATH", ""); this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF"); this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF"); @@ -1501,6 +1639,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; @@ -1552,6 +1692,29 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->InsertInclude(*it); } + const std::set<cmStdString> parentSystemIncludes = + this->Makefile->GetSystemIncludeDirectories(); + + for (std::set<cmStdString>::const_iterator it + = parentSystemIncludes.begin(); + it != parentSystemIncludes.end(); ++it) + { + this->SystemIncludeDirectories.insert(*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) { @@ -1560,14 +1723,13 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("POSITION_INDEPENDENT_CODE", 0); // Record current policies for later use. - this->PolicyStatusCMP0003 = - this->Makefile->GetPolicyStatus(cmPolicies::CMP0003); - this->PolicyStatusCMP0004 = - this->Makefile->GetPolicyStatus(cmPolicies::CMP0004); - this->PolicyStatusCMP0008 = - this->Makefile->GetPolicyStatus(cmPolicies::CMP0008); - this->PolicyStatusCMP0020 = - this->Makefile->GetPolicyStatus(cmPolicies::CMP0020); +#define CAPTURE_TARGET_POLICY(POLICY) \ + this->PolicyStatus ## POLICY = \ + this->Makefile->GetPolicyStatus(cmPolicies::POLICY); + + CM_FOR_EACH_TARGET_POLICY(CAPTURE_TARGET_POLICY) + +#undef CAPTURE_TARGET_POLICY } //---------------------------------------------------------------------------- @@ -1669,11 +1831,17 @@ bool cmTarget::IsCFBundleOnApple() } //---------------------------------------------------------------------------- +bool cmTarget::IsBundleOnApple() +{ + return this->IsFrameworkOnApple() || this->IsAppBundleOnApple() || + this->IsCFBundleOnApple(); +} + +//---------------------------------------------------------------------------- class cmTargetTraceDependencies { public: - cmTargetTraceDependencies(cmTarget* target, cmTargetInternals* internal, - const char* vsProjectFile); + cmTargetTraceDependencies(cmTarget* target, cmTargetInternals* internal); void Trace(); private: cmTarget* Target; @@ -1697,8 +1865,7 @@ private: //---------------------------------------------------------------------------- cmTargetTraceDependencies -::cmTargetTraceDependencies(cmTarget* target, cmTargetInternals* internal, - const char* vsProjectFile): +::cmTargetTraceDependencies(cmTarget* target, cmTargetInternals* internal): Target(target), Internal(internal) { // Convenience. @@ -1715,13 +1882,6 @@ cmTargetTraceDependencies this->QueueSource(*si); } - // Queue the VS project file to check dependencies on the rule to - // generate it. - if(vsProjectFile) - { - this->FollowName(vsProjectFile); - } - // Queue pre-build, pre-link, and post-build rule dependencies. this->CheckCustomCommands(this->Target->GetPreBuildCommands()); this->CheckCustomCommands(this->Target->GetPreLinkCommands()); @@ -1940,7 +2100,7 @@ cmTargetTraceDependencies } //---------------------------------------------------------------------------- -void cmTarget::TraceDependencies(const char* vsProjectFile) +void cmTarget::TraceDependencies() { // CMake-generated targets have no dependencies to trace. Normally tracing // would find nothing anyway, but when building CMake itself the "install" @@ -1952,7 +2112,7 @@ void cmTarget::TraceDependencies(const char* vsProjectFile) } // Use a helper object to trace the dependencies. - cmTargetTraceDependencies tracer(this, this->Internal.Get(), vsProjectFile); + cmTargetTraceDependencies tracer(this, this->Internal.Get()); tracer.Trace(); } @@ -2174,8 +2334,10 @@ void cmTarget::MergeLinkLibraries( cmMakefile& mf, i += this->PrevLinkedLibraries.size(); for( ; i != libs.end(); ++i ) { - // We call this so that the dependencies get written to the cache + // This is equivalent to the target_link_libraries plain signature. this->AddLinkLibrary( mf, selfname, i->first.c_str(), i->second ); + this->AppendProperty("INTERFACE_LINK_LIBRARIES", + this->GetDebugGeneratorExpressions(i->first.c_str(), i->second).c_str()); } this->PrevLinkedLibraries = libs; } @@ -2331,6 +2493,63 @@ static std::string targetNameGenex(const char *lib) } //---------------------------------------------------------------------------- +bool cmTarget::PushTLLCommandTrace(TLLSignature signature) +{ + bool ret = true; + if (!this->TLLCommands.empty()) + { + if (this->TLLCommands.back().first != signature) + { + ret = false; + } + } + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + this->TLLCommands.push_back(std::make_pair(signature, lfbt)); + return ret; +} + +//---------------------------------------------------------------------------- +void cmTarget::GetTllSignatureTraces(cmOStringStream &s, + TLLSignature sig) const +{ + std::vector<cmListFileBacktrace> sigs; + typedef std::vector<std::pair<TLLSignature, cmListFileBacktrace> > Container; + for(Container::const_iterator it = this->TLLCommands.begin(); + it != this->TLLCommands.end(); ++it) + { + if (it->first == sig) + { + sigs.push_back(it->second); + } + } + if (!sigs.empty()) + { + const char *sigString + = (sig == cmTarget::KeywordTLLSignature ? "keyword" + : "plain"); + s << "The uses of the " << sigString << " signature are here:\n"; + std::set<cmStdString> emitted; + for(std::vector<cmListFileBacktrace>::const_iterator it = sigs.begin(); + it != sigs.end(); ++it) + { + cmListFileBacktrace::const_iterator i = it->begin(); + if(i != it->end()) + { + cmListFileContext const& lfc = *i; + cmOStringStream line; + line << " * " << (lfc.Line? "": " in ") << lfc << std::endl; + if (emitted.insert(line.str()).second) + { + s << line.str(); + } + ++i; + } + } + } +} + +//---------------------------------------------------------------------------- void cmTarget::AddLinkLibrary(cmMakefile& mf, const char *target, const char* lib, LinkLibraryType llt) @@ -2407,6 +2626,61 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, //---------------------------------------------------------------------------- void +cmTarget::AddSystemIncludeDirectories(const std::set<cmStdString> &incs) +{ + for(std::set<cmStdString>::const_iterator li = incs.begin(); + li != incs.end(); ++li) + { + this->SystemIncludeDirectories.insert(*li); + } +} + +//---------------------------------------------------------------------------- +void +cmTarget::AddSystemIncludeDirectories(const std::vector<std::string> &incs) +{ + for(std::vector<std::string>::const_iterator li = incs.begin(); + li != incs.end(); ++li) + { + this->SystemIncludeDirectories.insert(*li); + } +} + +//---------------------------------------------------------------------------- +void cmTarget::FinalizeSystemIncludeDirectories() +{ + for (std::vector<cmValueWithOrigin>::const_iterator + it = this->Internal->LinkInterfacePropertyEntries.begin(), + end = this->Internal->LinkInterfacePropertyEntries.end(); + it != end; ++it) + { + { + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = + ge.Parse(it->Value); + std::string targetName = cge->Evaluate(this->Makefile, 0, + false, this, 0, 0); + if (!this->Makefile->FindTargetToUse(targetName.c_str())) + { + continue; + } + } + std::string includeGenex = "$<TARGET_PROPERTY:" + + it->Value + ",INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>"; + if (cmGeneratorExpression::Find(it->Value) != std::string::npos) + { + // Because it->Value is a generator expression, ensure that it + // evaluates to the non-empty string before being used in the + // TARGET_PROPERTY expression. + includeGenex = "$<$<BOOL:" + it->Value + ">:" + includeGenex + ">"; + } + this->SystemIncludeDirectories.insert(includeGenex); + } +} + +//---------------------------------------------------------------------------- +void cmTarget::AnalyzeLibDependencies( const cmMakefile& mf ) { // There are two key parts of the dependency analysis: (1) @@ -2491,8 +2765,6 @@ cmTarget::AnalyzeLibDependencies( const cmMakefile& mf ) } } - typedef std::vector< std::string > LinkLine; - // The dependency map. DependencyMap dep_map; @@ -2707,7 +2979,13 @@ void cmTarget::SetProperty(const char* prop, const char* value) { return; } - + if (strcmp(prop, "NAME") == 0) + { + cmOStringStream e; + e << "NAME property is read-only\n"; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); + return; + } if(strcmp(prop,"INCLUDE_DIRECTORIES") == 0) { cmListFileBacktrace lfbt; @@ -2716,19 +2994,49 @@ 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,"COMPILE_DEFINITIONS") == 0) + { + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmGeneratorExpression ge(lfbt); + deleteAndClear(this->Internal->CompileDefinitionsEntries); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); + this->Internal->CompileDefinitionsEntries.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 } @@ -2744,13 +3052,46 @@ void cmTarget::AppendProperty(const char* prop, const char* value, { return; } + if (strcmp(prop, "NAME") == 0) + { + cmOStringStream e; + e << "NAME property is read-only\n"; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); + return; + } if(strcmp(prop,"INCLUDE_DIRECTORIES") == 0) { cmListFileBacktrace lfbt; 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,"COMPILE_DEFINITIONS") == 0) + { + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmGeneratorExpression ge(lfbt); + this->Internal->CompileDefinitionsEntries.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 +3102,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 +3111,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 +3167,45 @@ 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))); +} + +//---------------------------------------------------------------------------- +void cmTarget::InsertCompileDefinition(const cmValueWithOrigin &entry, + bool before) +{ + cmGeneratorExpression ge(entry.Backtrace); + + std::vector<cmTargetInternals::TargetPropertyEntry*>::iterator position + = before ? this->Internal->CompileDefinitionsEntries.begin() + : this->Internal->CompileDefinitionsEntries.end(); + + this->Internal->CompileDefinitionsEntries.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 +3213,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,15 +3265,45 @@ 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()); - return; + " \"" << *li << "\""; + } + 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()); + if (messageType == cmake::FATAL_ERROR) + { + return; + } } } @@ -2905,7 +3324,7 @@ static void processIncludeDirectories(cmTarget *tgt, } if (cacheIncludes) { - (*it)->CachedIncludes = entryIncludes; + (*it)->CachedEntries = entryIncludes; } if (!usedIncludes.empty()) { @@ -2925,8 +3344,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 +3380,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,9 +3410,37 @@ 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)); } + + if(this->Makefile->IsOn("APPLE")) + { + LinkImplementation const* impl = this->GetLinkImplementation(config, + this); + for(std::vector<std::string>::const_iterator + it = impl->Libraries.begin(); + it != impl->Libraries.end(); ++it) + { + std::string libDir = cmSystemTools::CollapseFullPath(it->c_str()); + + static cmsys::RegularExpression + frameworkCheck("(.*\\.framework)(/Versions/[^/]+)?/[^/]+$"); + if(!frameworkCheck.find(libDir)) + { + continue; + } + + libDir = frameworkCheck.match(1); + + cmGeneratorExpression ge(lfbt); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = + ge.Parse(libDir.c_str()); + this->Internal + ->CachedLinkInterfaceIncludeDirectoriesEntries[configString] + .push_back(new cmTargetInternals::TargetPropertyEntry(cge)); + } + } } processIncludeDirectories(this, @@ -3019,90 +3466,294 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config) } //---------------------------------------------------------------------------- -std::string cmTarget::GetCompileDefinitions(const char *config) +static void processCompileOptionsInternal(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, const char *logName) { - const char *configProp = 0; - if (config) + cmMakefile *mf = tgt->GetMakefile(); + + for (std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator + it = entries.begin(), end = entries.end(); it != end; ++it) { - std::string configPropName; - configPropName = "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); - configProp = this->GetProperty(configPropName.c_str()); + 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 ") + logName + + std::string(" for target ") + + tgt->GetName() + ":\n" + + usedOptions, (*it)->ge->GetBacktrace()); + } } +} + +//---------------------------------------------------------------------------- +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) +{ + processCompileOptionsInternal(tgt, entries, options, uniqueOptions, + dagChecker, config, debugOptions, "options"); +} - const char *noconfigProp = this->GetProperty("COMPILE_DEFINITIONS"); +//---------------------------------------------------------------------------- +void cmTarget::GetCompileOptions(std::vector<std::string> &result, + const char *config) +{ + std::set<std::string> uniqueOptions; cmListFileBacktrace lfbt; + cmGeneratorExpressionDAGChecker dagChecker(lfbt, - this->GetName(), - "COMPILE_DEFINITIONS", 0, 0); + this->GetName(), + "COMPILE_OPTIONS", 0, 0); - std::string defsString = (noconfigProp ? noconfigProp : ""); - if (configProp && noconfigProp) + std::vector<std::string> debugProperties; + const char *debugProp = + this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); + if (debugProp) { - defsString += ";"; + cmSystemTools::ExpandListArgument(debugProp, debugProperties); } - defsString += (configProp ? configProp : ""); - cmGeneratorExpression ge(lfbt); - std::string result = ge.Parse(defsString.c_str())->Evaluate(this->Makefile, - config, - false, - this, - &dagChecker); - - std::vector<std::string> libs; - this->GetDirectLinkLibraries(config, libs, this); + bool debugOptions = !this->DebugCompileOptionsDone + && std::find(debugProperties.begin(), + debugProperties.end(), + "COMPILE_OPTIONS") + != debugProperties.end(); - if (libs.empty()) + if (this->Makefile->IsGeneratingBuildSystem()) { - return result; + this->DebugCompileOptionsDone = true; } - std::string sep; - std::string depString; - for (std::vector<std::string>::const_iterator it = libs.begin(); - it != libs.end(); ++it) + processCompileOptions(this, + this->Internal->CompileOptionsEntries, + result, + uniqueOptions, + &dagChecker, + config, + debugOptions); + + std::string configString = config ? config : ""; + if (!this->Internal->CacheLinkInterfaceCompileOptionsDone[configString]) { - if ((cmGeneratorExpression::IsValidTargetName(it->c_str()) - || cmGeneratorExpression::Find(it->c_str()) != std::string::npos) - && this->Makefile->FindTargetToUse(it->c_str())) + for (std::vector<cmValueWithOrigin>::const_iterator + it = this->Internal->LinkInterfacePropertyEntries.begin(), + end = this->Internal->LinkInterfacePropertyEntries.end(); + it != end; ++it) { - depString += sep + "$<TARGET_PROPERTY:" - + *it + ",INTERFACE_COMPILE_DEFINITIONS>"; - sep = ";"; + { + 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)); } } - std::string configString = config ? config : ""; - if (!this->Internal->CacheLinkInterfaceCompileDefinitionsDone[configString]) + 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; + } +} + +//---------------------------------------------------------------------------- +static void processCompileDefinitions(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) +{ + processCompileOptionsInternal(tgt, entries, options, uniqueOptions, + dagChecker, config, debugOptions, + "definitions"); +} + +//---------------------------------------------------------------------------- +void cmTarget::GetCompileDefinitions(std::vector<std::string> &list, + const char *config) +{ + std::set<std::string> uniqueOptions; + cmListFileBacktrace lfbt; + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + "COMPILE_DEFINITIONS", 0, 0); + + std::vector<std::string> debugProperties; + const char *debugProp = + this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); + if (debugProp) { - cmGeneratorExpression ge2(lfbt); - cmsys::auto_ptr<cmCompiledGeneratorExpression> cge2 = - ge2.Parse(depString); - this->Internal->CachedLinkInterfaceCompileDefinitions[configString] = - cge2->Evaluate(this->Makefile, - config, - false, - this, - &dagChecker); + cmSystemTools::ExpandListArgument(debugProp, debugProperties); } - if (!this->Internal->CachedLinkInterfaceCompileDefinitions[configString] - .empty()) + + bool debugDefines = !this->DebugCompileDefinitionsDone + && std::find(debugProperties.begin(), + debugProperties.end(), + "COMPILE_DEFINITIONS") + != debugProperties.end(); + + if (this->Makefile->IsGeneratingBuildSystem()) + { + this->DebugCompileDefinitionsDone = true; + } + + processCompileDefinitions(this, + this->Internal->CompileDefinitionsEntries, + list, + uniqueOptions, + &dagChecker, + config, + debugDefines); + + std::string configString = config ? config : ""; + if (!this->Internal->CacheLinkInterfaceCompileDefinitionsDone[configString]) { - result += (result.empty() ? "" : ";") - + this->Internal->CachedLinkInterfaceCompileDefinitions[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 defsGenex = "$<TARGET_PROPERTY:" + + it->Value + ",INTERFACE_COMPILE_DEFINITIONS>"; + 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. + defsGenex = "$<$<BOOL:" + it->Value + ">:" + defsGenex + ">"; + } + cmGeneratorExpression ge(it->Backtrace); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse( + defsGenex); + + this->Internal + ->CachedLinkInterfaceCompileDefinitionsEntries[configString].push_back( + new cmTargetInternals::TargetPropertyEntry(cge, + it->Value)); + } + if (config) + { + std::string configPropName = "COMPILE_DEFINITIONS_" + + cmSystemTools::UpperCase(config); + const char *configProp = this->GetProperty(configPropName.c_str()); + std::string defsString = (configProp ? configProp : ""); + + cmGeneratorExpression ge(lfbt); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = + ge.Parse(defsString); + this->Internal + ->CachedLinkInterfaceCompileDefinitionsEntries[configString].push_back( + new cmTargetInternals::TargetPropertyEntry(cge)); + } + } + processCompileDefinitions(this, + this->Internal->CachedLinkInterfaceCompileDefinitionsEntries[configString], + list, + uniqueOptions, + &dagChecker, + config, + debugDefines); + if (!this->Makefile->IsGeneratingBuildSystem()) { - this->Internal->CachedLinkInterfaceCompileDefinitions[configString] = ""; + deleteAndClear(this->Internal + ->CachedLinkInterfaceCompileDefinitionsEntries); } else { this->Internal->CacheLinkInterfaceCompileDefinitionsDone[configString] = true; } - - return result; } //---------------------------------------------------------------------------- @@ -3163,6 +3814,29 @@ static void cmTargetCheckLINK_INTERFACE_LIBRARIES( } //---------------------------------------------------------------------------- +static void cmTargetCheckINTERFACE_LINK_LIBRARIES(const char* value, + cmMakefile* context) +{ + // Look for link-type keywords in the value. + static cmsys::RegularExpression + keys("(^|;)(debug|optimized|general)(;|$)"); + if(!keys.find(value)) + { + return; + } + + // Report an error. + cmOStringStream e; + + e << "Property INTERFACE_LINK_LIBRARIES may not contain link-type " + "keyword \"" << keys.match(2) << "\". The INTERFACE_LINK_LIBRARIES " + "property may contain configuration-sensitive generator-expressions " + "which may be used to specify per-configuration rules."; + + context->IssueMessage(cmake::FATAL_ERROR, e.str()); +} + +//---------------------------------------------------------------------------- void cmTarget::CheckProperty(const char* prop, cmMakefile* context) { // Certain properties need checking. @@ -3180,6 +3854,13 @@ void cmTarget::CheckProperty(const char* prop, cmMakefile* context) cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, value, context, true); } } + if(strncmp(prop, "INTERFACE_LINK_LIBRARIES", 24) == 0) + { + if(const char* value = this->GetProperty(prop)) + { + cmTargetCheckINTERFACE_LINK_LIBRARIES(value, context); + } + } } //---------------------------------------------------------------------------- @@ -3304,17 +3985,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; } - this->Location = this->BuildMacContentDirectory(this->Location, config); + + if(this->IsAppBundleOnApple()) + { + std::string macdir = this->BuildMacContentDirectory("", config, false); + if(!macdir.empty()) + { + this->Location += "/"; + this->Location += macdir; + } + } + this->Location += "/"; this->Location += this->GetFullName(config, false); return this->Location.c_str(); } @@ -3390,6 +4077,11 @@ const char *cmTarget::GetProperty(const char* prop, return 0; } + if (strcmp(prop, "NAME") == 0) + { + return this->GetName(); + } + // Watch for special "computed" properties that are dependent on // other properties or variables. Always recompute them. if(this->GetType() == cmTarget::EXECUTABLE || @@ -3437,9 +4129,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 +4142,42 @@ 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,"COMPILE_DEFINITIONS") == 0) + { + static std::string output; + output = ""; + std::string sep; + typedef cmTargetInternals::TargetPropertyEntry + TargetPropertyEntry; + for (std::vector<TargetPropertyEntry*>::const_iterator + it = this->Internal->CompileDefinitionsEntries.begin(), + end = this->Internal->CompileDefinitionsEntries.end(); + it != end; ++it) + { + output += sep; + output += (*it)->ge->GetInput(); + sep = ";"; + } + return output.c_str(); + } if (strcmp(prop,"IMPORTED") == 0) { @@ -3798,6 +4526,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 +4552,79 @@ 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 if(install_name && use_install_name) + { + return false; + } + } + 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 +4721,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 +4859,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 +4960,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 +5265,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 +5279,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 = "@rpath"; + } + else { - dir += this->GetFrameworkDirectory(config); + dir = this->GetDirectory(config); } + dir += "/"; return dir; } else @@ -4455,29 +5298,26 @@ 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")) { std::string dir; + const char* install_name_dir = this->GetProperty("INSTALL_NAME_DIR"); if(!this->Makefile->IsOn("CMAKE_SKIP_RPATH") && !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH")) { - const char* install_name_dir = this->GetProperty("INSTALL_NAME_DIR"); if(install_name_dir && *install_name_dir) { dir = install_name_dir; dir += "/"; } } - - if(this->IsFrameworkOnApple() && !for_xcode) + if(!install_name_dir && this->GetPropertyAsBool("MACOSX_RPATH")) { - dir += this->GetFrameworkDirectory(config); + dir = "@rpath/"; } - return dir; } else @@ -5059,7 +5899,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 +5932,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 +6134,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. @@ -5379,11 +6223,16 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, // Get the link interface. { - std::string linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES"; - linkProp += suffix; - + std::string linkProp = "INTERFACE_LINK_LIBRARIES"; const char *propertyLibs = this->GetProperty(linkProp.c_str()); + if (!propertyLibs) + { + linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES"; + linkProp += suffix; + propertyLibs = this->GetProperty(linkProp.c_str()); + } + if(!propertyLibs) { linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES"; @@ -5425,7 +6274,7 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, } // Get the link languages. - if(this->GetType() == cmTarget::STATIC_LIBRARY) + if(this->LinkLanguagePropagatesToDependents()) { std::string linkProp = "IMPORTED_LINK_INTERFACE_LANGUAGES"; linkProp += suffix; @@ -5501,6 +6350,48 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config, } //---------------------------------------------------------------------------- +void cmTarget::GetTransitivePropertyLinkLibraries( + const char* config, + cmTarget *headTarget, + std::vector<std::string> &libs) +{ + cmTarget::LinkInterface const* iface = this->GetLinkInterface(config, + headTarget); + if (!iface) + { + return; + } + if(this->GetType() != STATIC_LIBRARY + || this->GetPolicyStatusCMP0022() == cmPolicies::WARN + || this->GetPolicyStatusCMP0022() == cmPolicies::OLD) + { + libs = iface->Libraries; + return; + } + + const char* linkIfaceProp = "INTERFACE_LINK_LIBRARIES"; + const char* interfaceLibs = this->GetProperty(linkIfaceProp); + + if (!interfaceLibs) + { + return; + } + + // The interface libraries have been explicitly set. + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + cmGeneratorExpressionDAGChecker dagChecker(lfbt, this->GetName(), + linkIfaceProp, 0, 0); + dagChecker.SetTransitivePropertiesOnly(); + cmSystemTools::ExpandListArgument(ge.Parse(interfaceLibs)->Evaluate( + this->Makefile, + config, + false, + headTarget, + this, &dagChecker), libs); +} + +//---------------------------------------------------------------------------- bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, cmTarget *headTarget) { @@ -5519,9 +6410,19 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, // libraries and executables that export symbols. const char* explicitLibraries = 0; std::string linkIfaceProp; - if(this->GetType() == cmTarget::SHARED_LIBRARY || - this->IsExecutableWithExports()) + if(this->PolicyStatusCMP0022 != cmPolicies::OLD && + this->PolicyStatusCMP0022 != cmPolicies::WARN) + { + // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES. + linkIfaceProp = "INTERFACE_LINK_LIBRARIES"; + explicitLibraries = this->GetProperty(linkIfaceProp.c_str()); + } + else if(this->GetType() == cmTarget::SHARED_LIBRARY || + this->IsExecutableWithExports()) { + // CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a + // shared lib or executable. + // Lookup the per-configuration property. linkIfaceProp = "LINK_INTERFACE_LIBRARIES"; linkIfaceProp += suffix; @@ -5535,6 +6436,33 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, } } + if(explicitLibraries && this->PolicyStatusCMP0022 == cmPolicies::WARN && + !this->Internal->PolicyWarnedCMP0022) + { + // Compare the explicitly set old link interface properties to the + // preferred new link interface property one and warn if different. + const char* newExplicitLibraries = + this->GetProperty("INTERFACE_LINK_LIBRARIES"); + if (newExplicitLibraries + && strcmp(newExplicitLibraries, explicitLibraries) != 0) + { + cmOStringStream w; + w << + (this->Makefile->GetPolicies() + ->GetPolicyWarning(cmPolicies::CMP0022)) << "\n" + "Target \"" << this->GetName() << "\" has an " + "INTERFACE_LINK_LIBRARIES property which differs from its " << + linkIfaceProp << " properties." + "\n" + "INTERFACE_LINK_LIBRARIES:\n" + " " << newExplicitLibraries << "\n" << + linkIfaceProp << ":\n" + " " << (explicitLibraries ? explicitLibraries : "(empty)") << "\n"; + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + this->Internal->PolicyWarnedCMP0022 = true; + } + } + // There is no implicit link interface for executables or modules // so if none was explicitly set then there is no link interface. // Note that CMake versions 2.2 and below allowed linking to modules. @@ -5560,7 +6488,8 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, headTarget, this, &dagChecker), iface.Libraries); - if(this->GetType() == cmTarget::SHARED_LIBRARY) + if(this->GetType() == cmTarget::SHARED_LIBRARY + || this->GetType() == cmTarget::STATIC_LIBRARY) { // Shared libraries may have runtime implementation dependencies // on other shared libraries that are not in the interface. @@ -5594,9 +6523,19 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, } } } + if(this->LinkLanguagePropagatesToDependents()) + { + // Targets using this archive need its language runtime libraries. + iface.Languages = impl->Languages; + } } } - else + else if (this->PolicyStatusCMP0022 == cmPolicies::WARN + || this->PolicyStatusCMP0022 == cmPolicies::OLD) + // If CMP0022 is NEW then the plain tll signature sets the + // INTERFACE_LINK_LIBRARIES, so if we get here then the project + // cleared the property explicitly and we should not fall back + // to the link implementation. { // The link implementation is the default link interface. LinkImplementation const* impl = this->GetLinkImplementation(config, @@ -5604,11 +6543,75 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, iface.ImplementationIsInterface = true; iface.Libraries = impl->Libraries; iface.WrongConfigLibraries = impl->WrongConfigLibraries; - if(this->GetType() == cmTarget::STATIC_LIBRARY) + if(this->LinkLanguagePropagatesToDependents()) { // Targets using this archive need its language runtime libraries. iface.Languages = impl->Languages; } + + if(this->PolicyStatusCMP0022 == cmPolicies::WARN && + !this->Internal->PolicyWarnedCMP0022) + { + // Compare the link implementation fallback link interface to the + // preferred new link interface property and warn if different. + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + cmGeneratorExpressionDAGChecker dagChecker(lfbt, this->GetName(), + "INTERFACE_LINK_LIBRARIES", 0, 0); + std::vector<std::string> ifaceLibs; + const char* newExplicitLibraries = + this->GetProperty("INTERFACE_LINK_LIBRARIES"); + cmSystemTools::ExpandListArgument( + ge.Parse(newExplicitLibraries)->Evaluate(this->Makefile, + config, + false, + headTarget, + this, &dagChecker), + ifaceLibs); + if (ifaceLibs != impl->Libraries) + { + std::string oldLibraries; + std::string newLibraries; + const char *sep = ""; + for(std::vector<std::string>::const_iterator it + = impl->Libraries.begin(); it != impl->Libraries.end(); ++it) + { + oldLibraries += sep; + oldLibraries += *it; + sep = ";"; + } + sep = ""; + for(std::vector<std::string>::const_iterator it + = ifaceLibs.begin(); it != ifaceLibs.end(); ++it) + { + newLibraries += sep; + newLibraries += *it; + sep = ";"; + } + if(oldLibraries.empty()) + { oldLibraries = "(empty)"; } + if(newLibraries.empty()) + { newLibraries = "(empty)"; } + + cmOStringStream w; + w << + (this->Makefile->GetPolicies() + ->GetPolicyWarning(cmPolicies::CMP0022)) << "\n" + "Target \"" << this->GetName() << "\" has an " + "INTERFACE_LINK_LIBRARIES property. " + "This should be preferred as the source of the link interface " + "for this library but because CMP0022 is not set CMake is " + "ignoring the property and using the link implementation " + "as the link interface instead." + "\n" + "INTERFACE_LINK_LIBRARIES:\n" + " " << newLibraries << "\n" + "Link implementation:\n" + " " << oldLibraries << "\n"; + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + this->Internal->PolicyWarnedCMP0022 = true; + } + } } if(this->GetType() == cmTarget::STATIC_LIBRARY) @@ -5936,59 +6939,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 +7065,8 @@ cmTargetInternalPointer cmTargetInternalPointer::~cmTargetInternalPointer() { deleteAndClear(this->Pointer->IncludeDirectoriesEntries); + deleteAndClear(this->Pointer->CompileOptionsEntries); + deleteAndClear(this->Pointer->CompileDefinitionsEntries); delete this->Pointer; } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 9d467961b..27b74ca4b 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -19,6 +19,14 @@ #include <cmsys/auto_ptr.hxx> +#define CM_FOR_EACH_TARGET_POLICY(F) \ + F(CMP0003) \ + F(CMP0004) \ + F(CMP0008) \ + F(CMP0020) \ + F(CMP0021) \ + F(CMP0022) + class cmake; class cmMakefile; class cmSourceFile; @@ -85,26 +93,19 @@ 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); cmMakefile *GetMakefile() const { return this->Makefile;}; - /** Get the status of policy CMP0003 when the target was created. */ - cmPolicies::PolicyStatus GetPolicyStatusCMP0003() const - { return this->PolicyStatusCMP0003; } - - /** Get the status of policy CMP0004 when the target was created. */ - cmPolicies::PolicyStatus GetPolicyStatusCMP0004() const - { return this->PolicyStatusCMP0004; } +#define DECLARE_TARGET_POLICY(POLICY) \ + cmPolicies::PolicyStatus GetPolicyStatus ## POLICY () const \ + { return this->PolicyStatus ## POLICY; } - /** Get the status of policy CMP0008 when the target was created. */ - cmPolicies::PolicyStatus GetPolicyStatusCMP0008() const - { return this->PolicyStatusCMP0008; } + CM_FOR_EACH_TARGET_POLICY(DECLARE_TARGET_POLICY) - /** Get the status of policy CMP0020 when the target was created. */ - cmPolicies::PolicyStatus GetPolicyStatusCMP0020() const - { return this->PolicyStatusCMP0020; } +#undef DECLARE_TARGET_POLICY /** * Get the list of the custom commands for this target @@ -189,6 +190,12 @@ public: void AddLinkLibrary(cmMakefile& mf, const char *target, const char* lib, LinkLibraryType llt); + enum TLLSignature { + KeywordTLLSignature, + PlainTLLSignature + }; + bool PushTLLCommandTrace(TLLSignature signature); + void GetTllSignatureTraces(cmOStringStream &s, TLLSignature sig) const; void MergeLinkLibraries( cmMakefile& mf, const char* selfname, const LinkLibraryVectorType& libs ); @@ -271,6 +278,9 @@ public: if the target cannot be linked. */ LinkInterface const* GetLinkInterface(const char* config, cmTarget *headTarget); + void GetTransitivePropertyLinkLibraries(const char* config, + cmTarget *headTarget, + std::vector<std::string> &libs); /** The link implementation specifies the direct library dependencies needed by the object files of the target. */ @@ -336,7 +346,7 @@ public: * Trace through the source files in this target and add al source files * that they depend on, used by all generators */ - void TraceDependencies(const char* vsProjectFile); + void TraceDependencies(); /** * Make sure the full path to all source files is known. @@ -362,6 +372,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 +420,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); @@ -430,7 +447,8 @@ public: If no macro should be defined null is returned. */ const char* GetExportMacro(); - std::string GetCompileDefinitions(const char *config); + void GetCompileDefinitions(std::vector<std::string> &result, + const char *config); // Compute the set of languages compiled by the target. This is // computed every time it is called because the languages can change @@ -462,6 +480,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 +498,35 @@ 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 InsertCompileDefinition(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); @@ -512,7 +541,24 @@ public: std::string GetDebugGeneratorExpressions(const std::string &value, cmTarget::LinkLibraryType llt); + + void AddSystemIncludeDirectories(const std::set<cmStdString> &incs); + void AddSystemIncludeDirectories(const std::vector<std::string> &incs); + std::set<cmStdString> const & GetSystemIncludeDirectories() const + { return this->SystemIncludeDirectories; } + + void FinalizeSystemIncludeDirectories(); + + bool LinkLanguagePropagatesToDependents() const + { return this->TargetTypeValue == STATIC_LIBRARY; } + private: + // The set of include directories that are marked as system include + // directories. + std::set<cmStdString> SystemIncludeDirectories; + + std::vector<std::pair<TLLSignature, cmListFileBacktrace> > TLLCommands; + /** * A list of direct dependencies. Use in conjunction with DependencyMap. */ @@ -596,6 +642,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 +673,8 @@ private: bool IsApple; bool IsImportedTarget; bool DebugIncludesDone; + bool DebugCompileOptionsDone; + bool DebugCompileDefinitionsDone; mutable std::set<std::string> LinkImplicitNullProperties; bool BuildInterfaceIncludesAppended; @@ -660,10 +713,12 @@ private: cmMakefile* Makefile; // Policy status recorded when target was created. - cmPolicies::PolicyStatus PolicyStatusCMP0003; - cmPolicies::PolicyStatus PolicyStatusCMP0004; - cmPolicies::PolicyStatus PolicyStatusCMP0008; - cmPolicies::PolicyStatus PolicyStatusCMP0020; +#define TARGET_POLICY_MEMBER(POLICY) \ + cmPolicies::PolicyStatus PolicyStatus ## POLICY; + + CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_MEMBER) + +#undef TARGET_POLICY_MEMBER // Internal representation details. friend class cmTargetInternals; diff --git a/Source/cmTargetCompileDefinitionsCommand.cxx b/Source/cmTargetCompileDefinitionsCommand.cxx index ba0ad5986..46c9666ef 100644 --- a/Source/cmTargetCompileDefinitionsCommand.cxx +++ b/Source/cmTargetCompileDefinitionsCommand.cxx @@ -60,7 +60,7 @@ std::string cmTargetCompileDefinitionsCommand //---------------------------------------------------------------------------- void cmTargetCompileDefinitionsCommand ::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content, - bool) + bool, bool) { tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content).c_str()); } diff --git a/Source/cmTargetCompileDefinitionsCommand.h b/Source/cmTargetCompileDefinitionsCommand.h index ec9b071db..585485d2a 100644 --- a/Source/cmTargetCompileDefinitionsCommand.h +++ b/Source/cmTargetCompileDefinitionsCommand.h @@ -81,7 +81,7 @@ private: virtual void HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content, - bool prepend); + bool prepend, bool system); virtual std::string Join(const std::vector<std::string> &content); }; diff --git a/Source/cmTargetCompileOptionsCommand.cxx b/Source/cmTargetCompileOptionsCommand.cxx new file mode 100644 index 000000000..254acc73d --- /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, 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 000000000..b9afd7169 --- /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, bool system); + virtual std::string Join(const std::vector<std::string> &content); +}; + +#endif diff --git a/Source/cmTargetExport.h b/Source/cmTargetExport.h index c9d87fb7e..76658887d 100644 --- a/Source/cmTargetExport.h +++ b/Source/cmTargetExport.h @@ -12,6 +12,8 @@ #ifndef cmTargetExport_h #define cmTargetExport_h +#include "cmStandardIncludes.h" + class cmTarget; class cmInstallTargetGenerator; class cmInstallFilesGenerator; @@ -33,6 +35,7 @@ public: cmInstallTargetGenerator* FrameworkGenerator; cmInstallTargetGenerator* BundleGenerator; cmInstallFilesGenerator* HeaderGenerator; + std::string InterfaceIncludeDirectories; ///@} }; diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx index 12d0a515f..e7b906c9e 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.cxx +++ b/Source/cmTargetIncludeDirectoriesCommand.cxx @@ -15,7 +15,8 @@ bool cmTargetIncludeDirectoriesCommand ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) { - return this->HandleArguments(args, "INCLUDE_DIRECTORIES", PROCESS_BEFORE); + return this->HandleArguments(args, "INCLUDE_DIRECTORIES", + ArgumentFlags(PROCESS_BEFORE | PROCESS_SYSTEM)); } //---------------------------------------------------------------------------- @@ -65,10 +66,39 @@ std::string cmTargetIncludeDirectoriesCommand //---------------------------------------------------------------------------- void cmTargetIncludeDirectoriesCommand ::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content, - bool prepend) + bool prepend, bool system) { cmListFileBacktrace lfbt; this->Makefile->GetBacktrace(lfbt); cmValueWithOrigin entry(this->Join(content), lfbt); tgt->InsertInclude(entry, prepend); + if (system) + { + tgt->AddSystemIncludeDirectories(content); + } +} + +//---------------------------------------------------------------------------- +void cmTargetIncludeDirectoriesCommand +::HandleInterfaceContent(cmTarget *tgt, + const std::vector<std::string> &content, + bool prepend, bool system) +{ + cmTargetPropCommandBase::HandleInterfaceContent(tgt, content, + prepend, system); + + if (system) + { + std::string joined; + std::string sep; + for(std::vector<std::string>::const_iterator it = content.begin(); + it != content.end(); ++it) + { + joined += sep; + sep = ";"; + joined += *it; + } + tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", + joined.c_str()); + } } diff --git a/Source/cmTargetIncludeDirectoriesCommand.h b/Source/cmTargetIncludeDirectoriesCommand.h index e4bc9cf67..fcc37f06a 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.h +++ b/Source/cmTargetIncludeDirectoriesCommand.h @@ -54,7 +54,7 @@ public: virtual const char* GetFullDocumentation() const { return - " target_include_directories(<target> [BEFORE] " + " target_include_directories(<target> [SYSTEM] [BEFORE] " "<INTERFACE|PUBLIC|PRIVATE> [items1...]\n" " [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])\n" "Specify include directories or targets to use when compiling a given " @@ -71,6 +71,14 @@ public: "The following arguments specify include directories. Specified " "include directories may be absolute paths or relative paths. " "Repeated calls for the same <target> append items in the order called." + "If SYSTEM is specified, the compiler will be told the " + "directories are meant as system include directories on some " + "platforms (signalling this setting might achieve effects such as " + "the compiler skipping warnings, or these fixed-install system files " + "not being considered in dependency calculations - see compiler " + "docs). If SYSTEM is used together with PUBLIC or INTERFACE, the " + "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES target property will be " + "populated with the specified directories." "\n" "Arguments to target_include_directories may use \"generator " "expressions\" with the syntax \"$<...>\". " @@ -86,7 +94,11 @@ private: virtual void HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content, - bool prepend); + bool prepend, bool system); + virtual void HandleInterfaceContent(cmTarget *tgt, + const std::vector<std::string> &content, + bool prepend, bool system); + virtual std::string Join(const std::vector<std::string> &content); }; diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index b7b7691c8..c2f46a1b1 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -31,6 +31,11 @@ bool cmTargetLinkLibrariesCommand return false; } + if (this->Makefile->IsAlias(args[0].c_str())) + { + this->SetError("can not be used on an ALIAS target."); + return false; + } // Lookup the target for which libraries are specified. this->Target = this->Makefile->GetCMakeInstance() @@ -116,7 +121,7 @@ bool cmTargetLinkLibrariesCommand { if(args[i] == "LINK_INTERFACE_LIBRARIES") { - this->CurrentProcessingState = ProcessingLinkInterface; + this->CurrentProcessingState = ProcessingPlainLinkInterface; if(i != 1) { this->Makefile->IssueMessage( @@ -127,9 +132,26 @@ bool cmTargetLinkLibrariesCommand return true; } } + else if(args[i] == "INTERFACE") + { + if(i != 1 + && this->CurrentProcessingState != ProcessingKeywordPrivateInterface + && this->CurrentProcessingState != ProcessingKeywordPublicInterface + && this->CurrentProcessingState != ProcessingKeywordLinkInterface) + { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "The INTERFACE option must appear as the second " + "argument, just after the target name." + ); + return true; + } + this->CurrentProcessingState = ProcessingKeywordLinkInterface; + } else if(args[i] == "LINK_PUBLIC") { - if(i != 1 && this->CurrentProcessingState != ProcessingPrivateInterface) + if(i != 1 + && this->CurrentProcessingState != ProcessingPlainPrivateInterface) { this->Makefile->IssueMessage( cmake::FATAL_ERROR, @@ -138,11 +160,28 @@ bool cmTargetLinkLibrariesCommand ); return true; } - this->CurrentProcessingState = ProcessingPublicInterface; + this->CurrentProcessingState = ProcessingPlainPublicInterface; + } + else if(args[i] == "PUBLIC") + { + if(i != 1 + && this->CurrentProcessingState != ProcessingKeywordPrivateInterface + && this->CurrentProcessingState != ProcessingKeywordPublicInterface + && this->CurrentProcessingState != ProcessingKeywordLinkInterface) + { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "The PUBLIC or PRIVATE option must appear as the second " + "argument, just after the target name." + ); + return true; + } + this->CurrentProcessingState = ProcessingKeywordPublicInterface; } else if(args[i] == "LINK_PRIVATE") { - if(i != 1 && this->CurrentProcessingState != ProcessingPublicInterface) + if(i != 1 + && this->CurrentProcessingState != ProcessingPlainPublicInterface) { this->Makefile->IssueMessage( cmake::FATAL_ERROR, @@ -151,7 +190,23 @@ bool cmTargetLinkLibrariesCommand ); return true; } - this->CurrentProcessingState = ProcessingPrivateInterface; + this->CurrentProcessingState = ProcessingPlainPrivateInterface; + } + else if(args[i] == "PRIVATE") + { + if(i != 1 + && this->CurrentProcessingState != ProcessingKeywordPrivateInterface + && this->CurrentProcessingState != ProcessingKeywordPublicInterface + && this->CurrentProcessingState != ProcessingKeywordLinkInterface) + { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "The PUBLIC or PRIVATE option must appear as the second " + "argument, just after the target name." + ); + return true; + } + this->CurrentProcessingState = ProcessingKeywordPrivateInterface; } else if(args[i] == "debug") { @@ -184,7 +239,10 @@ bool cmTargetLinkLibrariesCommand { // The link type was specified by the previous argument. haveLLT = false; - this->HandleLibrary(args[i].c_str(), llt); + if (!this->HandleLibrary(args[i].c_str(), llt)) + { + return false; + } } else { @@ -210,7 +268,10 @@ bool cmTargetLinkLibrariesCommand llt = cmTarget::OPTIMIZED; } } - this->HandleLibrary(args[i].c_str(), llt); + if (!this->HandleLibrary(args[i].c_str(), llt)) + { + return false; + } } } @@ -224,12 +285,17 @@ bool cmTargetLinkLibrariesCommand cmSystemTools::SetFatalErrorOccured(); } + const cmPolicies::PolicyStatus policy22Status + = this->Target->GetPolicyStatusCMP0022(); + // If any of the LINK_ options were given, make sure the // LINK_INTERFACE_LIBRARIES target property exists. // Use of any of the new keywords implies awareness of // this property. And if no libraries are named, it should // result in an empty link interface. - if(this->CurrentProcessingState != ProcessingLinkLibraries && + if((policy22Status == cmPolicies::OLD || + policy22Status == cmPolicies::WARN) && + this->CurrentProcessingState != ProcessingLinkLibraries && !this->Target->GetProperty("LINK_INTERFACE_LIBRARIES")) { this->Target->SetProperty("LINK_INTERFACE_LIBRARIES", ""); @@ -252,22 +318,106 @@ cmTargetLinkLibrariesCommand } //---------------------------------------------------------------------------- -void +bool cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib, cmTarget::LinkLibraryType llt) { + cmTarget::TLLSignature sig = + (this->CurrentProcessingState == ProcessingPlainPrivateInterface + || this->CurrentProcessingState == ProcessingPlainPublicInterface + || this->CurrentProcessingState == ProcessingKeywordPrivateInterface + || this->CurrentProcessingState == ProcessingKeywordPublicInterface + || this->CurrentProcessingState == ProcessingKeywordLinkInterface) + ? cmTarget::KeywordTLLSignature : cmTarget::PlainTLLSignature; + if (!this->Target->PushTLLCommandTrace(sig)) + { + const char *modal = 0; + cmake::MessageType messageType = cmake::AUTHOR_WARNING; + switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0023)) + { + case cmPolicies::WARN: + modal = "should"; + case cmPolicies::OLD: + break; + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::NEW: + modal = "must"; + messageType = cmake::FATAL_ERROR; + } + + if(modal) + { + cmOStringStream e; + // If the sig is a keyword form and there is a conflict, the existing + // form must be the plain form. + const char *existingSig + = (sig == cmTarget::KeywordTLLSignature ? "plain" + : "keyword"); + e << this->Makefile->GetPolicies() + ->GetPolicyWarning(cmPolicies::CMP0023) << "\n" + "The " << existingSig << " signature for target_link_libraries " + "has already been used with the target \"" + << this->Target->GetName() << "\". All uses of " + "target_link_libraries with a target " << modal << " be either " + "all-keyword or all-plain.\n"; + this->Target->GetTllSignatureTraces(e, + sig == cmTarget::KeywordTLLSignature + ? cmTarget::PlainTLLSignature + : cmTarget::KeywordTLLSignature); + this->Makefile->IssueMessage(messageType, e.str().c_str()); + if(messageType == cmake::FATAL_ERROR) + { + return false; + } + } + } + // Handle normal case first. - if(this->CurrentProcessingState != ProcessingLinkInterface) + if(this->CurrentProcessingState != ProcessingKeywordLinkInterface + && this->CurrentProcessingState != ProcessingPlainLinkInterface) { this->Makefile ->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt); - if (this->CurrentProcessingState != ProcessingPublicInterface) + if(this->CurrentProcessingState == ProcessingLinkLibraries) + { + this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES", + this->Target->GetDebugGeneratorExpressions(lib, llt).c_str()); + return true; + } + else if(this->CurrentProcessingState != ProcessingKeywordPublicInterface + && this->CurrentProcessingState != ProcessingPlainPublicInterface) { - // Not LINK_INTERFACE_LIBRARIES or LINK_PUBLIC, do not add to interface. - return; + if (this->Target->GetType() == cmTarget::STATIC_LIBRARY) + { + std::string configLib = this->Target + ->GetDebugGeneratorExpressions(lib, llt); + if (cmGeneratorExpression::IsValidTargetName(lib) + || cmGeneratorExpression::Find(lib) != std::string::npos) + { + configLib = "$<LINK_ONLY:" + configLib + ">"; + } + this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES", + configLib.c_str()); + } + // Not a 'public' or 'interface' library. Do not add to interface + // property. + return true; } } + this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES", + this->Target->GetDebugGeneratorExpressions(lib, llt).c_str()); + + const cmPolicies::PolicyStatus policy22Status + = this->Target->GetPolicyStatusCMP0022(); + + if (policy22Status != cmPolicies::OLD + && policy22Status != cmPolicies::WARN) + { + return true; + } + // Get the list of configurations considered to be DEBUG. std::vector<std::string> const& debugConfigs = this->Makefile->GetCMakeInstance()->GetDebugConfigs(); @@ -303,4 +453,5 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib, } } } + return true; } diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h index c683016dd..2cf6b03ef 100644 --- a/Source/cmTargetLinkLibrariesCommand.h +++ b/Source/cmTargetLinkLibrariesCommand.h @@ -88,14 +88,19 @@ public: "See the IMPORTED mode of the add_library command for more " "information. " "\n" - "Library dependencies are transitive by default. " + "Library dependencies are transitive by default with this signature. " "When this target is linked into another target then the libraries " "linked to this target will appear on the link line for the other " "target too. " - "See the LINK_INTERFACE_LIBRARIES target property to override the " - "set of transitive link dependencies for a target. " + "This transitive \"link interface\" is stored in the " + "INTERFACE_LINK_LIBRARIES target property when policy CMP0022 is set " + "to NEW and may be overridden by setting the property directly. " + "(" + "When CMP0022 is not set to NEW, transitive linking is builtin " + "but may be overridden by the LINK_INTERFACE_LIBRARIES property. " "Calls to other signatures of this command may set the property " "making any libraries linked exclusively by this signature private." + ")" "\n" "CMake will also propagate \"usage requirements\" from linked library " "targets. " @@ -109,17 +114,38 @@ public: " INTERFACE_POSITION_INDEPENDENT_CODE: Sets POSITION_INDEPENDENT_CODE\n" " or checked for consistency with existing value\n" "\n" + "If an <item> is a library in a Mac OX framework, the Headers " + "directory of the framework will also be processed as a \"usage " + "requirement\". This has the same effect as passing the framework " + "directory as an include directory." + " target_link_libraries(<target>\n" + " <PRIVATE|PUBLIC|INTERFACE> <lib> ...\n" + " [<PRIVATE|PUBLIC|INTERFACE> <lib> ... ] ...])\n" + "The PUBLIC, PRIVATE and INTERFACE keywords can be used to specify " + "both the link dependencies and the link interface in one command. " + "Libraries and targets following PUBLIC are linked to, and are " + "made part of the link interface. Libraries and targets " + "following PRIVATE are linked to, but are not made part of the " + "link interface. Libraries following INTERFACE are appended " + "to the link interface and are not used for linking <target>." + "\n" " target_link_libraries(<target> LINK_INTERFACE_LIBRARIES\n" " [[debug|optimized|general] <lib>] ...)\n" "The LINK_INTERFACE_LIBRARIES mode appends the libraries " - "to the LINK_INTERFACE_LIBRARIES and its per-configuration equivalent " - "target properties instead of using them for linking. " - "Libraries specified as \"debug\" are appended to the " + "to the INTERFACE_LINK_LIBRARIES target property instead of using them " + "for linking. If policy CMP0022 is not NEW, then this mode also " + "appends libraries to the LINK_INTERFACE_LIBRARIES and its " + "per-configuration equivalent. This signature " + "is for compatibility only. Prefer the INTERFACE mode instead. " + "Libraries specified as \"debug\" are wrapped in a generator " + "expression to correspond to debug builds. If policy CMP0022 is not " + "NEW, the libraries are also appended to the " "LINK_INTERFACE_LIBRARIES_DEBUG property (or to the properties " "corresponding to configurations listed in the DEBUG_CONFIGURATIONS " "global property if it is set). " "Libraries specified as \"optimized\" are appended to the " - "LINK_INTERFACE_LIBRARIES property. " + "INTERFACE_LINK_LIBRARIES property. If policy CMP0022 is not NEW, " + "they are also appended to the LINK_INTERFACE_LIBRARIES property. " "Libraries specified as \"general\" (or without any keyword) are " "treated as if specified for both \"debug\" and \"optimized\"." "\n" @@ -129,11 +155,15 @@ public: " [<LINK_PRIVATE|LINK_PUBLIC>\n" " [[debug|optimized|general] <lib>] ...])\n" "The LINK_PUBLIC and LINK_PRIVATE modes can be used to specify both " - "the link dependencies and the link interface in one command. " + "the link dependencies and the link interface in one command. This " + "signature is for compatibility only. Prefer the PUBLIC or PRIVATE " + "keywords instead. " "Libraries and targets following LINK_PUBLIC are linked to, and are " - "made part of the LINK_INTERFACE_LIBRARIES. Libraries and targets " - "following LINK_PRIVATE are linked to, but are not made part of the " - "LINK_INTERFACE_LIBRARIES. " + "made part of the INTERFACE_LINK_LIBRARIES. If policy CMP0022 is not " + "NEW, they are also made part of the LINK_INTERFACE_LIBRARIES. " + "Libraries and targets following LINK_PRIVATE are linked to, but are " + "not made part of the INTERFACE_LINK_LIBRARIES (or " + "LINK_INTERFACE_LIBRARIES)." "\n" "The library dependency graph is normally acyclic (a DAG), but in the " "case of mutually-dependent STATIC libraries CMake allows the graph " @@ -173,14 +203,17 @@ private: cmTarget* Target; enum ProcessingState { ProcessingLinkLibraries, - ProcessingLinkInterface, - ProcessingPublicInterface, - ProcessingPrivateInterface + ProcessingPlainLinkInterface, + ProcessingKeywordLinkInterface, + ProcessingPlainPublicInterface, + ProcessingKeywordPublicInterface, + ProcessingPlainPrivateInterface, + ProcessingKeywordPrivateInterface }; ProcessingState CurrentProcessingState; - void HandleLibrary(const char* lib, cmTarget::LinkLibraryType llt); + bool HandleLibrary(const char* lib, cmTarget::LinkLibraryType llt); }; diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index 771097ca2..1862cb696 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -19,13 +19,18 @@ bool cmTargetPropCommandBase ::HandleArguments(std::vector<std::string> const& args, const char *prop, ArgumentFlags flags) { - if(args.size() < 3) + if(args.size() < 2) { this->SetError("called with incorrect number of arguments"); return false; } // Lookup the target for which libraries are specified. + if (this->Makefile->IsAlias(args[0].c_str())) + { + this->SetError("can not be used on an ALIAS target."); + return false; + } this->Target = this->Makefile->GetCMakeInstance() ->GetGlobalGenerator()->FindTarget(0, args[0].c_str()); @@ -48,12 +53,24 @@ bool cmTargetPropCommandBase return false; } + bool system = false; unsigned int argIndex = 1; + if ((flags & PROCESS_SYSTEM) && args[argIndex] == "SYSTEM") + { + if (args.size() < 3) + { + this->SetError("called with incorrect number of arguments"); + return false; + } + system = true; + ++argIndex; + } + bool prepend = false; if ((flags & PROCESS_BEFORE) && args[argIndex] == "BEFORE") { - if (args.size() < 4) + if (args.size() < 3) { this->SetError("called with incorrect number of arguments"); return false; @@ -66,7 +83,7 @@ bool cmTargetPropCommandBase while (argIndex < args.size()) { - if (!this->ProcessContentArgs(args, argIndex, prepend)) + if (!this->ProcessContentArgs(args, argIndex, prepend, system)) { return false; } @@ -77,7 +94,7 @@ bool cmTargetPropCommandBase //---------------------------------------------------------------------------- bool cmTargetPropCommandBase ::ProcessContentArgs(std::vector<std::string> const& args, - unsigned int &argIndex, bool prepend) + unsigned int &argIndex, bool prepend, bool system) { const std::string scope = args[argIndex]; @@ -105,12 +122,12 @@ bool cmTargetPropCommandBase || args[i] == "PRIVATE" || args[i] == "INTERFACE" ) { - this->PopulateTargetProperies(scope, content, prepend); + this->PopulateTargetProperies(scope, content, prepend, system); return true; } content.push_back(args[i]); } - this->PopulateTargetProperies(scope, content, prepend); + this->PopulateTargetProperies(scope, content, prepend, system); return true; } @@ -118,27 +135,35 @@ bool cmTargetPropCommandBase void cmTargetPropCommandBase ::PopulateTargetProperies(const std::string &scope, const std::vector<std::string> &content, - bool prepend) + bool prepend, bool system) { if (scope == "PRIVATE" || scope == "PUBLIC") { - this->HandleDirectContent(this->Target, content, prepend); + this->HandleDirectContent(this->Target, content, prepend, system); } if (scope == "INTERFACE" || scope == "PUBLIC") { - if (prepend) - { - const std::string propName = std::string("INTERFACE_") + this->Property; - const char *propValue = this->Target->GetProperty(propName.c_str()); - const std::string totalContent = this->Join(content) + (propValue - ? std::string(";") + propValue - : std::string()); - this->Target->SetProperty(propName.c_str(), totalContent.c_str()); - } - else - { - this->Target->AppendProperty(("INTERFACE_" + this->Property).c_str(), - this->Join(content).c_str()); - } + this->HandleInterfaceContent(this->Target, content, prepend, system); + } +} + +//---------------------------------------------------------------------------- +void cmTargetPropCommandBase::HandleInterfaceContent(cmTarget *tgt, + const std::vector<std::string> &content, + bool prepend, bool) +{ + if (prepend) + { + const std::string propName = std::string("INTERFACE_") + this->Property; + const char *propValue = tgt->GetProperty(propName.c_str()); + const std::string totalContent = this->Join(content) + (propValue + ? std::string(";") + propValue + : std::string()); + tgt->SetProperty(propName.c_str(), totalContent.c_str()); + } + else + { + tgt->AppendProperty(("INTERFACE_" + this->Property).c_str(), + this->Join(content).c_str()); } } diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h index 8047a48aa..690582fdd 100644 --- a/Source/cmTargetPropCommandBase.h +++ b/Source/cmTargetPropCommandBase.h @@ -25,7 +25,8 @@ public: enum ArgumentFlags { NO_FLAGS = 0, - PROCESS_BEFORE = 1 + PROCESS_BEFORE = 1, + PROCESS_SYSTEM = 2 }; bool HandleArguments(std::vector<std::string> const& args, @@ -36,20 +37,24 @@ protected: std::string Property; cmTarget *Target; + virtual void HandleInterfaceContent(cmTarget *tgt, + const std::vector<std::string> &content, + bool prepend, bool system); private: virtual void HandleImportedTarget(const std::string &tgt) = 0; virtual void HandleMissingTarget(const std::string &name) = 0; virtual void HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content, - bool prepend) = 0; + bool prepend, bool system) = 0; + virtual std::string Join(const std::vector<std::string> &content) = 0; bool ProcessContentArgs(std::vector<std::string> const& args, - unsigned int &argIndex, bool prepend); + unsigned int &argIndex, bool prepend, bool system); void PopulateTargetProperies(const std::string &scope, const std::vector<std::string> &content, - bool prepend); + bool prepend, bool system); }; #endif diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx index 912ec7634..0904431d1 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 6caa130ce..a20594cbe 100644 --- a/Source/cmTryCompileCommand.h +++ b/Source/cmTryCompileCommand.h @@ -64,19 +64,19 @@ 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 " + " [COPY_FILE <fileName> [COPY_FILE_ERROR <var>]])\n" + "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." + "given fileName and optionally COPY_FILE_ERROR to capture any error." "\n" "In this version all files in bindir/CMakeFiles/CMakeTmp " "will be cleaned automatically. For debugging, --debug-trycompile can " diff --git a/Source/cmVS10LinkFlagTable.h b/Source/cmVS10LinkFlagTable.h index 64febbb52..5d1562002 100644 --- a/Source/cmVS10LinkFlagTable.h +++ b/Source/cmVS10LinkFlagTable.h @@ -201,7 +201,7 @@ static cmVS7FlagTable cmVS10LinkFlagTable[] = cmVS7FlagTable::UserValueRequired}, {"GenerateMapFile", "MAP", "", "true", cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue}, - {"MapFileName", "MAP", "Generate Map File", "", + {"MapFileName", "MAP:", "Generate Map File", "", cmVS7FlagTable::UserValueRequired}, //String List Properties diff --git a/Source/cmVS11LinkFlagTable.h b/Source/cmVS11LinkFlagTable.h index ea0d0f0b0..b4587a836 100644 --- a/Source/cmVS11LinkFlagTable.h +++ b/Source/cmVS11LinkFlagTable.h @@ -227,7 +227,7 @@ static cmVS7FlagTable cmVS11LinkFlagTable[] = cmVS7FlagTable::UserValueRequired}, {"GenerateMapFile", "MAP", "", "true", cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue}, - {"MapFileName", "MAP", "Generate Map File", "", + {"MapFileName", "MAP:", "Generate Map File", "", cmVS7FlagTable::UserValueRequired}, //String List Properties diff --git a/Source/cmVS12LinkFlagTable.h b/Source/cmVS12LinkFlagTable.h index ce32e3815..73d450a9d 100644 --- a/Source/cmVS12LinkFlagTable.h +++ b/Source/cmVS12LinkFlagTable.h @@ -227,7 +227,7 @@ static cmVS7FlagTable cmVS12LinkFlagTable[] = cmVS7FlagTable::UserValueRequired}, {"GenerateMapFile", "MAP", "", "true", cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue}, - {"MapFileName", "MAP", "Generate Map File", "", + {"MapFileName", "MAP:", "Generate Map File", "", cmVS7FlagTable::UserValueRequired}, //String List Properties diff --git a/Source/cmVariableWatch.cxx b/Source/cmVariableWatch.cxx index f5fdca465..8ad6fce8f 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", @@ -36,37 +37,63 @@ cmVariableWatch::cmVariableWatch() cmVariableWatch::~cmVariableWatch() { + cmVariableWatch::StringToVectorOfPairs::iterator svp_it; + + for ( svp_it = this->WatchMap.begin(); + svp_it != this->WatchMap.end(); ++svp_it ) + { + cmVariableWatch::VectorOfPairs::iterator p_it; + + for ( p_it = svp_it->second.begin(); + p_it != svp_it->second.end(); ++p_it ) + { + delete *p_it; + } + } } -void cmVariableWatch::AddWatch(const std::string& variable, - WatchMethod method, void* client_data /*=0*/) +bool cmVariableWatch::AddWatch(const std::string& variable, + WatchMethod method, void* client_data /*=0*/, + DeleteData delete_data /*=0*/) { - cmVariableWatch::Pair p; - p.Method = method; - p.ClientData = client_data; + cmVariableWatch::Pair* p = new cmVariableWatch::Pair; + p->Method = method; + p->ClientData = client_data; + p->DeleteDataCall = delete_data; cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable]; cmVariableWatch::VectorOfPairs::size_type cc; for ( cc = 0; cc < vp->size(); cc ++ ) { - cmVariableWatch::Pair* pair = &(*vp)[cc]; - if ( pair->Method == method ) + cmVariableWatch::Pair* pair = (*vp)[cc]; + if ( pair->Method == method && + client_data && client_data == pair->ClientData) { - (*vp)[cc] = p; - return; + // Callback already exists + return false; } } vp->push_back(p); + return true; } void cmVariableWatch::RemoveWatch(const std::string& variable, - WatchMethod method) + WatchMethod method, + void* client_data /*=0*/) { + if ( !this->WatchMap.count(variable) ) + { + return; + } cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable]; cmVariableWatch::VectorOfPairs::iterator it; for ( it = vp->begin(); it != vp->end(); ++it ) { - if ( it->Method == method ) + if ( (*it)->Method == method && + // If client_data is NULL, we want to disconnect all watches against + // the given method; otherwise match ClientData as well. + (!client_data || (client_data == (*it)->ClientData))) { + delete *it; vp->erase(it); return; } @@ -86,7 +113,7 @@ void cmVariableWatch::VariableAccessed(const std::string& variable, cmVariableWatch::VectorOfPairs::const_iterator it; for ( it = vp->begin(); it != vp->end(); it ++ ) { - it->Method(variable, access_type, it->ClientData, + (*it)->Method(variable, access_type, (*it)->ClientData, newValue, mf); } } diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h index 7dd4ac5e6..790c75acc 100644 --- a/Source/cmVariableWatch.h +++ b/Source/cmVariableWatch.h @@ -26,6 +26,7 @@ class cmVariableWatch public: typedef void (*WatchMethod)(const std::string& variable, int access_type, void* client_data, const char* newValue, const cmMakefile* mf); + typedef void (*DeleteData)(void* client_data); cmVariableWatch(); ~cmVariableWatch(); @@ -33,9 +34,10 @@ public: /** * Add watch to the variable */ - void AddWatch(const std::string& variable, WatchMethod method, - void* client_data=0); - void RemoveWatch(const std::string& variable, WatchMethod method); + bool AddWatch(const std::string& variable, WatchMethod method, + void* client_data=0, DeleteData delete_data=0); + void RemoveWatch(const std::string& variable, WatchMethod method, + void* client_data=0); /** * This method is called when variable is accessed @@ -67,10 +69,18 @@ protected: { WatchMethod Method; void* ClientData; - Pair() : Method(0), ClientData(0) {} + DeleteData DeleteDataCall; + Pair() : Method(0), ClientData(0), DeleteDataCall(0) {} + ~Pair() + { + if (this->DeleteDataCall && this->ClientData) + { + this->DeleteDataCall(this->ClientData); + } + } }; - typedef std::vector< Pair > VectorOfPairs; + typedef std::vector< Pair* > VectorOfPairs; typedef std::map<cmStdString, VectorOfPairs > StringToVectorOfPairs; StringToVectorOfPairs WatchMap; diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx index a432943ae..33e159bce 100644 --- a/Source/cmVariableWatchCommand.cxx +++ b/Source/cmVariableWatchCommand.cxx @@ -14,63 +14,27 @@ #include "cmVariableWatch.h" //---------------------------------------------------------------------------- -static void cmVariableWatchCommandVariableAccessed( - const std::string& variable, int access_type, void* client_data, - const char* newValue, const cmMakefile* mf) +struct cmVariableWatchCallbackData { - cmVariableWatchCommand* command - = static_cast<cmVariableWatchCommand*>(client_data); - command->VariableAccessed(variable, access_type, newValue, mf); -} + bool InCallback; + std::string Command; +}; //---------------------------------------------------------------------------- -cmVariableWatchCommand::cmVariableWatchCommand() -{ - this->InCallback = false; -} - -//---------------------------------------------------------------------------- -bool cmVariableWatchCommand -::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) +static void cmVariableWatchCommandVariableAccessed( + const std::string& variable, int access_type, void* client_data, + const char* newValue, const cmMakefile* mf) { - if ( args.size() < 1 ) - { - this->SetError("must be called with at least one argument."); - return false; - } - std::string variable = args[0]; - if ( args.size() > 1 ) - { - std::string command = args[1]; - this->Handlers[variable].Commands.push_back(args[1]); - } - if ( variable == "CMAKE_CURRENT_LIST_FILE" ) - { - cmOStringStream ostr; - ostr << "cannot be set on the variable: " << variable.c_str(); - this->SetError(ostr.str().c_str()); - return false; - } + cmVariableWatchCallbackData* data + = static_cast<cmVariableWatchCallbackData*>(client_data); - this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch( - variable, cmVariableWatchCommandVariableAccessed, this); - - return true; -} - -//---------------------------------------------------------------------------- -void cmVariableWatchCommand::VariableAccessed(const std::string& variable, - int access_type, const char* newValue, const cmMakefile* mf) -{ - if ( this->InCallback ) + if ( data->InCallback ) { return; } - this->InCallback = true; + data->InCallback = true; cmListFileFunction newLFF; - cmVariableWatchCommandHandler *handler = &this->Handlers[variable]; - cmVariableWatchCommandHandler::VectorOfCommands::iterator it; cmListFileArgument arg; bool processed = false; const char* accessString = cmVariableWatch::GetAccessAsString(access_type); @@ -80,22 +44,25 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable, cmMakefile* makefile = const_cast<cmMakefile*>(mf); std::string stack = makefile->GetProperty("LISTFILE_STACK"); - for ( it = handler->Commands.begin(); it != handler->Commands.end(); - ++ it ) + if ( !data->Command.empty() ) { - std::string command = *it; newLFF.Arguments.clear(); newLFF.Arguments.push_back( - cmListFileArgument(variable, true, "unknown", 9999)); + cmListFileArgument(variable, cmListFileArgument::Quoted, + "unknown", 9999)); newLFF.Arguments.push_back( - cmListFileArgument(accessString, true, "unknown", 9999)); + cmListFileArgument(accessString, cmListFileArgument::Quoted, + "unknown", 9999)); newLFF.Arguments.push_back( - cmListFileArgument(newValue?newValue:"", true, "unknown", 9999)); + cmListFileArgument(newValue?newValue:"", cmListFileArgument::Quoted, + "unknown", 9999)); newLFF.Arguments.push_back( - cmListFileArgument(currentListFile, true, "unknown", 9999)); + cmListFileArgument(currentListFile, cmListFileArgument::Quoted, + "unknown", 9999)); newLFF.Arguments.push_back( - cmListFileArgument(stack, true, "unknown", 9999)); - newLFF.Name = command; + cmListFileArgument(stack, cmListFileArgument::Quoted, + "unknown", 9999)); + newLFF.Name = data->Command; newLFF.FilePath = "Some weird path"; newLFF.Line = 9999; cmExecutionStatus status; @@ -106,10 +73,10 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable, cmOStringStream error; error << "Error in cmake code at\n" << arg.FilePath << ":" << arg.Line << ":\n" - << "A command failed during the invocation of callback\"" - << command << "\"."; + << "A command failed during the invocation of callback \"" + << data->Command << "\"."; cmSystemTools::Error(error.str().c_str()); - this->InCallback = false; + data->InCallback = false; return; } processed = true; @@ -117,24 +84,76 @@ 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?newValue:"") << "\"."; + makefile->IssueMessage(cmake::LOG, msg.str()); + } + + data->InCallback = false; +} + +//---------------------------------------------------------------------------- +static void deleteVariableWatchCallbackData(void* client_data) +{ + cmVariableWatchCallbackData* data + = static_cast<cmVariableWatchCallbackData*>(client_data); + delete data; +} + +//---------------------------------------------------------------------------- +cmVariableWatchCommand::cmVariableWatchCommand() +{ +} + +//---------------------------------------------------------------------------- +cmVariableWatchCommand::~cmVariableWatchCommand() +{ + std::set<std::string>::const_iterator it; + for ( it = this->WatchedVariables.begin(); + it != this->WatchedVariables.end(); + ++it ) + { + this->Makefile->GetCMakeInstance()->GetVariableWatch()->RemoveWatch( + *it, cmVariableWatchCommandVariableAccessed); + } +} + +//---------------------------------------------------------------------------- +bool cmVariableWatchCommand +::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) +{ + if ( args.size() < 1 ) + { + this->SetError("must be called with at least one argument."); + return false; + } + std::string variable = args[0]; + std::string command; + if ( args.size() > 1 ) + { + command = args[1]; } - this->InCallback = false; + if ( variable == "CMAKE_CURRENT_LIST_FILE" ) + { + cmOStringStream ostr; + ostr << "cannot be set on the variable: " << variable.c_str(); + this->SetError(ostr.str().c_str()); + return false; + } + + cmVariableWatchCallbackData* data = new cmVariableWatchCallbackData; + + data->InCallback = false; + data->Command = command; + + this->WatchedVariables.insert(variable); + if ( !this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch( + variable, cmVariableWatchCommandVariableAccessed, + data, deleteVariableWatchCallbackData) ) + { + deleteVariableWatchCallbackData(data); + return false; + } + + return true; } diff --git a/Source/cmVariableWatchCommand.h b/Source/cmVariableWatchCommand.h index 3abc08894..545535c40 100644 --- a/Source/cmVariableWatchCommand.h +++ b/Source/cmVariableWatchCommand.h @@ -14,13 +14,6 @@ #include "cmCommand.h" -class cmVariableWatchCommandHandler -{ -public: - typedef std::vector<std::string> VectorOfCommands; - VectorOfCommands Commands; -}; - /** \class cmVariableWatchCommand * \brief Watch when the variable changes and invoke command * @@ -39,6 +32,9 @@ public: //! Default constructor cmVariableWatchCommand(); + //! Destructor. + ~cmVariableWatchCommand(); + /** * This is called when the command is first encountered in * the CMakeLists.txt file. @@ -83,13 +79,8 @@ public: cmTypeMacro(cmVariableWatchCommand, cmCommand); - void VariableAccessed(const std::string& variable, int access_type, - const char* newValue, const cmMakefile* mf); - protected: - std::map<std::string, cmVariableWatchCommandHandler> Handlers; - - bool InCallback; + std::set<std::string> WatchedVariables; }; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 9cfb3703e..6376376a0 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -216,12 +216,16 @@ void cmVisualStudio10TargetGenerator::Generate() // Write the encoding header into the file char magic[] = {0xEF,0xBB, 0xBF}; this->BuildFileStream->write(magic, 3); - this->WriteString("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",0); - this->WriteString("<Project DefaultTargets=\"Build\" " - "ToolsVersion=\"4.0\" " - "xmlns=\"http://schemas.microsoft.com/" - "developer/msbuild/2003\">\n", - 0); + + //get the tools version to use + const std::string toolsVer(this->GlobalGenerator->GetToolsVersion()); + std::string project_defaults="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; + project_defaults.append("<Project DefaultTargets=\"Build\" ToolsVersion=\""); + project_defaults.append(toolsVer +"\" "); + project_defaults.append( + "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"); + this->WriteString(project_defaults.c_str(),0); + this->WriteProjectConfigurations(); this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1); this->WriteString("<ProjectGUID>", 2); @@ -274,6 +278,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 +296,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", @@ -291,6 +311,11 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteString( "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n", 1); this->WriteString("<ImportGroup Label=\"ExtensionSettings\">\n", 1); + if (this->GlobalGenerator->IsMasmEnabled()) + { + this->WriteString("<Import Project=\"$(VCTargetsPath)\\" + "BuildCustomizations\\masm.props\" />\n", 2); + } this->WriteString("</ImportGroup>\n", 1); this->WriteString("<ImportGroup Label=\"PropertySheets\">\n", 1); this->WriteString("<Import Project=\"" VS10_USER_PROPS "\"" @@ -303,12 +328,18 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteCustomCommands(); this->WriteAllSources(); this->WriteDotNetReferences(); + this->WriteEmbeddedResourceGroup(); this->WriteWinRTReferences(); this->WriteProjectReferences(); this->WriteString( "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\"" " />\n", 1); this->WriteString("<ImportGroup Label=\"ExtensionTargets\">\n", 1); + if (this->GlobalGenerator->IsMasmEnabled()) + { + this->WriteString("<Import Project=\"$(VCTargetsPath)\\" + "BuildCustomizations\\masm.targets\" />\n", 2); + } this->WriteString("</ImportGroup>\n", 1); this->WriteString("</Project>", 0); // The groups are stored in a separate file for VS 10 @@ -341,6 +372,47 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences() } } +void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() +{ + std::vector<cmSourceFile*> const& resxObjs = + this->GeneratorTarget->ResxSources; + if(!resxObjs.empty()) + { + this->WriteString("<ItemGroup>\n", 1); + for(std::vector<cmSourceFile*>::const_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("<DependentUpon>", 3); + std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h"; + (*this->BuildFileStream ) << hFileName; + this->WriteString("</DependentUpon>\n", 3); + + std::vector<std::string> const * configs = + this->GlobalGenerator->GetConfigurations(); + for(std::vector<std::string>::const_iterator i = configs->begin(); + i != configs->end(); ++i) + { + this->WritePlatformConfigTag("LogicalName", i->c_str(), 3); + if(this->Target->GetProperty("VS_GLOBAL_ROOTNAMESPACE")) + { + (*this->BuildFileStream ) << "$(RootNamespace)."; + } + (*this->BuildFileStream ) << "%(Filename)"; + (*this->BuildFileStream ) << ".resources"; + (*this->BuildFileStream ) << "</LogicalName>\n"; + } + + this->WriteString("</EmbeddedResource>\n", 2); + } + this->WriteString("</ItemGroup>\n", 1); + } +} + void cmVisualStudio10TargetGenerator::WriteWinRTReferences() { std::vector<std::string> references; @@ -467,6 +539,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() this->WriteString("<WindowsAppContainer>true" "</WindowsAppContainer>\n", 2); } + this->WriteString("</PropertyGroup>\n", 1); } } @@ -647,18 +720,40 @@ void cmVisualStudio10TargetGenerator::WriteGroups() fout.write(magic, 3); cmGeneratedFileStream* save = this->BuildFileStream; this->BuildFileStream = & fout; - this->WriteString("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" - "<Project " - "ToolsVersion=\"4.0\" " - "xmlns=\"http://schemas.microsoft.com/" - "developer/msbuild/2003\">\n", - 0); + + //get the tools version to use + const std::string toolsVer(this->GlobalGenerator->GetToolsVersion()); + std::string project_defaults="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; + project_defaults.append("<Project ToolsVersion=\""); + project_defaults.append(toolsVer +"\" "); + project_defaults.append( + "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"); + this->WriteString(project_defaults.c_str(),0); + for(ToolSourceMap::const_iterator ti = this->Tools.begin(); ti != this->Tools.end(); ++ti) { this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups); } + std::vector<cmSourceFile*> const& resxObjs = + this->GeneratorTarget->ResxSources; + if(!resxObjs.empty()) + { + this->WriteString("<ItemGroup>\n", 1); + for(std::vector<cmSourceFile*>::const_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 +808,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 +956,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); } @@ -876,24 +1000,37 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() si != this->GeneratorTarget->ObjectSources.end(); ++si) { const char* lang = (*si)->GetLanguage(); - bool cl = strcmp(lang, "C") == 0 || strcmp(lang, "CXX") == 0; - bool rc = strcmp(lang, "RC") == 0; - const char* tool = cl? "ClCompile" : (rc? "ResourceCompile" : "None"); - this->WriteSource(tool, *si, " "); - // ouput any flags specific to this source file - if(cl && this->OutputSourceSpecificFlags(*si)) + const char* tool = NULL; + if (strcmp(lang, "C") == 0 || strcmp(lang, "CXX") == 0) { - // if the source file has specific flags the tag - // is ended on a new line - this->WriteString("</ClCompile>\n", 2); + tool = "ClCompile"; } - else if(rc && this->OutputSourceSpecificFlags(*si)) + else if (strcmp(lang, "ASM_MASM") == 0 && + this->GlobalGenerator->IsMasmEnabled()) { - this->WriteString("</ResourceCompile>\n", 2); + tool = "MASM"; + } + else if (strcmp(lang, "RC") == 0) + { + tool = "ResourceCompile"; + } + + if (tool) + { + this->WriteSource(tool, *si, " "); + if (this->OutputSourceSpecificFlags(*si)) + { + this->WriteString("</", 2); + (*this->BuildFileStream ) << tool << ">\n"; + } + else + { + (*this->BuildFileStream ) << " />\n"; + } } else { - (*this->BuildFileStream ) << " />\n"; + this->WriteSource("None", *si); } } @@ -1192,7 +1329,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,21 +1356,21 @@ 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( - configName.c_str()).c_str()); + std::vector<std::string> targetDefines; + this->Target->GetCompileDefinitions(targetDefines, configName.c_str()); + clOptions.AddDefines(targetDefines); clOptions.SetVerboseMakefile( this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")); @@ -1272,18 +1409,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); } @@ -1294,7 +1420,9 @@ OutputIncludes(std::vector<std::string> const & includes) for(std::vector<std::string>::const_iterator i = includes.begin(); i != includes.end(); ++i) { - *this->BuildFileStream << *i << ";"; + std::string incDir = *i; + this->ConvertToWindowsSlash(incDir); + *this->BuildFileStream << cmVS10EscapeXML(incDir) << ";"; } this->WriteString("%(AdditionalIncludeDirectories)" "</AdditionalIncludeDirectories>\n", 0); @@ -1322,20 +1450,17 @@ cmVisualStudio10TargetGenerator::WriteLibOptions(std::string const& config) { return; } - const char* libflags = this->Target->GetProperty("STATIC_LIBRARY_FLAGS"); - std::string flagsConfigVar = "STATIC_LIBRARY_FLAGS_"; - flagsConfigVar += cmSystemTools::UpperCase(config); - const char* libflagsConfig = - this->Target->GetProperty(flagsConfigVar.c_str()); - if(libflags || libflagsConfig) + std::string libflags; + this->LocalGenerator->GetStaticLibraryFlags(libflags, + cmSystemTools::UpperCase(config), this->Target); + if(!libflags.empty()) { this->WriteString("<Lib>\n", 2); cmVisualStudioGeneratorOptions libOptions(this->LocalGenerator, cmVisualStudioGeneratorOptions::Linker, cmVSGetLibFlagTable(this->LocalGenerator), 0, this); - libOptions.Parse(libflags?libflags:""); - libOptions.Parse(libflagsConfig?libflagsConfig:""); + libOptions.Parse(libflags.c_str()); libOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", ""); libOptions.OutputFlagMap(*this->BuildFileStream, " "); this->WriteString("</Lib>\n", 2); @@ -1377,7 +1502,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; } @@ -1428,11 +1553,11 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) } if ( this->Target->GetPropertyAsBool("WIN32_EXECUTABLE") ) { - flags += " /SUBSYSTEM:WINDOWS"; + linkOptions.AddFlag("SubSystem", "Windows"); } else { - flags += " /SUBSYSTEM:CONSOLE"; + linkOptions.AddFlag("SubSystem", "Console"); } std::string standardLibsVar = "CMAKE_"; standardLibsVar += linkLanguage; @@ -1459,7 +1584,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 +1716,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 +1870,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 55a850a1b..9a480a87f 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -59,9 +59,11 @@ private: void WriteSources(const char* tool, std::vector<cmSourceFile*> const&); void WriteAllSources(); void WriteDotNetReferences(); + void WriteEmbeddedResourceGroup(); void WriteWinRTReferences(); void WritePathAndIncrementalLinkOptions(); void WriteItemDefinitionGroups(); + bool ComputeClOptions(); bool ComputeClOptions(std::string const& configName); void WriteClOptions(std::string const& config, @@ -91,7 +93,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 01950e16d..6aca787f5 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, ">", ">"); @@ -99,13 +100,13 @@ void cmVisualStudioGeneratorOptions::SetVerboseMakefile(bool verbose) } } -bool cmVisualStudioGeneratorOptions::IsDebug() +bool cmVisualStudioGeneratorOptions::IsDebug() const { return this->FlagMap.find("DebugInformationFormat") != this->FlagMap.end(); } //---------------------------------------------------------------------------- -bool cmVisualStudioGeneratorOptions::UsingUnicode() +bool cmVisualStudioGeneratorOptions::UsingUnicode() const { // Look for the a _UNICODE definition. for(std::vector<std::string>::const_iterator di = this->Defines.begin(); @@ -119,7 +120,7 @@ bool cmVisualStudioGeneratorOptions::UsingUnicode() return false; } //---------------------------------------------------------------------------- -bool cmVisualStudioGeneratorOptions::UsingSBCS() +bool cmVisualStudioGeneratorOptions::UsingSBCS() const { // Look for the a _SBCS definition. for(std::vector<std::string>::const_iterator di = this->Defines.begin(); @@ -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/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index a1a55daff..90f76672d 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -47,10 +47,10 @@ public: void SetVerboseMakefile(bool verbose); // Check for specific options. - bool UsingUnicode(); - bool UsingSBCS(); + bool UsingUnicode() const; + bool UsingSBCS() const; - bool IsDebug(); + bool IsDebug() const; // Write options to output. void OutputPreprocessorDefinitions(std::ostream& fout, const char* prefix, diff --git a/Source/cmVisualStudioSlnData.cxx b/Source/cmVisualStudioSlnData.cxx new file mode 100644 index 000000000..82b4ee84f --- /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 000000000..ec128cf11 --- /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 000000000..bae59740a --- /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 000000000..bee70cc13 --- /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/cmVisualStudioWCEPlatformParser.cxx b/Source/cmVisualStudioWCEPlatformParser.cxx index b302246ea..219a5eb49 100644 --- a/Source/cmVisualStudioWCEPlatformParser.cxx +++ b/Source/cmVisualStudioWCEPlatformParser.cxx @@ -20,8 +20,12 @@ int cmVisualStudioWCEPlatformParser::ParseVersion(const char* version) const std::string vckey = registryBase + "\\Setup\\VC;ProductDir"; const std::string vskey = registryBase + "\\Setup\\VS;ProductDir"; - if(!cmSystemTools::ReadRegistryValue(vckey.c_str(), this->VcInstallDir) || - !cmSystemTools::ReadRegistryValue(vskey.c_str(), this->VsInstallDir)) + if(!cmSystemTools::ReadRegistryValue(vckey.c_str(), + this->VcInstallDir, + cmSystemTools::KeyWOW64_32) || + !cmSystemTools::ReadRegistryValue(vskey.c_str(), + this->VsInstallDir, + cmSystemTools::KeyWOW64_32)) { return 0; } diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 400034582..7d2eeadd6 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -49,9 +49,9 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf, unsigned int i; for(i =0; i < this->Args.size(); ++i) { - err += (this->Args[i].Quoted?"\"":""); + err += (this->Args[i].Delim?"\"":""); err += this->Args[i].Value; - err += (this->Args[i].Quoted?"\"":""); + err += (this->Args[i].Delim?"\"":""); err += " "; } err += "("; diff --git a/Source/cmWin32ProcessExecution.cxx b/Source/cmWin32ProcessExecution.cxx index 5752ab61c..1bdeffbed 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 98b6bda98..2127ebd2e 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/cm_sha2.c b/Source/cm_sha2.c index 12c39ed63..24de2b294 100644 --- a/Source/cm_sha2.c +++ b/Source/cm_sha2.c @@ -740,7 +740,8 @@ void SHA1_Final(sha_byte digest[], SHA_CTX* context) { /* Convert FROM host byte order */ REVERSE64(context->s1.bitcount,context->s1.bitcount); #endif - *(sha_word64*)&context->s1.buffer[56] = context->s1.bitcount; + MEMCPY_BCOPY(&context->s1.buffer[56], &context->s1.bitcount, + sizeof(sha_word64)); /* Final transform: */ SHA1_Internal_Transform(context, (sha_word32*)context->s1.buffer); @@ -1067,7 +1068,8 @@ void SHA256_Internal_Last(SHA_CTX* context) { *context->s256.buffer = 0x80; } /* Set the bit count: */ - *(sha_word64*)&context->s256.buffer[56] = context->s256.bitcount; + MEMCPY_BCOPY(&context->s256.buffer[56], &context->s256.bitcount, + sizeof(sha_word64)); /* Final transform: */ SHA256_Internal_Transform(context, (sha_word32*)context->s256.buffer); @@ -1475,8 +1477,10 @@ void SHA512_Internal_Last(SHA_CTX* context) { *context->s512.buffer = 0x80; } /* Store the length of input data (in bits): */ - *(sha_word64*)&context->s512.buffer[112] = context->s512.bitcount[1]; - *(sha_word64*)&context->s512.buffer[120] = context->s512.bitcount[0]; + MEMCPY_BCOPY(&context->s512.buffer[112], &context->s512.bitcount[1], + sizeof(sha_word64)); + MEMCPY_BCOPY(&context->s512.buffer[120], &context->s512.bitcount[0], + sizeof(sha_word64)); /* Final transform: */ SHA512_Internal_Transform(context, (sha_word64*)context->s512.buffer); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 376758e48..14ddc1b01 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); } } @@ -601,7 +612,7 @@ bool cmake::FindPackage(const std::vector<std::string>& args) std::vector<std::string> includeDirs; cmSystemTools::ExpandListArgument(includes, includeDirs); - std::string includeFlags = lg->GetIncludeFlags(includeDirs, + std::string includeFlags = lg->GetIncludeFlags(includeDirs, 0, language.c_str(), false); std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS"); @@ -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" @@ -1724,10 +1734,11 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& args) { return cmake::ExecuteEchoColor(args); } - else if (args[1] == "cmake_automoc") + else if (args[1] == "cmake_automoc" && args.size() >= 4) { 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) @@ -3595,6 +3607,14 @@ void cmake::DefineProperties(cmake *cm) "for the FOLDER target property."); cm->DefineProperty + ("AUTOMOC_TARGETS_FOLDER", cmProperty::GLOBAL, + "Name of FOLDER for *_automoc targets that are added automatically by " + "CMake for targets for which AUTOMOC is enabled.", + "If not set, CMake uses the FOLDER property of the parent target as a " + "default value for this property. See also the documentation for the " + "FOLDER target property and the AUTOMOC target property."); + + cm->DefineProperty ("PREDEFINED_TARGETS_FOLDER", cmProperty::GLOBAL, "Name of FOLDER for targets that are added automatically by CMake.", "If not set, CMake uses \"CMakePredefinedTargets\" as a default " @@ -3647,11 +3667,11 @@ void cmake::RecordPropertyAccess(const char *name, void cmake::ReportUndefinedPropertyAccesses(const char *filename) { + if(!this->GlobalGenerator) + { return; } FILE *progFile = fopen(filename,"w"); - if (!progFile || !this->GlobalGenerator) - { - return; - } + if(!progFile) + { return; } // what are the enabled languages? std::vector<std::string> enLangs; @@ -4049,7 +4069,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 +4141,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 +4197,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 63065a17c..a50c1ed02 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 42678419e..68d833964 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -62,7 +62,10 @@ static const char * cmDocumentationDescription[][3] = " --config <cfg> = For multi-configuration tools, choose <cfg>.\n" \ " --clean-first = Build target 'clean' first, then build.\n" \ " (To clean only, use --target 'clean'.)\n" \ - " --use-stderr = Don't merge stdout/stderr.\n" \ + " --use-stderr = Don't merge stdout/stderr output and pass the\n" \ + " original stdout/stderr handles to the native\n" \ + " tool so it can use the capabilities of the\n" \ + " calling terminal (e.g. colored output).\n" \ " -- = Pass remaining options to the native tool.\n" //---------------------------------------------------------------------------- @@ -86,8 +89,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."}, @@ -108,9 +111,11 @@ static const char * cmDocumentationOptions[][3] = "to stdout. This can be used to use cmake instead of pkg-config to find " "installed libraries in plain Makefile-based projects or in " "autoconf-based projects (via share/aclocal/cmake.m4)."}, - {"--graphviz=[file]", "Generate graphviz of dependencies.", + {"--graphviz=[file]", "Generate graphviz of dependencies, see " + "CMakeGraphVizOptions.cmake for more.", "Generate a graphviz input file that will contain all the library and " - "executable dependencies in the project."}, + "executable dependencies in the project. See the documentation for " + "CMakeGraphVizOptions.cmake for more details. "}, {"--system-information [file]", "Dump information about this system.", "Dump a wide range of information about the current system. If run " "from the top of a binary tree for a CMake project it will dump " @@ -152,7 +157,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."}, @@ -604,7 +609,7 @@ static int do_build(int ac, char** av) } else if(strcmp(av[i], "--use-stderr") == 0) { - outputflag = cmSystemTools::OUTPUT_NORMAL; + outputflag = cmSystemTools::OUTPUT_PASSTHROUGH; } else if(strcmp(av[i], "--") == 0) { diff --git a/Source/cmakewizard.cxx b/Source/cmakewizard.cxx index 749f669d0..bac403a89 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 04dab59d0..85715574f 100644 --- a/Source/cmcldeps.cxx +++ b/Source/cmcldeps.cxx @@ -62,8 +62,8 @@ static std::string trimLeadingSpace(const std::string& cmdline) { return cmdline.substr(i); } -static void doEscape(std::string& str, const std::string& search, - const std::string& repl) { +static void replaceAll(std::string& str, const std::string& search, + const std::string& repl) { std::string::size_type pos = 0; while ((pos = str.find(search, pos)) != std::string::npos) { str.replace(pos, search.size(), repl); @@ -71,6 +71,10 @@ static void doEscape(std::string& str, const std::string& search, } } +bool startsWith(const std::string& str, const std::string& what) { + return str.compare(0, what.size(), what) == 0; +} + // Strips one argument from the cmdline and returns it. "surrounding quotes" // are removed from the argument if there were any. static std::string getArg(std::string& cmdline) { @@ -117,6 +121,13 @@ static void parseCommandLine(LPTSTR wincmdline, rest = trimLeadingSpace(cmdline); } +// Not all backslashes need to be escaped in a depfile, but it's easier that +// way. See the re2c grammar in ninja's source code for more info. +static void escapePath(std::string &path) { + replaceAll(path, "\\", "\\\\"); + replaceAll(path, " ", "\\ "); +} + static void outputDepFile(const std::string& dfile, const std::string& objfile, std::vector<std::string>& incs) { @@ -132,16 +143,24 @@ static void outputDepFile(const std::string& dfile, const std::string& objfile, // FIXME should this be fatal or not? delete obj? delete d? if (!out) return; + std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); + replaceAll(cwd, "/", "\\"); + cwd += "\\"; std::string tmp = objfile; - doEscape(tmp, " ", "\\ "); + escapePath(tmp); fprintf(out, "%s: \\\n", tmp.c_str()); std::vector<std::string>::iterator it = incs.begin(); for (; it != incs.end(); ++it) { tmp = *it; - doEscape(tmp, "\\", "/"); - doEscape(tmp, " ", "\\ "); + // The paths need to match the ones used to identify build artifacts in the + // build.ninja file. Therefore we need to canonicalize the path to use + // backward slashes and relativize the path to the build directory. + replaceAll(tmp, "/", "\\"); + if (startsWith(tmp, cwd)) + tmp = tmp.substr(cwd.size()); + escapePath(tmp); fprintf(out, "%s \\\n", tmp.c_str()); } @@ -150,10 +169,6 @@ static void outputDepFile(const std::string& dfile, const std::string& objfile, } -bool startsWith(const std::string& str, const std::string& what) { - return str.compare(0, what.size(), what) == 0; -} - bool contains(const std::string& str, const std::string& what) { return str.find(what) != std::string::npos; } @@ -225,7 +240,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 3e63183eb..e767a1612 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 124b8aca0..0f2783689 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) @@ -640,6 +649,68 @@ IF(KWSYS_USE_SystemInformation) SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_CXX_HAS__ATOI64=1) ENDIF() + IF(UNIX) + INCLUDE(CheckIncludeFileCXX) + # check for simple stack trace + # usually it's in libc but on FreeBSD + # it's in libexecinfo + FIND_LIBRARY(EXECINFO_LIB "execinfo") + IF (NOT EXECINFO_LIB) + SET(EXECINFO_LIB "") + ENDIF() + CHECK_INCLUDE_FILE_CXX("execinfo.h" KWSYS_CXX_HAS_EXECINFOH) + IF (KWSYS_CXX_HAS_EXECINFOH) + # we have the backtrace header check if it + # can be used with this compiler + SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB}) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BACKTRACE + "Checking whether backtrace works with this C++ compiler" DIRECT) + SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) + IF (KWSYS_CXX_HAS_BACKTRACE) + # backtrace is supported by this system and compiler. + # now check for the more advanced capabilities. + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE=1) + # check for symbol lookup using dladdr + CHECK_INCLUDE_FILE_CXX("dlfcn.h" KWSYS_CXX_HAS_DLFCNH) + IF (KWSYS_CXX_HAS_DLFCNH) + # we have symbol lookup libraries and headers + # check if they can be used with this compiler + SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${CMAKE_DL_LIBS}) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_DLADDR + "Checking whether dladdr works with this C++ compiler" DIRECT) + SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) + IF (KWSYS_CXX_HAS_DLADDR) + # symbol lookup is supported by this system + # and compiler. + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP=1) + ENDIF() + ENDIF() + # c++ demangling support + # check for cxxabi headers + CHECK_INCLUDE_FILE_CXX("cxxabi.h" KWSYS_CXX_HAS_CXXABIH) + IF (KWSYS_CXX_HAS_CXXABIH) + # check if cxxabi can be used with this + # system and compiler. + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CXXABI + "Checking whether cxxabi works with this C++ compiler" DIRECT) + IF (KWSYS_CXX_HAS_CXXABI) + # c++ demangle using cxxabi is supported with + # this system and compiler + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE=1) + ENDIF() + ENDIF() + # basic backtrace works better with release build + # don't bother with advanced features for release + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS_DEBUG KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS_RELWITHDEBINFO KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1) + ENDIF() + ENDIF() + ENDIF() IF(BORLAND) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM "Checking whether Borland CXX compiler supports assembler instructions" DIRECT) @@ -904,12 +975,23 @@ IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS) ENDIF(UNIX) ENDIF(KWSYS_USE_DynamicLoader) - IF(KWSYS_USE_SystemInformation AND WIN32) - TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ws2_32) - IF(KWSYS_SYS_HAS_PSAPI) - TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} Psapi) + IF(KWSYS_USE_SystemInformation) + IF(WIN32) + TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ws2_32) + IF(KWSYS_SYS_HAS_PSAPI) + TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} Psapi) + ENDIF() + ELSEIF(UNIX) + IF (EXECINFO_LIB AND KWSYS_CXX_HAS_BACKTRACE) + # backtrace on FreeBSD is not in libc + TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ${EXECINFO_LIB}) + ENDIF() + IF (KWSYS_CXX_HAS_DLADDR) + # for symbol lookup using dladdr + TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE} ${CMAKE_DL_LIBS}) + ENDIF() ENDIF() - ENDIF(KWSYS_USE_SystemInformation AND WIN32) + ENDIF() # Apply user-defined target properties to the library. IF(KWSYS_PROPERTIES_CXX) diff --git a/Source/kwsys/CommandLineArguments.hxx.in b/Source/kwsys/CommandLineArguments.hxx.in index 68e9600ef..cbf6ee393 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/RegularExpression.cxx b/Source/kwsys/RegularExpression.cxx index f6eeebae4..c8297873f 100644 --- a/Source/kwsys/RegularExpression.cxx +++ b/Source/kwsys/RegularExpression.cxx @@ -312,8 +312,8 @@ static char* regbranch (int*); static char* regpiece (int*); static char* regatom (int*); static char* regnode (char); -static const char* regnext (register const char*); -static char* regnext (register char*); +static const char* regnext (const char*); +static char* regnext (char*); static void regc (char); static void reginsert (char, char*); static void regtail (char*, const char*); @@ -344,10 +344,10 @@ static int strcspn (); // for later pattern matching. bool RegularExpression::compile (const char* exp) { - register const char* scan; - register const char* longest; - register size_t len; - int flags; + const char* scan; + const char* longest; + size_t len; + int flags; if (exp == 0) { //RAISE Error, SYM(RegularExpression), SYM(No_Expr), @@ -444,11 +444,11 @@ bool RegularExpression::compile (const char* exp) { * follows makes it hard to avoid. */ static char* reg (int paren, int *flagp) { - register char* ret; - register char* br; - register char* ender; - register int parno =0; - int flags; + char* ret; + char* br; + char* ender; + int parno =0; + int flags; *flagp = HASWIDTH; // Tentatively. @@ -525,10 +525,10 @@ static char* reg (int paren, int *flagp) { * Implements the concatenation operator. */ static char* regbranch (int *flagp) { - register char* ret; - register char* chain; - register char* latest; - int flags; + char* ret; + char* chain; + char* latest; + int flags; *flagp = WORST; // Tentatively. @@ -562,10 +562,10 @@ static char* regbranch (int *flagp) { * endmarker role is not redundant. */ static char* regpiece (int *flagp) { - register char* ret; - register char op; - register char* next; - int flags; + char* ret; + char op; + char* next; + int flags; ret = regatom(&flags); if (ret == 0) @@ -631,8 +631,8 @@ static char* regpiece (int *flagp) { * separate node; the code is simpler that way and it's not worth fixing. */ static char* regatom (int *flagp) { - register char* ret; - int flags; + char* ret; + int flags; *flagp = WORST; // Tentatively. @@ -648,8 +648,8 @@ static char* regatom (int *flagp) { *flagp |= HASWIDTH | SIMPLE; break; case '[':{ - register int rxpclass; - register int rxpclassend; + int rxpclass; + int rxpclassend; if (*regparse == '^') { // Complement of range. ret = regnode(ANYBUT); @@ -720,8 +720,8 @@ static char* regatom (int *flagp) { *flagp |= HASWIDTH | SIMPLE; break; default:{ - register int len; - register char ender; + int len; + char ender; regparse--; len = int(strcspn(regparse, META)); @@ -754,8 +754,8 @@ static char* regatom (int *flagp) { Location. */ static char* regnode (char op) { - register char* ret; - register char* ptr; + char* ret; + char* ptr; ret = regcode; if (ret == ®dummy) { @@ -790,9 +790,9 @@ static void regc (char b) { * Means relocating the operand. */ static void reginsert (char op, char* opnd) { - register char* src; - register char* dst; - register char* place; + char* src; + char* dst; + char* place; if (regcode == ®dummy) { regsize += 3; @@ -816,9 +816,9 @@ static void reginsert (char op, char* opnd) { - regtail - set the next-pointer at the end of a node chain */ static void regtail (char* p, const char* val) { - register char* scan; - register char* temp; - register int offset; + char* scan; + char* temp; + int offset; if (p == ®dummy) return; @@ -893,7 +893,7 @@ bool RegularExpression::find (kwsys_stl::string const& s) // Returns true if found, and sets start and end indexes accordingly. bool RegularExpression::find (const char* string) { - register const char* s; + const char* s; this->searchstring = string; @@ -956,9 +956,9 @@ bool RegularExpression::find (const char* string) { */ static int regtry (const char* string, const char* *start, const char* *end, const char* prog) { - register int i; - register const char* *sp1; - register const char* *ep; + int i; + const char* *sp1; + const char* *ep; reginput = string; regstartp = start; @@ -992,8 +992,8 @@ static int regtry (const char* string, const char* *start, * 0 failure, 1 success */ static int regmatch (const char* prog) { - register const char* scan; // Current node. - const char* next; // Next node. + const char* scan; // Current node. + const char* next; // Next node. scan = prog; @@ -1016,8 +1016,8 @@ static int regmatch (const char* prog) { reginput++; break; case EXACTLY:{ - register size_t len; - register const char* opnd; + size_t len; + const char* opnd; opnd = OPERAND(scan); // Inline the first character, for speed. @@ -1052,8 +1052,8 @@ static int regmatch (const char* prog) { case OPEN + 7: case OPEN + 8: case OPEN + 9:{ - register int no; - register const char* save; + int no; + const char* save; no = OP(scan) - OPEN; save = reginput; @@ -1081,8 +1081,8 @@ static int regmatch (const char* prog) { case CLOSE + 7: case CLOSE + 8: case CLOSE + 9:{ - register int no; - register const char* save; + int no; + const char* save; no = OP(scan) - CLOSE; save = reginput; @@ -1103,7 +1103,7 @@ static int regmatch (const char* prog) { // break; case BRANCH:{ - register const char* save; + const char* save; if (OP(next) != BRANCH) // No choice. next = OPERAND(scan); // Avoid recursion. @@ -1122,10 +1122,10 @@ static int regmatch (const char* prog) { break; case STAR: case PLUS:{ - register char nextch; - register int no; - register const char* save; - register int min_no; + char nextch; + int no; + const char* save; + int min_no; // // Lookahead to avoid useless match attempts when we know @@ -1174,9 +1174,9 @@ static int regmatch (const char* prog) { - regrepeat - repeatedly match something simple, report how many */ static int regrepeat (const char* p) { - register int count = 0; - register const char* scan; - register const char* opnd; + int count = 0; + const char* scan; + const char* opnd; scan = reginput; opnd = OPERAND(p); @@ -1216,8 +1216,8 @@ static int regrepeat (const char* p) { /* - regnext - dig the "next" pointer out of a node */ -static const char* regnext (register const char* p) { - register int offset; +static const char* regnext (const char* p) { + int offset; if (p == ®dummy) return (0); @@ -1232,8 +1232,8 @@ static const char* regnext (register const char* p) { return (p + offset); } -static char* regnext (register char* p) { - register int offset; +static char* regnext (char* p) { + int offset; if (p == ®dummy) return (0); diff --git a/Source/kwsys/SharedForward.h.in b/Source/kwsys/SharedForward.h.in index 8521099ad..8bbc74ac2 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 9e2a93d7c..beefd7d73 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -18,6 +18,10 @@ # include <winsock.h> // WSADATA, include before sys/types.h #endif +#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +#endif + // TODO: // We need an alternative implementation for many functions in this file // when USE_ASM_INSTRUCTIONS gets defined as 0. @@ -114,8 +118,15 @@ typedef int siginfo_t; # define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN # endif # if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0 >= 1050 -# include <execinfo.h> -# define KWSYS_SYSTEMINFORMATION_HAVE_BACKTRACE +# if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) +# include <execinfo.h> +# if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) +# include <cxxabi.h> +# endif +# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) +# include <dlfcn.h> +# endif +# endif # endif #endif @@ -130,10 +141,13 @@ typedef int siginfo_t; # define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN # endif # endif -# if defined(__GNUC__) +# if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) # include <execinfo.h> -# if !(defined(__LSB_VERSION__) && __LSB_VERSION__ < 41) -# define KWSYS_SYSTEMINFORMATION_HAVE_BACKTRACE +# if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) +# include <cxxabi.h> +# endif +# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) +# include <dlfcn.h> # endif # endif # if defined(KWSYS_CXX_HAS_RLIMIT64) @@ -357,6 +371,10 @@ public: static void SetStackTraceOnError(int enable); + // get current stack + static + kwsys_stl::string GetProgramStack(int firstFrame, int wholePath); + /** Run the different checks */ void RunCPUCheck(); void RunOSCheck(); @@ -812,6 +830,11 @@ void SystemInformation::SetStackTraceOnError(int enable) SystemInformationImplementation::SetStackTraceOnError(enable); } +kwsys_stl::string SystemInformation::GetProgramStack(int firstFrame, int wholePath) +{ + return SystemInformationImplementation::GetProgramStack(firstFrame, wholePath); +} + /** Run the different checks */ void SystemInformation::RunCPUCheck() { @@ -908,6 +931,12 @@ int LoadLines( } continue; } + char *pBuf=buf; + while(*pBuf) + { + if (*pBuf=='\n') *pBuf='\0'; + pBuf+=1; + } lines.push_back(buf); ++nRead; } @@ -1046,12 +1075,29 @@ void StacktraceSignalHandler( #if defined(__linux) || defined(__APPLE__) kwsys_ios::ostringstream oss; oss + << kwsys_ios::endl << "=========================================================" << kwsys_ios::endl << "Process id " << getpid() << " "; switch (sigNo) { + case SIGINT: + oss << "Caught SIGINT"; + break; + + case SIGTERM: + oss << "Caught SIGTERM"; + break; + + case SIGABRT: + oss << "Caught SIGABRT"; + break; + case SIGFPE: - oss << "Caught SIGFPE "; + oss + << "Caught SIGFPE at " + << (sigInfo->si_addr==0?"0x":"") + << sigInfo->si_addr + << " "; switch (sigInfo->si_code) { # if defined(FPE_INTDIV) @@ -1099,7 +1145,11 @@ void StacktraceSignalHandler( break; case SIGSEGV: - oss << "Caught SIGSEGV "; + oss + << "Caught SIGSEGV at " + << (sigInfo->si_addr==0?"0x":"") + << sigInfo->si_addr + << " "; switch (sigInfo->si_code) { case SEGV_MAPERR: @@ -1116,16 +1166,12 @@ void StacktraceSignalHandler( } break; - case SIGINT: - oss << "Caught SIGTERM"; - break; - - case SIGTERM: - oss << "Caught SIGTERM"; - break; - case SIGBUS: - oss << "Caught SIGBUS type "; + oss + << "Caught SIGBUS at " + << (sigInfo->si_addr==0?"0x":"") + << sigInfo->si_addr + << " "; switch (sigInfo->si_code) { case BUS_ADRALN: @@ -1134,13 +1180,25 @@ void StacktraceSignalHandler( # if defined(BUS_ADRERR) case BUS_ADRERR: - oss << "non-exestent physical address"; + oss << "nonexistent physical address"; break; # endif # if defined(BUS_OBJERR) case BUS_OBJERR: - oss << "object specific hardware error"; + oss << "object-specific hardware error"; + break; +# endif + +# if defined(BUS_MCEERR_AR) + case BUS_MCEERR_AR: + oss << "Hardware memory error consumed on a machine check; action required."; + break; +# endif + +# if defined(BUS_MCEERR_AO) + case BUS_MCEERR_AO: + oss << "Hardware memory error detected in process but not consumed; action optional."; break; # endif @@ -1151,7 +1209,11 @@ void StacktraceSignalHandler( break; case SIGILL: - oss << "Caught SIGILL "; + oss + << "Caught SIGILL at " + << (sigInfo->si_addr==0?"0x":"") + << sigInfo->si_addr + << " "; switch (sigInfo->si_code) { case ILL_ILLOPC: @@ -1205,20 +1267,16 @@ void StacktraceSignalHandler( oss << "Caught " << sigNo << " code " << sigInfo->si_code; break; } - oss << kwsys_ios::endl; -#if defined(KWSYS_SYSTEMINFORMATION_HAVE_BACKTRACE) - oss << "Program Stack:" << kwsys_ios::endl; - void *stackSymbols[128]; - int n=backtrace(stackSymbols,128); - char **stackText=backtrace_symbols(stackSymbols,n); - for (int i=0; i<n; ++i) - { - oss << " " << stackText[i] << kwsys_ios::endl; - } -#endif oss - << "=========================================================" << kwsys_ios::endl; + << kwsys_ios::endl + << "Program Stack:" << kwsys_ios::endl + << SystemInformationImplementation::GetProgramStack(2,0) + << "=========================================================" << kwsys_ios::endl; kwsys_ios::cerr << oss.str() << kwsys_ios::endl; + + // restore the previously registered handlers + // and abort + SystemInformationImplementation::SetStackTraceOnError(0); abort(); #else // avoid warning C4100 @@ -1227,8 +1285,213 @@ void StacktraceSignalHandler( #endif } #endif + +#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) +#define safes(_arg)((_arg)?(_arg):"???") + +// Description: +// A container for symbol properties. Each instance +// must be Initialized. +class SymbolProperties +{ +public: + SymbolProperties(); + + // Description: + // The SymbolProperties instance must be initialized by + // passing a stack address. + void Initialize(void *address); + + // Description: + // Get the symbol's stack address. + void *GetAddress() const { return this->Address; } + + // Description: + // If not set paths will be removed. eg, from a binary + // or source file. + void SetReportPath(int rp){ this->ReportPath=rp; } + + // Description: + // Set/Get the name of the binary file that the symbol + // is found in. + void SetBinary(const char *binary) + { this->Binary=safes(binary); } + + kwsys_stl::string GetBinary() const; + + // Description: + // Set the name of the function that the symbol is found in. + // If c++ demangling is supported it will be demangled. + void SetFunction(const char *function) + { this->Function=this->Demangle(function); } + + kwsys_stl::string GetFunction() const + { return this->Function; } + + // Description: + // Set/Get the name of the source file where the symbol + // is defined. + void SetSourceFile(const char *sourcefile) + { this->SourceFile=safes(sourcefile); } + + kwsys_stl::string GetSourceFile() const + { return this->GetFileName(this->SourceFile); } + + // Description: + // Set/Get the line number where the symbol is defined + void SetLineNumber(long linenumber){ this->LineNumber=linenumber; } + long GetLineNumber() const { return this->LineNumber; } + + // Description: + // Set the address where the biinary image is mapped + // into memory. + void SetBinaryBaseAddress(void *address) + { this->BinaryBaseAddress=address; } + +private: + void *GetRealAddress() const + { return (void*)((char*)this->Address-(char*)this->BinaryBaseAddress); } + + kwsys_stl::string GetFileName(const kwsys_stl::string &path) const; + kwsys_stl::string Demangle(const char *symbol) const; + +private: + kwsys_stl::string Binary; + void *BinaryBaseAddress; + void *Address; + kwsys_stl::string SourceFile; + kwsys_stl::string Function; + long LineNumber; + int ReportPath; +}; + +// -------------------------------------------------------------------------- +kwsys_ios::ostream &operator<<( + kwsys_ios::ostream &os, + const SymbolProperties &sp) +{ +#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) + os + << kwsys_ios::hex << sp.GetAddress() << " : " + << sp.GetFunction() + << " [(" << sp.GetBinary() << ") " + << sp.GetSourceFile() << ":" + << kwsys_ios::dec << sp.GetLineNumber() << "]"; +#elif defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) + void *addr = sp.GetAddress(); + char **syminfo = backtrace_symbols(&addr,1); + os << safes(syminfo[0]); + free(syminfo); +#else + (void)os; + (void)sp; +#endif + return os; +} + +// -------------------------------------------------------------------------- +SymbolProperties::SymbolProperties() +{ + // not using an initializer list + // to avoid some PGI compiler warnings + this->SetBinary("???"); + this->SetBinaryBaseAddress(NULL); + this->Address = NULL; + this->SetSourceFile("???"); + this->SetFunction("???"); + this->SetLineNumber(-1); + this->SetReportPath(0); + // avoid PGI compiler warnings + this->GetRealAddress(); + this->GetFunction(); + this->GetSourceFile(); + this->GetLineNumber(); +} + +// -------------------------------------------------------------------------- +kwsys_stl::string SymbolProperties::GetFileName(const kwsys_stl::string &path) const +{ + kwsys_stl::string file(path); + if (!this->ReportPath) + { + size_t at = file.rfind("/"); + if (at!=kwsys_stl::string::npos) + { + file = file.substr(at+1,kwsys_stl::string::npos); + } + } + return file; +} + +// -------------------------------------------------------------------------- +kwsys_stl::string SymbolProperties::GetBinary() const +{ +// only linux has proc fs +#if defined(__linux__) + if (this->Binary=="/proc/self/exe") + { + kwsys_stl::string binary; + char buf[1024]={'\0'}; + ssize_t ll=0; + if ((ll=readlink("/proc/self/exe",buf,1024))>0) + { + buf[ll]='\0'; + binary=buf; + } + else + { + binary="/proc/self/exe"; + } + return this->GetFileName(binary); + } +#endif + return this->GetFileName(this->Binary); +} + +// -------------------------------------------------------------------------- +kwsys_stl::string SymbolProperties::Demangle(const char *symbol) const +{ + kwsys_stl::string result = safes(symbol); +#if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) + int status = 0; + size_t bufferLen = 1024; + char *buffer = (char*)malloc(1024); + char *demangledSymbol = + abi::__cxa_demangle(symbol, buffer, &bufferLen, &status); + if (!status) + { + result = demangledSymbol; + } + free(buffer); +#else + (void)symbol; +#endif + return result; +} + +// -------------------------------------------------------------------------- +void SymbolProperties::Initialize(void *address) +{ + this->Address = address; +#if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) + // first fallback option can demangle c++ functions + Dl_info info; + int ierr=dladdr(this->Address,&info); + if (ierr && info.dli_sname && info.dli_saddr) + { + this->SetBinary(info.dli_fname); + this->SetFunction(info.dli_sname); + } +#else + // second fallback use builtin backtrace_symbols + // to decode the bactrace. +#endif +} +#endif // don't define this class if we're not using it + } // anonymous namespace + SystemInformationImplementation::SystemInformationImplementation() { this->TotalVirtualMemory = 0; @@ -1471,7 +1734,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( @@ -3336,12 +3599,61 @@ SystemInformationImplementation::GetProcessId() } /** +return current program stack in a string +demangle cxx symbols if possible. +*/ +kwsys_stl::string SystemInformationImplementation::GetProgramStack( + int firstFrame, + int wholePath) +{ + kwsys_stl::string programStack = "" +#if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) + "WARNING: The stack could not be examined " + "because backtrace is not supported.\n" +#elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD) + "WARNING: The stack trace will not use advanced " + "capabilities because this is a release build.\n" +#else +# if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) + "WARNING: Function names will not be demangled because " + "dladdr is not available.\n" +# endif +# if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) + "WARNING: Function names will not be demangled " + "because cxxabi is not available.\n" +# endif +#endif + ; + + kwsys_ios::ostringstream oss; +#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) + void *stackSymbols[256]; + int nFrames=backtrace(stackSymbols,256); + for (int i=firstFrame; i<nFrames; ++i) + { + SymbolProperties symProps; + symProps.SetReportPath(wholePath); + symProps.Initialize(stackSymbols[i]); + oss << symProps << kwsys_ios::endl; + } +#else + (void)firstFrame; + (void)wholePath; +#endif + programStack += oss.str(); + + return programStack; +} + + +/** when set print stack trace in response to common signals. */ void SystemInformationImplementation::SetStackTraceOnError(int enable) { #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) static int saOrigValid=0; + static struct sigaction saABRTOrig; static struct sigaction saSEGVOrig; static struct sigaction saTERMOrig; static struct sigaction saINTOrig; @@ -3349,9 +3661,11 @@ void SystemInformationImplementation::SetStackTraceOnError(int enable) static struct sigaction saBUSOrig; static struct sigaction saFPEOrig; + if (enable && !saOrigValid) { // save the current actions + sigaction(SIGABRT,0,&saABRTOrig); sigaction(SIGSEGV,0,&saSEGVOrig); sigaction(SIGTERM,0,&saTERMOrig); sigaction(SIGINT,0,&saINTOrig); @@ -3365,9 +3679,10 @@ void SystemInformationImplementation::SetStackTraceOnError(int enable) // install ours struct sigaction sa; sa.sa_sigaction=(SigAction)StacktraceSignalHandler; - sa.sa_flags=SA_SIGINFO|SA_RESTART; + sa.sa_flags=SA_SIGINFO|SA_RESTART|SA_RESETHAND; sigemptyset(&sa.sa_mask); + sigaction(SIGABRT,&sa,0); sigaction(SIGSEGV,&sa,0); sigaction(SIGTERM,&sa,0); sigaction(SIGINT,&sa,0); @@ -3379,6 +3694,7 @@ void SystemInformationImplementation::SetStackTraceOnError(int enable) if (!enable && saOrigValid) { // restore previous actions + sigaction(SIGABRT,&saABRTOrig,0); sigaction(SIGSEGV,&saSEGVOrig,0); sigaction(SIGTERM,&saTERMOrig,0); sigaction(SIGINT,&saINTOrig,0); @@ -3487,7 +3803,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 8f4cb4e5a..a9fd05def 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, @@ -136,6 +136,12 @@ public: static void SetStackTraceOnError(int enable); + // format and return the current program stack in a string. In + // order to produce an informative stack trace the application + // should be dynamically linked and compiled with debug symbols. + static + kwsys_stl::string GetProgramStack(int firstFrame, int wholePath); + /** Run the different checks */ void RunCPUCheck(); void RunOSCheck(); diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 8b25d608d..e9a1fd37d 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) @@ -695,6 +695,52 @@ void SystemTools::ReplaceString(kwsys_stl::string& source, #endif #if defined(_WIN32) && !defined(__CYGWIN__) +static bool SystemToolsParseRegistryKey(const char* key, + HKEY& primaryKey, + kwsys_stl::string& second, + kwsys_stl::string& valuename) +{ + kwsys_stl::string primary = key; + + size_t start = primary.find("\\"); + if (start == kwsys_stl::string::npos) + { + return false; + } + + size_t valuenamepos = primary.find(";"); + if (valuenamepos != kwsys_stl::string::npos) + { + valuename = primary.substr(valuenamepos+1); + } + + second = primary.substr(start+1, valuenamepos-start-1); + primary = primary.substr(0, start); + + if (primary == "HKEY_CURRENT_USER") + { + primaryKey = HKEY_CURRENT_USER; + } + if (primary == "HKEY_CURRENT_CONFIG") + { + primaryKey = HKEY_CURRENT_CONFIG; + } + if (primary == "HKEY_CLASSES_ROOT") + { + primaryKey = HKEY_CLASSES_ROOT; + } + if (primary == "HKEY_LOCAL_MACHINE") + { + primaryKey = HKEY_LOCAL_MACHINE; + } + if (primary == "HKEY_USERS") + { + primaryKey = HKEY_USERS; + } + + return true; +} + static DWORD SystemToolsMakeRegistryMode(DWORD mode, SystemTools::KeyWOW64 view) { @@ -718,6 +764,55 @@ static DWORD SystemToolsMakeRegistryMode(DWORD mode, } #endif +#if defined(_WIN32) && !defined(__CYGWIN__) +bool +SystemTools::GetRegistrySubKeys(const char *key, + kwsys_stl::vector<kwsys_stl::string>& subkeys, + KeyWOW64 view) +{ + HKEY primaryKey = HKEY_CURRENT_USER; + kwsys_stl::string second; + kwsys_stl::string valuename; + if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) + { + return false; + } + + HKEY hKey; + if(RegOpenKeyEx(primaryKey, + second.c_str(), + 0, + SystemToolsMakeRegistryMode(KEY_READ, view), + &hKey) != ERROR_SUCCESS) + { + return false; + } + else + { + char name[1024]; + DWORD dwNameSize = sizeof(name)/sizeof(name[0]); + + DWORD i = 0; + while (RegEnumKey(hKey, i, name, dwNameSize) == ERROR_SUCCESS) + { + subkeys.push_back(name); + ++i; + } + + RegCloseKey(hKey); + } + + return true; +} +#else +bool SystemTools::GetRegistrySubKeys(const char *, + kwsys_stl::vector<kwsys_stl::string>&, + KeyWOW64) +{ + return false; +} +#endif + // Read a registry value. // Example : // HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath @@ -730,47 +825,14 @@ bool SystemTools::ReadRegistryValue(const char *key, kwsys_stl::string &value, KeyWOW64 view) { bool valueset = false; - kwsys_stl::string primary = key; + HKEY primaryKey = HKEY_CURRENT_USER; kwsys_stl::string second; kwsys_stl::string valuename; - - size_t start = primary.find("\\"); - if (start == kwsys_stl::string::npos) + if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { return false; } - size_t valuenamepos = primary.find(";"); - if (valuenamepos != kwsys_stl::string::npos) - { - valuename = primary.substr(valuenamepos+1); - } - - second = primary.substr(start+1, valuenamepos-start-1); - primary = primary.substr(0, start); - - HKEY primaryKey = HKEY_CURRENT_USER; - if (primary == "HKEY_CURRENT_USER") - { - primaryKey = HKEY_CURRENT_USER; - } - if (primary == "HKEY_CURRENT_CONFIG") - { - primaryKey = HKEY_CURRENT_CONFIG; - } - if (primary == "HKEY_CLASSES_ROOT") - { - primaryKey = HKEY_CLASSES_ROOT; - } - if (primary == "HKEY_LOCAL_MACHINE") - { - primaryKey = HKEY_LOCAL_MACHINE; - } - if (primary == "HKEY_USERS") - { - primaryKey = HKEY_USERS; - } - HKEY hKey; if(RegOpenKeyEx(primaryKey, second.c_str(), @@ -834,47 +896,14 @@ bool SystemTools::ReadRegistryValue(const char *, kwsys_stl::string &, bool SystemTools::WriteRegistryValue(const char *key, const char *value, KeyWOW64 view) { - kwsys_stl::string primary = key; + HKEY primaryKey = HKEY_CURRENT_USER; kwsys_stl::string second; kwsys_stl::string valuename; - - size_t start = primary.find("\\"); - if (start == kwsys_stl::string::npos) + if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { return false; } - size_t valuenamepos = primary.find(";"); - if (valuenamepos != kwsys_stl::string::npos) - { - valuename = primary.substr(valuenamepos+1); - } - - second = primary.substr(start+1, valuenamepos-start-1); - primary = primary.substr(0, start); - - HKEY primaryKey = HKEY_CURRENT_USER; - if (primary == "HKEY_CURRENT_USER") - { - primaryKey = HKEY_CURRENT_USER; - } - if (primary == "HKEY_CURRENT_CONFIG") - { - primaryKey = HKEY_CURRENT_CONFIG; - } - if (primary == "HKEY_CLASSES_ROOT") - { - primaryKey = HKEY_CLASSES_ROOT; - } - if (primary == "HKEY_LOCAL_MACHINE") - { - primaryKey = HKEY_LOCAL_MACHINE; - } - if (primary == "HKEY_USERS") - { - primaryKey = HKEY_USERS; - } - HKEY hKey; DWORD dwDummy; char lpClass[] = ""; @@ -919,47 +948,14 @@ bool SystemTools::WriteRegistryValue(const char *, const char *, KeyWOW64) #if defined(_WIN32) && !defined(__CYGWIN__) bool SystemTools::DeleteRegistryValue(const char *key, KeyWOW64 view) { - kwsys_stl::string primary = key; + HKEY primaryKey = HKEY_CURRENT_USER; kwsys_stl::string second; kwsys_stl::string valuename; - - size_t start = primary.find("\\"); - if (start == kwsys_stl::string::npos) + if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { return false; } - size_t valuenamepos = primary.find(";"); - if (valuenamepos != kwsys_stl::string::npos) - { - valuename = primary.substr(valuenamepos+1); - } - - second = primary.substr(start+1, valuenamepos-start-1); - primary = primary.substr(0, start); - - HKEY primaryKey = HKEY_CURRENT_USER; - if (primary == "HKEY_CURRENT_USER") - { - primaryKey = HKEY_CURRENT_USER; - } - if (primary == "HKEY_CURRENT_CONFIG") - { - primaryKey = HKEY_CURRENT_CONFIG; - } - if (primary == "HKEY_CLASSES_ROOT") - { - primaryKey = HKEY_CLASSES_ROOT; - } - if (primary == "HKEY_LOCAL_MACHINE") - { - primaryKey = HKEY_LOCAL_MACHINE; - } - if (primary == "HKEY_USERS") - { - primaryKey = HKEY_USERS; - } - HKEY hKey; if(RegOpenKeyEx(primaryKey, second.c_str(), @@ -1124,22 +1120,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; + } + 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 utimbuf buf; - buf.actime = fromStat.st_atime; - buf.modtime = static_cast<time_t>(SystemTools::GetTime()); - if(utime(filename, &buf) < 0) + 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,12 +2773,12 @@ bool SystemTools::FileIsDirectory(const char* name) return false; } - // Remove any trailing slash from the name. + // 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] != ':') { if(last < sizeof(local_buffer)) { @@ -3049,7 +3081,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()); } @@ -4011,7 +4043,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()) { @@ -4225,17 +4257,13 @@ bool SystemTools::IsSubDirectory(const char* cSubdir, const char* cDir) } kwsys_stl::string subdir = cSubdir; kwsys_stl::string dir = cDir; + SystemTools::ConvertToUnixSlashes(subdir); SystemTools::ConvertToUnixSlashes(dir); - kwsys_stl::string path = subdir; - do + if(subdir.size() > dir.size() && subdir[dir.size()] == '/') { - path = SystemTools::GetParentDirectory(path.c_str()); - if(SystemTools::ComparePath(dir.c_str(), path.c_str())) - { - return true; - } + std::string s = subdir.substr(0, dir.size()); + return SystemTools::ComparePath(s.c_str(), dir.c_str()); } - while ( path.size() > dir.size() ); return false; } @@ -4837,7 +4865,8 @@ static int SystemToolsDebugReport(int, char* message, int*) void SystemTools::EnableMSVCDebugHook() { - if (getenv("DART_TEST_FROM_DART")) + if (getenv("DART_TEST_FROM_DART") || + getenv("DASHBOARD_TEST_FROM_CTEST")) { _CrtSetReportHook(SystemToolsDebugReport); } diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index 9c56e96b0..d6dae3986 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -716,6 +716,13 @@ public: enum KeyWOW64 { KeyWOW64_Default, KeyWOW64_32, KeyWOW64_64 }; /** + * Get a list of subkeys. + */ + static bool GetRegistrySubKeys(const char *key, + kwsys_stl::vector<kwsys_stl::string>& subkeys, + KeyWOW64 view = KeyWOW64_Default); + + /** * Read a registry value */ static bool ReadRegistryValue(const char *key, kwsys_stl::string &value, @@ -766,7 +773,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/auto_ptr.hxx.in b/Source/kwsys/auto_ptr.hxx.in index 857b1db3c..ad9654cb4 100644 --- a/Source/kwsys/auto_ptr.hxx.in +++ b/Source/kwsys/auto_ptr.hxx.in @@ -31,6 +31,17 @@ # define @KWSYS_NAMESPACE@_AUTO_PTR_CAST(a) a #endif +// In C++11, clang will warn about using dynamic exception specifications +// as they are deprecated. But as this class is trying to faithfully +// mimic std::auto_ptr, we want to keep the 'throw()' decorations below. +// So we suppress the warning. +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated") +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" +# endif +#endif + namespace @KWSYS_NAMESPACE@ { @@ -198,4 +209,11 @@ public: } // namespace @KWSYS_NAMESPACE@ +// Undo warning suppression. +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated") +# pragma clang diagnostic pop +# endif +#endif + #endif diff --git a/Source/kwsys/hashtable.hxx.in b/Source/kwsys/hashtable.hxx.in index c83550304..651de82bf 100644 --- a/Source/kwsys/hashtable.hxx.in +++ b/Source/kwsys/hashtable.hxx.in @@ -62,6 +62,17 @@ # pragma set woff 3970 /* pointer to int conversion */ 3321 3968 #endif +// In C++11, clang will warn about using dynamic exception specifications +// as they are deprecated. But as this class is trying to faithfully +// mimic unordered_set and unordered_map, we want to keep the 'throw()' +// decorations below. So we suppress the warning. +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated") +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" +# endif +#endif + #if @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_TEMPLATE # define @KWSYS_NAMESPACE@_HASH_DEFAULT_ALLOCATOR(T) @KWSYS_NAMESPACE@_stl::allocator< T > #elif @KWSYS_NAMESPACE@_STL_HAS_ALLOCATOR_NONTEMPLATE @@ -1268,6 +1279,13 @@ using @KWSYS_NAMESPACE@::operator==; using @KWSYS_NAMESPACE@::operator!=; #endif +// Undo warning suppression. +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated") +# pragma clang diagnostic pop +# endif +#endif + #if defined(_MSC_VER) # pragma warning (pop) #endif diff --git a/Source/kwsys/kwsysPlatformTests.cmake b/Source/kwsys/kwsysPlatformTests.cmake index d042450ee..f9ee254f0 100644 --- a/Source/kwsys/kwsysPlatformTests.cmake +++ b/Source/kwsys/kwsysPlatformTests.cmake @@ -19,6 +19,7 @@ MACRO(KWSYS_PLATFORM_TEST lang var description invert) ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS} + CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=${KWSYS_PLATFORM_TEST_LINK_LIBRARIES}" OUTPUT_VARIABLE OUTPUT) IF(${var}_COMPILED) FILE(APPEND @@ -150,9 +151,11 @@ ENDMACRO(KWSYS_PLATFORM_C_TEST_RUN) MACRO(KWSYS_PLATFORM_CXX_TEST var description invert) SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES}) SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS}) + SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES ${KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES}) KWSYS_PLATFORM_TEST(CXX "${var}" "${description}" "${invert}") SET(KWSYS_PLATFORM_TEST_DEFINES) SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) + SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES) ENDMACRO(KWSYS_PLATFORM_CXX_TEST) MACRO(KWSYS_PLATFORM_CXX_TEST_RUN var description invert) diff --git a/Source/kwsys/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx index 48976c442..be7a09ee2 100644 --- a/Source/kwsys/kwsysPlatformTestsCXX.cxx +++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx @@ -494,6 +494,73 @@ 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_HAS_BACKTRACE +#if defined(__PATHSCALE__) || defined(__PATHCC__) \ + || (defined(__LSB_VERSION__) && (__LSB_VERSION__ < 41)) +backtrace doesnt work with this compiler or os +#endif +#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +#endif +#include <execinfo.h> +int main() +{ + void *stackSymbols[256]; + backtrace(stackSymbols,256); + backtrace_symbols(&stackSymbols[0],1); + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_DLADDR +#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +#endif +#include <dlfcn.h> +int main() +{ + Dl_info info; + int ierr=dladdr((void*)main,&info); + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_CXXABI +#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +#endif +#include <cxxabi.h> +int main() +{ + int status = 0; + size_t bufferLen = 512; + char buffer[512] = {'\0'}; + const char *function="_ZN5kwsys17SystemInformation15GetProgramStackEii"; + char *demangledFunction = + abi::__cxa_demangle(function, buffer, &bufferLen, &status); + return status; +} +#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 61c157291..dd6d60390 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 3b971e268..f0c7f1a7b 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 49a686c17..53d51ac40 100644 --- a/Source/kwsys/testSystemInformation.cxx +++ b/Source/kwsys/testSystemInformation.cxx @@ -88,14 +88,31 @@ 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"; } } - //int GetProcessorCacheXSize(long int); -// bool DoesCPUSupportFeature(long int); + + /* test stack trace + */ + kwsys_ios::cout + << "Program Stack:" << kwsys_ios::endl + << kwsys::SystemInformation::GetProgramStack(0,0) << kwsys_ios::endl + << kwsys_ios::endl; + + /* test segv handler + info.SetStackTraceOnError(1); + double *d = (double*)100; + *d=0; + */ + + /* test abort handler + info.SetStackTraceOnError(1); + abort(); + */ + return 0; } |