diff options
Diffstat (limited to 'Source')
46 files changed, 862 insertions, 402 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index f9d1c03..c01c490 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -355,18 +355,18 @@ IF (WIN32) ENDIF(NOT UNIX) ENDIF (WIN32) -# turn on Ninja by default +# Turn on Ninja by default, but disable it +# on platforms where it does not pass all tests. +# Enforce Ninja support by setting CMAKE_USE_NINJA set(_CMAKE_DEFAULT_NINJA_VALUE TRUE) -# turn it off for platforms where it does not pass all the -# tests if(WIN32 OR APPLE) SET(_CMAKE_DEFAULT_NINJA_VALUE FALSE) endif() SET(CMAKE_ENABLE_NINJA ${_CMAKE_DEFAULT_NINJA_VALUE} CACHE BOOL - "Enable the ninja generator for CMake. currently not fully working for Windows or OSX") + "Enable the ninja generator for CMake. On Windows and OSX broken") MARK_AS_ADVANCED(CMAKE_ENABLE_NINJA) IF(CMAKE_ENABLE_NINJA) - MESSAGE(STATUS "Enable ninja generator.") + MESSAGE(STATUS "Ninja generator enabled.") SET(SRCS ${SRCS} cmGlobalNinjaGenerator.cxx cmGlobalNinjaGenerator.h @@ -382,7 +382,7 @@ IF(CMAKE_ENABLE_NINJA) ) ADD_DEFINITIONS(-DCMAKE_USE_NINJA) ELSE() - MESSAGE(STATUS "Disable ninja generator.") + MESSAGE(STATUS "Ninja generator disabled, enforce with -DCMAKE_ENABLE_NINJA=ON") ENDIF() # create a library used by the command line and the GUI diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 13268bb..0908537 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -2,5 +2,5 @@ SET(CMake_VERSION_MAJOR 2) SET(CMake_VERSION_MINOR 8) SET(CMake_VERSION_PATCH 8) -SET(CMake_VERSION_TWEAK 20120422) +SET(CMake_VERSION_TWEAK 20120501) #SET(CMake_VERSION_RC 1) diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index 178a18d..fa456de 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -480,11 +480,16 @@ int cmCPackDebGenerator::createDeb() // Do not end the md5sum file with yet another (invalid) } - cmd = "\""; - cmd += cmakeExecutable; - cmd += "\" -E tar cfz control.tar.gz ./control ./md5sums"; - const char* controlExtra = - this->GetOption("CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA"); + cmd = ""; + if (NULL != this->GetOption("CPACK_DEBIAN_FAKEROOT_EXECUTABLE")) + { + cmd = this->GetOption("CPACK_DEBIAN_FAKEROOT_EXECUTABLE"); + } + cmd += " \""; + cmd += cmakeExecutable; + cmd += "\" -E tar cfz control.tar.gz ./control ./md5sums"; + const char* controlExtra = + this->GetOption("CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA"); if( controlExtra ) { std::vector<std::string> controlExtraList; diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 309abb1..ae06b0f 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -752,6 +752,33 @@ int cmCTestCoverageHandler::HandlePHPCoverage( return static_cast<int>(cont->TotalCoverage.size()); } +struct cmCTestCoverageHandlerLocale +{ + cmCTestCoverageHandlerLocale() + { + if(const char* l = cmSystemTools::GetEnv("LC_ALL")) + { + lc_all = l; + } + if(lc_all != "C") + { + cmSystemTools::PutEnv("LC_ALL=C"); + } + } + ~cmCTestCoverageHandlerLocale() + { + if(!lc_all.empty()) + { + cmSystemTools::PutEnv(("LC_ALL=" + lc_all).c_str()); + } + else + { + cmSystemTools::UnsetEnv("LC_ALL"); + } + } + std::string lc_all; +}; + //---------------------------------------------------------------------- int cmCTestCoverageHandler::HandleGCovCoverage( cmCTestCoverageHandlerContainer* cont) @@ -815,7 +842,8 @@ int cmCTestCoverageHandler::HandleGCovCoverage( int file_count = 0; // make sure output from gcov is in English! - cmSystemTools::PutEnv("LC_ALL=POSIX"); + cmCTestCoverageHandlerLocale locale_C; + static_cast<void>(locale_C); // files is a list of *.da and *.gcda files with coverage data in them. // These are binary files that you give as input to gcov so that it will diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 035aaa9..3e4ecdd 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -358,7 +358,7 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os) os << "\t\t</Results>\n" - << logTag << memcheckstr << std::endl + << logTag << cmXMLSafe(memcheckstr) << std::endl << "\t</Log>\n"; this->WriteTestResultFooter(os, result); if ( current < cc ) diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 81f18b0..c3de5dc 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -671,7 +671,7 @@ bool cmCTestRunTest::ForkProcess(double testTimeOut, bool explicitTimeout, if (environment && environment->size()>0) { - cmSystemTools::AppendEnv(environment); + cmSystemTools::AppendEnv(*environment); } return this->TestProcess->StartProcess(); diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 5841b8d..d3ab2ef 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -643,11 +643,7 @@ int cmCTestScriptHandler::RunCurrentScript() { std::vector<std::string> envArgs; cmSystemTools::ExpandListArgument(this->CTestEnv.c_str(),envArgs); - // for each variable/argument do a putenv - for (unsigned i = 0; i < envArgs.size(); ++i) - { - cmSystemTools::PutEnv(envArgs[i].c_str()); - } + cmSystemTools::AppendEnv(envArgs); } // now that we have done most of the error checking finally run the diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 3f7fdc7..4aff64b 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -48,7 +48,7 @@ #include <float.h> #include <ctype.h> -#include <memory> // auto_ptr +#include <cmsys/auto_ptr.hxx> #include <cm_zlib.h> #include <cmsys/Base64.h> @@ -509,7 +509,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command) cmake cm; cmGlobalGenerator gg; gg.SetCMakeInstance(&cm); - std::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator()); + cmsys::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator()); cmMakefile *mf = lg->GetMakefile(); if ( !this->ReadCustomConfigurationFileTree(this->BinaryDir.c_str(), mf) ) { @@ -1277,7 +1277,6 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::ostream* log, double testTimeOut, std::vector<std::string>* environment) { - std::vector<std::string> origEnv; bool modifyEnv = (environment && environment->size()>0); // determine how much time we have @@ -1334,9 +1333,11 @@ int cmCTest::RunTest(std::vector<const char*> argv, } std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory(); + cmsys::auto_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv; if (modifyEnv) { - origEnv = cmSystemTools::AppendEnv(environment); + saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment); + cmSystemTools::AppendEnv(*environment); } *retVal = inst.Run(args, output); @@ -1351,11 +1352,6 @@ int cmCTest::RunTest(std::vector<const char*> argv, "Internal cmCTest object used to run test." << std::endl << *output << std::endl); - if (modifyEnv) - { - cmSystemTools::RestoreEnv(origEnv); - } - return cmsysProcess_State_Exited; } std::vector<char> tempOutput; @@ -1364,9 +1360,11 @@ int cmCTest::RunTest(std::vector<const char*> argv, *output = ""; } + cmsys::auto_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv; if (modifyEnv) { - origEnv = cmSystemTools::AppendEnv(environment); + saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment); + cmSystemTools::AppendEnv(*environment); } cmsysProcess* cp = cmsysProcess_New(); @@ -1436,11 +1434,6 @@ int cmCTest::RunTest(std::vector<const char*> argv, } cmsysProcess_Delete(cp); - if (modifyEnv) - { - cmSystemTools::RestoreEnv(origEnv); - } - return result; } diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 48f644b..ed485e3 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -404,6 +404,7 @@ void cmCoreTryCompile::CleanupFiles(const char* binDir) if(cmSystemTools::FileIsDirectory(fullPath.c_str())) { this->CleanupFiles(fullPath.c_str()); + cmSystemTools::RemoveADirectory(fullPath.c_str()); } else { diff --git a/Source/cmDocumentationFormatterHTML.cxx b/Source/cmDocumentationFormatterHTML.cxx index 6ced1e4..ed28b45 100644 --- a/Source/cmDocumentationFormatterHTML.cxx +++ b/Source/cmDocumentationFormatterHTML.cxx @@ -127,7 +127,7 @@ void cmDocumentationFormatterHTML { os << "<h2><a name=\"section_"; cmDocumentationPrintHTMLId(os, name); - os << "\"/>" << name << "</h2>\n"; + os << "\"></a>" << name << "</h2>\n"; } // Is a list needed? @@ -167,9 +167,9 @@ void cmDocumentationFormatterHTML { os << " <a name=\"" << prefix << ":"; cmDocumentationPrintHTMLId(os, op->Name.c_str()); - os << "\"><b><code>"; + os << "\"></a><b><code>"; this->PrintHTMLEscapes(os, op->Name.c_str()); - os << "</code></b></a>: "; + os << "</code></b>: "; } this->PrintHTMLEscapes(os, op->Brief.c_str()); if(op->Full.size()) @@ -269,9 +269,9 @@ void cmDocumentationFormatterHTML return; } - os << "<h2><a name=\"section_Index\">Master Index " + os << "<h2><a name=\"section_Index\"></a>Master Index " << "CMake " << cmVersion::GetCMakeVersion() - << "</a></h2>\n"; + << "</h2>\n"; if (!sections.empty()) { diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index ccb17f0..5df8627 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -60,6 +60,9 @@ cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator() // disable until somebody actually tests it: // this->SupportedGlobalGenerators.push_back("MSYS Makefiles"); #endif +#ifdef CMAKE_USE_NINJA + this->SupportedGlobalGenerators.push_back("Ninja"); +#endif this->SupportedGlobalGenerators.push_back("Unix Makefiles"); } @@ -383,6 +386,7 @@ void cmExtraCodeBlocksGenerator case cmTarget::STATIC_LIBRARY: case cmTarget::SHARED_LIBRARY: case cmTarget::MODULE_LIBRARY: + case cmTarget::OBJECT_LIBRARY: { this->AppendTarget(fout, ti->first.c_str(), &ti->second, make.c_str(), makefile, compiler.c_str()); @@ -420,6 +424,7 @@ void cmExtraCodeBlocksGenerator case cmTarget::STATIC_LIBRARY: case cmTarget::SHARED_LIBRARY: case cmTarget::MODULE_LIBRARY: + case cmTarget::OBJECT_LIBRARY: case cmTarget::UTILITY: // can have sources since 2.6.3 { const std::vector<cmSourceFile*>&sources=ti->second.GetSourceFiles(); @@ -532,6 +537,31 @@ void cmExtraCodeBlocksGenerator } +// Write a dummy file for OBJECT libraries, so C::B can reference some file +std::string cmExtraCodeBlocksGenerator::CreateDummyTargetFile( + cmMakefile* mf, cmTarget* target) const +{ + // this file doesn't seem to be used by C::B in custom makefile mode, + // but we generate a unique file for each OBJECT library so in case + // C::B uses it in some way, the targets don't interfere with each other. + std::string filename = mf->GetCurrentOutputDirectory(); + filename += "/"; + filename += mf->GetLocalGenerator()->GetTargetDirectory(*target); + filename += "/"; + filename += target->GetName(); + filename += ".objlib"; + cmGeneratedFileStream fout(filename.c_str()); + if(fout) + { + fout << "# This is a dummy file for the OBJECT library " + << target->GetName() + << " for the CMake CodeBlocks project generator.\n" + << "# Don't edit, this file will be overwritten.\n"; + } + return filename; +} + + // Generate the xml code for one target. void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout, const char* targetName, @@ -570,7 +600,18 @@ void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout, } const char* buildType = makefile->GetDefinition("CMAKE_BUILD_TYPE"); - fout<<" <Option output=\"" << target->GetLocation(buildType) + std::string location; + if ( target->GetType()==cmTarget::OBJECT_LIBRARY) + { + location = this->CreateDummyTargetFile(const_cast<cmMakefile*>(makefile), + target); + } + else + { + location = target->GetLocation(buildType); + } + + fout<<" <Option output=\"" << location << "\" prefix_auto=\"0\" extension_auto=\"0\" />\n" " <Option working_dir=\"" << workingDir << "\" />\n" " <Option object_output=\"./\" />\n" @@ -728,7 +769,8 @@ int cmExtraCodeBlocksGenerator::GetCBTargetType(cmTarget* target) return 1; } } - else if ( target->GetType()==cmTarget::STATIC_LIBRARY) + else if (( target->GetType()==cmTarget::STATIC_LIBRARY) + || (target->GetType()==cmTarget::OBJECT_LIBRARY)) { return 2; } diff --git a/Source/cmExtraCodeBlocksGenerator.h b/Source/cmExtraCodeBlocksGenerator.h index 57751fc..e0a64ca 100644 --- a/Source/cmExtraCodeBlocksGenerator.h +++ b/Source/cmExtraCodeBlocksGenerator.h @@ -44,6 +44,8 @@ private: void CreateNewProjectFile(const std::vector<cmLocalGenerator*>& lgs, const std::string& filename); + std::string CreateDummyTargetFile(cmMakefile* mf, cmTarget* target) const; + std::string GetCBCompilerId(const cmMakefile* mf); int GetCBTargetType(cmTarget* target); std::string BuildMakeCommand(const std::string& make, const char* makefile, diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 3f14fa1..d69431e 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -300,7 +300,7 @@ bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args) offset = atoi(offsetArg.GetCString()); } - file.seekg(offset); + file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6 std::string output; diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index ef16ce8..4f9ba7e 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -89,7 +89,7 @@ void cmFindPackageCommand::GenerateDocumentation() "FIND_XXX", "find_package"); this->CommandDocumentation = " find_package(<package> [version] [EXACT] [QUIET] [MODULE]\n" - " [[REQUIRED|COMPONENTS] [components...]]\n" + " [REQUIRED] [[COMPONENTS] [components...]]\n" " [OPTIONAL_COMPONENTS components...]\n" " [NO_POLICY_SCOPE])\n" "Finds and loads settings from an external project. " @@ -102,7 +102,7 @@ void cmFindPackageCommand::GenerateDocumentation() "package cannot be found." "\n" "A package-specific list of required components may be listed after the " - "COMPONENTS option or directly after the REQUIRED option. " + "COMPONENTS option (or after the REQUIRED option if present). " "Additional optional components may be listed after OPTIONAL_COMPONENTS. " "Available components and their influence on whether a package is " "considered to be found are defined by the target package." @@ -136,7 +136,7 @@ void cmFindPackageCommand::GenerateDocumentation() "proceeds to Config mode.\n" "The complete Config mode command signature is:\n" " find_package(<package> [version] [EXACT] [QUIET]\n" - " [[REQUIRED|COMPONENTS] [components...]]\n" + " [REQUIRED] [[COMPONENTS] [components...]]\n" " [CONFIG|NO_MODULE]\n" " [NO_POLICY_SCOPE]\n" " [NAMES name1 [name2 ...]]\n" @@ -353,6 +353,29 @@ void cmFindPackageCommand::GenerateDocumentation() "variable CMAKE_DISABLE_FIND_PACKAGE_<package> to TRUE. See the " "documentation for the CMAKE_DISABLE_FIND_PACKAGE_<package> variable for " "more information.\n" + "When loading a find module or package configuration file find_package " + "defines variables to provide information about the call arguments " + "(and restores their original state before returning):\n" + " <package>_FIND_REQUIRED = true if REQUIRED option was given\n" + " <package>_FIND_QUIETLY = true if QUIET option was given\n" + " <package>_FIND_VERSION = full requested version string\n" + " <package>_FIND_VERSION_MAJOR = major version if requested, else 0\n" + " <package>_FIND_VERSION_MINOR = minor version if requested, else 0\n" + " <package>_FIND_VERSION_PATCH = patch version if requested, else 0\n" + " <package>_FIND_VERSION_TWEAK = tweak version if requested, else 0\n" + " <package>_FIND_VERSION_COUNT = number of version components, 0 to 4\n" + " <package>_FIND_VERSION_EXACT = true if EXACT option was given\n" + " <package>_FIND_COMPONENTS = list of requested components\n" + " <package>_FIND_REQUIRED_<c> = true if component <c> is required\n" + " false if component <c> is optional\n" + "In Module mode the loaded find module is responsible to honor the " + "request detailed by these variables; see the find module for details. " + "In Config mode find_package handles REQUIRED, QUIET, and version " + "options automatically but leaves it to the package configuration file " + "to handle components in a way that makes sense for the package. " + "The package configuration file may set <package>_FOUND to false " + "to tell find_package that component requirements are not satisfied." + "\n" "See the cmake_policy() command documentation for discussion of the " "NO_POLICY_SCOPE option." ; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 545f9e8..b06cdb4 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2092,6 +2092,21 @@ cmTarget cmGlobalGenerator::CreateGlobalTarget( } //---------------------------------------------------------------------------- +std::string +cmGlobalGenerator::GenerateRuleFile(std::string const& output) const +{ + std::string ruleFile = output; + ruleFile += ".rule"; + const char* dir = this->GetCMakeCFGIntDir(); + if(dir && dir[0] == '$') + { + cmSystemTools::ReplaceString(ruleFile, dir, + cmake::GetCMakeFilesDirectory()); + } + return ruleFile; +} + +//---------------------------------------------------------------------------- void cmGlobalGenerator::AppendDirectoryForConfig(const char*, const char*, const char*, std::string&) { diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 80b948b..5254b89 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -277,6 +277,9 @@ public: i.e. "Can I build Debug and Release in the same tree?" */ virtual bool IsMultiConfig() { return false; } + /** Generate an <output>.rule file path for a given command output. */ + virtual std::string GenerateRuleFile(std::string const& output) const; + protected: typedef std::vector<cmLocalGenerator*> GeneratorVector; // for a project collect all its targets by following depend diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 22ead10..18a786d 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -13,6 +13,7 @@ #include "cmGlobalVisualStudio10Generator.h" #include "cmLocalVisualStudio10Generator.h" #include "cmMakefile.h" +#include "cmSourceFile.h" #include "cmake.h" @@ -51,6 +52,38 @@ cmLocalGenerator *cmGlobalVisualStudio10Generator::CreateLocalGenerator() } //---------------------------------------------------------------------------- +void cmGlobalVisualStudio10Generator::Generate() +{ + this->LongestSource = LongestSourcePath(); + this->cmGlobalVisualStudio8Generator::Generate(); + if(this->LongestSource.Length > 0) + { + cmMakefile* mf = this->LongestSource.Target->GetMakefile(); + cmOStringStream e; + e << + "The binary and/or source directory paths may be too long to generate " + "Visual Studio 10 files for this project. " + "Consider choosing shorter directory names to build this project with " + "Visual Studio 10. " + "A more detailed explanation follows." + "\n" + "There is a bug in the VS 10 IDE that renders property dialog fields " + "blank for files referenced by full path in the project file. " + "However, CMake must reference at least one file by full path:\n" + " " << this->LongestSource.SourceFile->GetFullPath() << "\n" + "This is because some Visual Studio tools would append the relative " + "path to the end of the referencing directory path, as in:\n" + " " << mf->GetCurrentOutputDirectory() << "/" + << this->LongestSource.SourceRel << "\n" + "and then incorrectly complain that the file does not exist because " + "the path length is too long for some internal buffer or API. " + "To avoid this problem CMake must use a full path for this file " + "which then triggers the VS 10 property dialog bug."; + mf->IssueMessage(cmake::WARNING, e.str().c_str()); + } +} + +//---------------------------------------------------------------------------- void cmGlobalVisualStudio10Generator ::GetDocumentation(cmDocumentationEntry& entry) const { @@ -212,3 +245,36 @@ bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf) return false; } } + +//---------------------------------------------------------------------------- +std::string +cmGlobalVisualStudio10Generator +::GenerateRuleFile(std::string const& output) const +{ + // The VS 10 generator needs to create the .rule files on disk. + // Hide them away under the CMakeFiles directory. + std::string ruleDir = this->GetCMakeInstance()->GetHomeOutputDirectory(); + ruleDir += cmake::GetCMakeFilesDirectory(); + ruleDir += "/"; + ruleDir += cmSystemTools::ComputeStringMD5( + cmSystemTools::GetFilenamePath(output).c_str()); + std::string ruleFile = ruleDir + "/"; + ruleFile += cmSystemTools::GetFilenameName(output); + ruleFile += ".rule"; + return ruleFile; +} + +//---------------------------------------------------------------------------- +void cmGlobalVisualStudio10Generator::PathTooLong( + cmTarget* target, cmSourceFile* sf, std::string const& sfRel) +{ + size_t len = (strlen(target->GetMakefile()->GetCurrentOutputDirectory()) + + 1 + sfRel.length()); + if(len > this->LongestSource.Length) + { + this->LongestSource.Length = len; + this->LongestSource.Target = target; + this->LongestSource.SourceFile = sf; + this->LongestSource.SourceRel = sfRel; + } +} diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 750b89c..4236563 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -46,6 +46,8 @@ public: ///! create the correct local generator virtual cmLocalGenerator *CreateLocalGenerator(); + virtual void Generate(); + /** * Try to determine system infomation such as shared library * extension, pthreads, byte order etc. @@ -75,10 +77,26 @@ public: virtual const char* GetCMakeCFGIntDir() const { return "$(Configuration)";} bool Find64BitTools(cmMakefile* mf); + + /** Generate an <output>.rule file path for a given command output. */ + virtual std::string GenerateRuleFile(std::string const& output) const; + + void PathTooLong(cmTarget* target, cmSourceFile* sf, + std::string const& sfRel); protected: virtual const char* GetIDEVersion() { return "10.0"; } std::string PlatformToolset; bool ExpressEdition; +private: + struct LongestSourcePath + { + LongestSourcePath(): Length(0), Target(0), SourceFile(0) {} + size_t Length; + cmTarget* Target; + cmSourceFile* SourceFile; + std::string SourceRel; + }; + LongestSourcePath LongestSource; }; #endif diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index a5feaca..d6b653c 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -241,9 +241,12 @@ void cmGlobalVisualStudio71Generator ::WriteExternalProject(std::ostream& fout, const char* name, const char* location, + const char* typeGuid, const std::set<cmStdString>& depends) { - fout << "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"" + fout << "Project(\"{" + << (typeGuid ? typeGuid : "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942") + << "}\") = \"" << name << "\", \"" << this->ConvertToSolutionPath(location) << "\", \"{" << this->GetGUID(name) @@ -279,18 +282,21 @@ void cmGlobalVisualStudio71Generator // executables to the libraries it uses are also done here void cmGlobalVisualStudio71Generator ::WriteProjectConfigurations(std::ostream& fout, const char* name, - bool partOfDefaultBuild) + bool partOfDefaultBuild, + const char* platformMapping) { 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 << "|Win32\n"; + << ".ActiveCfg = " << *i << "|" + << (platformMapping ? platformMapping : "Win32") << std::endl; if(partOfDefaultBuild) { fout << "\t\t{" << guid << "}." << *i - << ".Build.0 = " << *i << "|Win32\n"; + << ".Build.0 = " << *i << "|" + << (platformMapping ? platformMapping : "Win32") << std::endl; } } } diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h index 81c2087..503b708 100644 --- a/Source/cmGlobalVisualStudio71Generator.h +++ b/Source/cmGlobalVisualStudio71Generator.h @@ -64,10 +64,12 @@ protected: const char* name, const char* path, cmTarget &t); virtual void WriteProjectConfigurations(std::ostream& fout, const char* name, - bool partOfDefaultBuild); + bool partOfDefaultBuild, + const char* platformMapping = NULL); virtual void WriteExternalProject(std::ostream& fout, const char* name, const char* path, + const char* typeGuid, const std::set<cmStdString>& depends); virtual void WriteSLNFooter(std::ostream& fout); virtual void WriteSLNHeader(std::ostream& fout); diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index a68e6d8..6332d0b 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -250,8 +250,9 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations( const char* expath = target->GetProperty("EXTERNAL_MSPROJECT"); if(expath) { - this->WriteProjectConfigurations(fout, target->GetName(), - true); + this->WriteProjectConfigurations( + fout, target->GetName(), + true, target->GetProperty("VS_PLATFORM_MAPPING")); } else { @@ -286,8 +287,12 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( { std::string project = target->GetName(); std::string location = expath; - this->WriteExternalProject(fout, project.c_str(), - location.c_str(), target->GetUtilities()); + + this->WriteExternalProject(fout, + project.c_str(), + location.c_str(), + target->GetProperty("VS_PROJECT_TYPE"), + target->GetUtilities()); written = true; } else @@ -580,18 +585,21 @@ cmGlobalVisualStudio7Generator // executables to the libraries it uses are also done here void cmGlobalVisualStudio7Generator ::WriteProjectConfigurations(std::ostream& fout, const char* name, - bool partOfDefaultBuild) + bool partOfDefaultBuild, + const char* platformMapping) { 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 << "|Win32\n"; + << ".ActiveCfg = " << *i << "|" + << (platformMapping ? platformMapping : "Win32") << "\n"; if(partOfDefaultBuild) { fout << "\t\t{" << guid << "}." << *i - << ".Build.0 = " << *i << "|Win32\n"; + << ".Build.0 = " << *i << "|" + << (platformMapping ? platformMapping : "Win32") << "\n"; } } } @@ -604,10 +612,14 @@ void cmGlobalVisualStudio7Generator void cmGlobalVisualStudio7Generator::WriteExternalProject(std::ostream& fout, const char* name, const char* location, + const char* typeGuid, const std::set<cmStdString>&) { std::string d = cmSystemTools::ConvertToOutputPath(location); - fout << "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"" + fout << "Project(" + << "\"{" + << (typeGuid ? typeGuid : "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942") + << "}\") = \"" << name << "\", \"" << this->ConvertToSolutionPath(location) << "\", \"{" << this->GetGUID(name) diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index c92998e..9b9107d 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -107,7 +107,8 @@ protected: const char* name, const char* path, cmTarget &t); virtual void WriteProjectConfigurations(std::ostream& fout, const char* name, - bool partOfDefaultBuild); + bool partOfDefaultBuild, + const char* platformMapping = NULL); virtual void WriteSLNFooter(std::ostream& fout); virtual void WriteSLNHeader(std::ostream& fout); virtual std::string WriteUtilityDepend(cmTarget* target); @@ -130,6 +131,7 @@ protected: virtual void WriteExternalProject(std::ostream& fout, const char* name, const char* path, + const char* typeGuid, const std::set<cmStdString>& dependencies); diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index a723109..e7c4232 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -214,13 +214,11 @@ void cmGlobalVisualStudio8Generator::AddCheckTarget() // (this could be avoided with per-target source files) const char* no_main_dependency = 0; const char* no_working_directory = 0; - mf->AddCustomCommandToOutput( - stamps, listFiles, - no_main_dependency, commandLines, "Checking Build System", - no_working_directory, true); - std::string ruleName = stamps[0]; - ruleName += ".rule"; - if(cmSourceFile* file = mf->GetSource(ruleName.c_str())) + if(cmSourceFile* file = + mf->AddCustomCommandToOutput( + stamps, listFiles, + no_main_dependency, commandLines, "Checking Build System", + no_working_directory, true)) { tgt->AddSourceFile(file); } @@ -270,20 +268,23 @@ cmGlobalVisualStudio8Generator void cmGlobalVisualStudio8Generator ::WriteProjectConfigurations(std::ostream& fout, const char* name, - bool partOfDefaultBuild) + bool partOfDefaultBuild, + const char* platformMapping) { 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 - << "|" << this->GetPlatformName() << ".ActiveCfg = " - << *i << "|" << this->GetPlatformName() << "\n"; + << "|" << this->GetPlatformName() << ".ActiveCfg = " << *i << "|" + << (platformMapping ? platformMapping : this->GetPlatformName()) + << "\n"; if(partOfDefaultBuild) { fout << "\t\t{" << guid << "}." << *i - << "|" << this->GetPlatformName() << ".Build.0 = " - << *i << "|" << this->GetPlatformName() << "\n"; + << "|" << this->GetPlatformName() << ".Build.0 = " << *i << "|" + << (platformMapping ? platformMapping : this->GetPlatformName()) + << "\n"; } } } diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h index e0913ed..7dae429 100644 --- a/Source/cmGlobalVisualStudio8Generator.h +++ b/Source/cmGlobalVisualStudio8Generator.h @@ -77,7 +77,8 @@ protected: virtual void WriteSolutionConfigurations(std::ostream& fout); virtual void WriteProjectConfigurations(std::ostream& fout, const char* name, - bool partOfDefaultBuild); + bool partOfDefaultBuild, + const char* platformMapping = NULL); virtual bool ComputeTargetDepends(); virtual void WriteProjectDepends(std::ostream& fout, const char* name, const char* path, cmTarget &t); diff --git a/Source/cmIncludeExternalMSProjectCommand.cxx b/Source/cmIncludeExternalMSProjectCommand.cxx index a4369a3..d219c16 100644 --- a/Source/cmIncludeExternalMSProjectCommand.cxx +++ b/Source/cmIncludeExternalMSProjectCommand.cxx @@ -25,18 +25,75 @@ bool cmIncludeExternalMSProjectCommand #ifdef _WIN32 if(this->Makefile->GetDefinition("WIN32")) { + enum Doing { DoingNone, DoingType, DoingGuid, DoingPlatform }; + + Doing doing = DoingNone; + + std::string customType; + std::string customGuid; + std::string platformMapping; + + std::vector<std::string> depends; + for (unsigned int i=2; i<args.size(); ++i) + { + if (args[i] == "TYPE") + { + doing = DoingType; + } + else if (args[i] == "GUID") + { + doing = DoingGuid; + } + else if (args[i] == "PLATFORM") + { + doing = DoingPlatform; + } + else + { + switch (doing) + { + case DoingNone: depends.push_back(args[i]); break; + case DoingType: customType = args[i]; break; + case DoingGuid: customGuid = args[i]; break; + case DoingPlatform: platformMapping = args[i]; break; + } + doing = DoingNone; + } + } + + // Hack together a utility target storing enough information + // to reproduce the target inclusion. + std::string utility_name = args[0]; + std::string path = args[1]; cmSystemTools::ConvertToUnixSlashes(path); + if (!customGuid.empty()) + { + std::string guidVariable = utility_name + "_GUID_CMAKE"; + this->Makefile->GetCMakeInstance()->AddCacheEntry( + guidVariable.c_str(), customGuid.c_str(), + "Stored GUID", cmCacheManager::INTERNAL); + } + // Create a target instance for this utility. cmTarget* target=this->Makefile->AddNewTarget(cmTarget::UTILITY, - args[0].c_str()); + utility_name.c_str()); + + target->SetProperty("GENERATOR_FILE_NAME", utility_name.c_str()); target->SetProperty("EXTERNAL_MSPROJECT", path.c_str()); - target->SetProperty("EXCLUDE_FROM_ALL","FALSE"); - target->SetProperty("GENERATOR_FILE_NAME", args[0].c_str()); - for (unsigned int i=2; i<args.size(); ++i) + target->SetProperty("EXCLUDE_FROM_ALL", "FALSE"); + + if (!customType.empty()) + target->SetProperty("VS_PROJECT_TYPE",customType.c_str()); + if (!platformMapping.empty()) + target->SetProperty("VS_PLATFORM_MAPPING",platformMapping.c_str()); + + for (std::vector<std::string>::const_iterator it = depends.begin(); + it != depends.end(); + ++it) { - target->AddUtility(args[i].c_str()); + target->AddUtility(it->c_str()); } } #endif diff --git a/Source/cmIncludeExternalMSProjectCommand.h b/Source/cmIncludeExternalMSProjectCommand.h index 911a772..2b2ed0d 100644 --- a/Source/cmIncludeExternalMSProjectCommand.h +++ b/Source/cmIncludeExternalMSProjectCommand.h @@ -59,11 +59,21 @@ public: { return " include_external_msproject(projectname location\n" + " [TYPE projectTypeGUID]\n" + " [GUID projectGUID]\n" + " [PLATFORM platformName]\n" " dep1 dep2 ...)\n" "Includes an external Microsoft project in the generated workspace " "file. Currently does nothing on UNIX. This will create a " "target named [projectname]. This can be used in the add_dependencies " - "command to make things depend on the external project."; + "command to make things depend on the external project." + "\n" + "TYPE, GUID and PLATFORM are optional parameters that allow one " + "to specify the type of project, id (GUID) of the project and " + "the name of the target platform. " + "This is useful for projects requiring values other than the default " + "(e.g. WIX projects). " + "These options are not supported by the Visual Studio 6 generator."; } cmTypeMacro(cmIncludeExternalMSProjectCommand, cmCommand); diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx index cbbcbb0..908f3b0 100644 --- a/Source/cmListCommand.cxx +++ b/Source/cmListCommand.cxx @@ -204,6 +204,12 @@ bool cmListCommand::HandleGetCommand(std::vector<std::string> const& args) this->Makefile->AddDefinition(variableName.c_str(), "NOTFOUND"); return true; } + // FIXME: Add policy to make non-existing lists an error like empty lists. + if(varArgsExpanded.empty()) + { + this->SetError("GET given empty list"); + return false; + } std::string value; size_t cc; @@ -318,7 +324,8 @@ bool cmListCommand::HandleInsertCommand(std::vector<std::string> const& args) // expand the variable int item = atoi(args[2].c_str()); std::vector<std::string> varArgsExpanded; - if ( !this->GetList(varArgsExpanded, listName.c_str()) && item != 0) + if((!this->GetList(varArgsExpanded, listName.c_str()) + || varArgsExpanded.empty()) && item != 0) { cmOStringStream str; str << "index: " << item << " out of range (0, 0)"; @@ -544,6 +551,12 @@ bool cmListCommand::HandleRemoveAtCommand( this->SetError("sub-command REMOVE_AT requires list to be present."); return false; } + // FIXME: Add policy to make non-existing lists an error like empty lists. + if(varArgsExpanded.empty()) + { + this->SetError("REMOVE_AT given empty list"); + return false; + } size_t cc; std::vector<size_t> removed; diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx index bf0e997..ace7adf 100644 --- a/Source/cmLocalVisualStudio10Generator.cxx +++ b/Source/cmLocalVisualStudio10Generator.cxx @@ -99,6 +99,14 @@ void cmLocalVisualStudio10Generator { cmVS10XMLParser parser; parser.ParseFile(path); + + // if we can not find a GUID then create one + if(parser.GUID.empty()) + { + this->GlobalGenerator->CreateGUID(name); + return; + } + std::string guidStoreName = name; guidStoreName += "_GUID_CMAKE"; // save the GUID in the cache diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index 99a4c95..5ab223b 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -320,7 +320,7 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout, sourceGroup.AssignSource(*i); // while we are at it, if it is a .rule file then for visual studio 6 we // must generate it - if ((*i)->GetExtension() == "rule") + if ((*i)->GetPropertyAsBool("__CMAKE_RULE")) { if(!cmSystemTools::FileExists(source.c_str())) { diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index e3ef1b8..0a709ae 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -883,7 +883,7 @@ cmMakefile::AddCustomCommandToTarget(const char* target, } //---------------------------------------------------------------------------- -void +cmSourceFile* cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs, const std::vector<std::string>& depends, const char* main_dependency, @@ -897,7 +897,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs, if(outputs.empty()) { cmSystemTools::Error("Attempt to add a custom rule with no output!"); - return; + return 0; } // Validate custom commands. TODO: More strict? @@ -910,7 +910,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs, cmOStringStream e; e << "COMMAND may not contain literal quotes:\n " << cl[0] << "\n"; this->IssueMessage(cmake::FATAL_ERROR, e.str()); - return; + return 0; } } @@ -928,7 +928,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs, { // The existing custom command is identical. Silently ignore // the duplicate. - return; + return file; } else { @@ -948,17 +948,11 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs, // Generate a rule file if the main dependency is not available. if(!file) { + cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator(); + // Construct a rule file associated with the first output produced. - std::string outName = outputs[0]; - outName += ".rule"; - const char* dir = - this->LocalGenerator->GetGlobalGenerator()-> - GetCMakeCFGIntDir(); - if(dir && dir[0] == '$') - { - cmSystemTools::ReplaceString(outName, dir, - cmake::GetCMakeFilesDirectory()); - } + std::string outName = gg->GenerateRuleFile(outputs[0]); + // Check if the rule file already exists. file = this->GetSource(outName.c_str()); if(file && file->GetCustomCommand() && !replace) @@ -970,11 +964,12 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs, outName.c_str(), "\" which already has a custom rule."); } - return; + return file; } // Create a cmSourceFile for the rule file. file = this->GetOrCreateSource(outName.c_str(), true); + file->SetProperty("__CMAKE_RULE", "1"); } // Always create the output sources and mark them generated. @@ -1004,10 +999,11 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs, cc->SetEscapeAllowMakeVars(true); file->SetCustomCommand(cc); } + return file; } //---------------------------------------------------------------------------- -void +cmSourceFile* cmMakefile::AddCustomCommandToOutput(const char* output, const std::vector<std::string>& depends, const char* main_dependency, @@ -1019,9 +1015,9 @@ cmMakefile::AddCustomCommandToOutput(const char* output, { std::vector<std::string> outputs; outputs.push_back(output); - this->AddCustomCommandToOutput(outputs, depends, main_dependency, - commandLines, comment, workingDir, - replace, escapeOldStyle); + return this->AddCustomCommandToOutput(outputs, depends, main_dependency, + commandLines, comment, workingDir, + replace, escapeOldStyle); } //---------------------------------------------------------------------------- @@ -1054,13 +1050,14 @@ cmMakefile::AddCustomCommandOldStyle(const char* target, { // Get the name of this output. const char* output = oi->c_str(); + cmSourceFile* sf; // Choose whether to use a main dependency. if(sourceFiles.find(source)) { // The source looks like a real file. Use it as the main dependency. - this->AddCustomCommandToOutput(output, depends, source, - commandLines, comment, 0); + sf = this->AddCustomCommandToOutput(output, depends, source, + commandLines, comment, 0); } else { @@ -1068,20 +1065,18 @@ cmMakefile::AddCustomCommandOldStyle(const char* target, const char* no_main_dependency = 0; std::vector<std::string> depends2 = depends; depends2.push_back(source); - this->AddCustomCommandToOutput(output, depends2, no_main_dependency, - commandLines, comment, 0); + sf = this->AddCustomCommandToOutput(output, depends2, no_main_dependency, + commandLines, comment, 0); } // If the rule was added to the source (and not a .rule file), // then add the source to the target to make sure the rule is // included. - std::string sname = output; - sname += ".rule"; - if(!this->GetSource(sname.c_str())) + if(sf && !sf->GetPropertyAsBool("__CMAKE_RULE")) { if (this->Targets.find(target) != this->Targets.end()) { - this->Targets[target].AddSource(source); + this->Targets[target].AddSourceFile(sf); } else { @@ -1976,7 +1971,6 @@ cmSourceFile *cmMakefile::GetSourceFileWithOutput(const char *cname) // look through all the source files that have custom commands // and see if the custom command has the passed source file as an output - // keep in mind the possible .rule extension that may be tacked on for(std::vector<cmSourceFile*>::const_iterator i = this->SourceFiles.begin(); i != this->SourceFiles.end(); ++i) { diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index ebd5bcf..9fc64d6 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -175,20 +175,22 @@ public: cmTarget::CustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle = true); - void AddCustomCommandToOutput(const std::vector<std::string>& outputs, - const std::vector<std::string>& depends, - const char* main_dependency, - const cmCustomCommandLines& commandLines, - const char* comment, const char* workingDir, - bool replace = false, - bool escapeOldStyle = true); - void AddCustomCommandToOutput(const char* output, - const std::vector<std::string>& depends, - const char* main_dependency, - const cmCustomCommandLines& commandLines, - const char* comment, const char* workingDir, - bool replace = false, - bool escapeOldStyle = true); + cmSourceFile* AddCustomCommandToOutput( + const std::vector<std::string>& outputs, + const std::vector<std::string>& depends, + const char* main_dependency, + const cmCustomCommandLines& commandLines, + const char* comment, const char* workingDir, + bool replace = false, + bool escapeOldStyle = true); + cmSourceFile* AddCustomCommandToOutput( + const char* output, + const std::vector<std::string>& depends, + const char* main_dependency, + const cmCustomCommandLines& commandLines, + const char* comment, const char* workingDir, + bool replace = false, + bool escapeOldStyle = true); void AddCustomCommandOldStyle(const char* target, const std::vector<std::string>& outputs, const std::vector<std::string>& depends, diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index bb8bd3f..63ba58d 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -47,8 +47,7 @@ cmNinjaNormalTargetGenerator(cmTarget* target) { // on Windows the output dir is already needed at compile time // ensure the directory exists (OutDir test) - std::string outpath = target->GetDirectory(this->GetConfigName()); - cmSystemTools::MakeDirectory(outpath.c_str()); + EnsureDirectoryExists(target->GetDirectory(this->GetConfigName())); } } @@ -56,6 +55,21 @@ cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator() { } +void +cmNinjaNormalTargetGenerator +::EnsureDirectoryExists(const std::string& dir) +{ + cmSystemTools::MakeDirectory(dir.c_str()); +} + +void +cmNinjaNormalTargetGenerator +::EnsureParentDirectoryExists(const std::string& path) +{ + EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path.c_str())); +} + + void cmNinjaNormalTargetGenerator::Generate() { if (!this->TargetLinkLanguage) { @@ -384,13 +398,18 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() } } + std::string path; if (!this->TargetNameImport.empty()) { - vars["TARGET_IMPLIB"] = this->GetLocalGenerator()->ConvertToOutputFormat( - targetOutputImplib.c_str(), cmLocalGenerator::SHELL); + path = this->GetLocalGenerator()->ConvertToOutputFormat( + targetOutputImplib.c_str(), cmLocalGenerator::SHELL); + vars["TARGET_IMPLIB"] = path; + EnsureParentDirectoryExists(path); } - vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat( - this->GetTargetPDB().c_str(), cmLocalGenerator::SHELL); + path = this->GetLocalGenerator()->ConvertToOutputFormat( + this->GetTargetPDB().c_str(), cmLocalGenerator::SHELL); + vars["TARGET_PDB"] = path; + EnsureParentDirectoryExists(path); std::vector<cmCustomCommand> *cmdLists[3] = { &this->GetTarget()->GetPreBuildCommands(), @@ -417,7 +436,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for // the link commands. if (!preLinkCmdLines.empty()) { - std::string path = this->GetLocalGenerator()->ConvertToOutputFormat( + path = this->GetLocalGenerator()->ConvertToOutputFormat( this->GetMakefile()->GetHomeOutputDirectory(), cmLocalGenerator::SHELL); preLinkCmdLines.push_back("cd " + path); diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h index 1702caf..7acbe8f 100644 --- a/Source/cmNinjaNormalTargetGenerator.h +++ b/Source/cmNinjaNormalTargetGenerator.h @@ -35,6 +35,9 @@ private: void WriteObjectLibStatement(); std::vector<std::string> ComputeLinkCmd(); + void EnsureDirectoryExists(const std::string& dir); + void EnsureParentDirectoryExists(const std::string& path); + private: // Target name info. std::string TargetNameOut; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 1376a48..89f03f6 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -104,6 +104,9 @@ public: private: HANDLE handle_; }; +#elif defined(__APPLE__) +#include <crt_externs.h> +#define environ (*_NSGetEnviron()) #endif bool cmSystemTools::s_RunCommandHideConsole = false; @@ -1630,33 +1633,28 @@ std::vector<std::string> cmSystemTools::GetEnvironmentVariables() } //---------------------------------------------------------------------- -std::vector<std::string> cmSystemTools::AppendEnv( - std::vector<std::string>* env) +void cmSystemTools::AppendEnv(std::vector<std::string> const& env) { - std::vector<std::string> origEnv = GetEnvironmentVariables(); - - if (env && env->size()>0) + for(std::vector<std::string>::const_iterator eit = env.begin(); + eit != env.end(); ++eit) { - std::vector<std::string>::const_iterator eit; - - for (eit = env->begin(); eit!= env->end(); ++eit) - { - PutEnv(eit->c_str()); - } + cmSystemTools::PutEnv(eit->c_str()); } - - return origEnv; } //---------------------------------------------------------------------- -void cmSystemTools::RestoreEnv(const std::vector<std::string>& env) +cmSystemTools::SaveRestoreEnvironment::SaveRestoreEnvironment() { - std::vector<std::string>::const_iterator eit; + this->Env = cmSystemTools::GetEnvironmentVariables(); +} +//---------------------------------------------------------------------- +cmSystemTools::SaveRestoreEnvironment::~SaveRestoreEnvironment() +{ // First clear everything in the current environment: - // std::vector<std::string> currentEnv = GetEnvironmentVariables(); - for (eit = currentEnv.begin(); eit!= currentEnv.end(); ++eit) + for(std::vector<std::string>::const_iterator + eit = currentEnv.begin(); eit != currentEnv.end(); ++eit) { std::string var(*eit); @@ -1666,27 +1664,11 @@ void cmSystemTools::RestoreEnv(const std::vector<std::string>& env) var = var.substr(0, pos); } - UnsetEnv(var.c_str()); + cmSystemTools::UnsetEnv(var.c_str()); } // Then put back each entry from the original environment: - // - for (eit = env.begin(); eit!= env.end(); ++eit) - { - PutEnv(eit->c_str()); - } -} - -//---------------------------------------------------------------------- -cmSystemTools::SaveRestoreEnvironment::SaveRestoreEnvironment() -{ - this->Env = cmSystemTools::GetEnvironmentVariables(); -} - -//---------------------------------------------------------------------- -cmSystemTools::SaveRestoreEnvironment::~SaveRestoreEnvironment() -{ - cmSystemTools::RestoreEnv(this->Env); + cmSystemTools::AppendEnv(this->Env); } #endif diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 5f21de2..69673c9 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -371,16 +371,8 @@ public: /** Get the list of all environment variables */ static std::vector<std::string> GetEnvironmentVariables(); - /** Append multiple variables to the current environment. - Return the original environment, as it was before the - append. */ - static std::vector<std::string> AppendEnv( - std::vector<std::string>* env); - - /** Restore the full environment to "env" - use after - AppendEnv to put the environment back to the way it - was. */ - static void RestoreEnv(const std::vector<std::string>& env); + /** Append multiple variables to the current environment. */ + static void AppendEnv(std::vector<std::string> const& env); /** Helper class to save and restore the environment. Instantiate this class as an automatic variable on diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h index be866c3..63114d2 100644 --- a/Source/cmTargetLinkLibrariesCommand.h +++ b/Source/cmTargetLinkLibrariesCommand.h @@ -64,7 +64,8 @@ public: "Specify libraries or flags to use when linking a given target. " "The named <target> must have been created in the current directory " "by a command such as add_executable or add_library. " - "The remaining arguments specify library names or flags." + "The remaining arguments specify library names or flags. " + "Repeated calls for the same <target> append items in the order called." "\n" "If a library name matches that of another target in the project " "a dependency will automatically be added in the build system to make " diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 6caaad1..9a97ab0 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -459,8 +459,9 @@ cmVisualStudio10TargetGenerator::WriteCustomRule(cmSourceFile* source, command) { std::string sourcePath = source->GetFullPath(); - // the rule file seems to need to exist for vs10 - if (source->GetExtension() == "rule") + // VS 10 will always rebuild a custom command attached to a .rule + // file that doesn't exist so create the file explicitly. + if (source->GetPropertyAsBool("__CMAKE_RULE")) { if(!cmSystemTools::FileExists(sourcePath.c_str())) { @@ -490,14 +491,9 @@ cmVisualStudio10TargetGenerator::WriteCustomRule(cmSourceFile* source, std::vector<std::string> *configs = static_cast<cmGlobalVisualStudio7Generator *> (this->GlobalGenerator)->GetConfigurations(); - this->WriteString("<CustomBuild Include=\"", 2); - // custom command have to use relative paths or they do not - // show up in the GUI - std::string path = cmSystemTools::RelativePath( - this->Makefile->GetCurrentOutputDirectory(), - sourcePath.c_str()); - this->ConvertToWindowsSlash(path); - (*this->BuildFileStream ) << path << "\">\n"; + + this->WriteSource("CustomBuild", source, ">\n"); + for(std::vector<std::string>::iterator i = configs->begin(); i != configs->end(); ++i) { @@ -540,6 +536,18 @@ cmVisualStudio10TargetGenerator::WriteCustomRule(cmSourceFile* source, this->WriteString("</CustomBuild>\n", 2); } +std::string +cmVisualStudio10TargetGenerator::ConvertPath(std::string const& path, + bool forceRelative) +{ + return forceRelative + ? cmSystemTools::RelativePath( + this->Makefile->GetCurrentOutputDirectory(), path.c_str()) + : this->LocalGenerator->Convert(path.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::UNCHANGED); +} + void cmVisualStudio10TargetGenerator::ConvertToWindowsSlash(std::string& s) { // first convert all of the slashes @@ -558,13 +566,6 @@ void cmVisualStudio10TargetGenerator::WriteGroups() std::vector<cmSourceFile*> classes = this->Target->GetSourceFiles(); std::set<cmSourceGroup*> groupsUsed; - std::vector<cmSourceFile*> clCompile; - std::vector<cmSourceFile*> customBuild; - std::vector<cmSourceFile*> none; - std::vector<cmSourceFile*> headers; - std::vector<cmSourceFile*> idls; - std::vector<cmSourceFile*> resource; - for(std::vector<cmSourceFile*>::const_iterator s = classes.begin(); s != classes.end(); s++) { @@ -573,40 +574,6 @@ void cmVisualStudio10TargetGenerator::WriteGroups() cmSourceGroup& sourceGroup = this->Makefile->FindSourceGroup(source.c_str(), sourceGroups); groupsUsed.insert(&sourceGroup); - const char* lang = sf->GetLanguage(); - bool header = (*s)->GetPropertyAsBool("HEADER_FILE_ONLY") - || this->GlobalGenerator->IgnoreFile - ((*s)->GetExtension().c_str()); - std::string ext = - cmSystemTools::LowerCase((*s)->GetExtension()); - if(!lang) - { - lang = "None"; - } - if(header) - { - headers.push_back(sf); - } - else if(lang[0] == 'C') - { - clCompile.push_back(sf); - } - else if(strcmp(lang, "RC") == 0) - { - resource.push_back(sf); - } - else if(sf->GetCustomCommand()) - { - customBuild.push_back(sf); - } - else if(ext == "idl") - { - idls.push_back(sf); - } - else - { - none.push_back(sf); - } } this->AddMissingSourceGroups(groupsUsed, sourceGroups); @@ -628,11 +595,11 @@ void cmVisualStudio10TargetGenerator::WriteGroups() "xmlns=\"http://schemas.microsoft.com/" "developer/msbuild/2003\">\n", 0); - this->WriteGroupSources("ClCompile", clCompile, sourceGroups); - this->WriteGroupSources("ClInclude", headers, sourceGroups); - this->WriteGroupSources("ResourceCompile", resource, sourceGroups); - this->WriteGroupSources("Midl", idls, sourceGroups); - this->WriteGroupSources("CustomBuild", customBuild, sourceGroups); + for(ToolSourceMap::const_iterator ti = this->Tools.begin(); + ti != this->Tools.end(); ++ti) + { + this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups); + } // Add object library contents as external objects. std::vector<std::string> objs; @@ -689,7 +656,6 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->WriteString("</Filter>\n", 2); } this->WriteString("</ItemGroup>\n", 1); - this->WriteGroupSources("None", none, sourceGroups); this->WriteString("</Project>\n", 0); // restore stream pointer this->BuildFileStream = save; @@ -749,32 +715,20 @@ cmVisualStudio10TargetGenerator::AddMissingSourceGroups( void cmVisualStudio10TargetGenerator:: WriteGroupSources(const char* name, - std::vector<cmSourceFile*> const& sources, + ToolSources const& sources, std::vector<cmSourceGroup>& sourceGroups) { this->WriteString("<ItemGroup>\n", 1); - for(std::vector<cmSourceFile*>::const_iterator s = sources.begin(); + for(ToolSources::const_iterator s = sources.begin(); s != sources.end(); ++s) { - cmSourceFile* sf = *s; - if(sf->GetExtension() == "obj") - { - continue; - } + cmSourceFile* sf = s->SourceFile; std::string const& source = sf->GetFullPath(); cmSourceGroup& sourceGroup = this->Makefile->FindSourceGroup(source.c_str(), sourceGroups); const char* filter = sourceGroup.GetFullName(); this->WriteString("<", 2); - std::string path = source; - // custom command sources must use relative paths or they will - // not show up in the GUI. - if(sf->GetCustomCommand()) - { - path = cmSystemTools::RelativePath( - this->Makefile->GetCurrentOutputDirectory(), - source.c_str()); - } + std::string path = this->ConvertPath(source, s->RelativePath); this->ConvertToWindowsSlash(path); (*this->BuildFileStream) << name << " Include=\"" << path; @@ -795,15 +749,47 @@ WriteGroupSources(const char* name, } void cmVisualStudio10TargetGenerator::WriteSource( - const char* tool, cmSourceFile* sf, bool end) + const char* tool, cmSourceFile* sf, const char* end) { - std::string sourceFile = sf->GetFullPath(); - // do not use a relative path here because it means that you - // can not use as long a path to the file. + // Visual Studio tools append relative paths to the current dir, as in: + // + // c:\path\to\current\dir\..\..\..\relative\path\to\source.c + // + // and fail if this exceeds the maximum allowed path length. Our path + // conversion uses full paths outside the build tree to allow deeper trees. + bool forceRelative = false; + std::string sourceFile = this->ConvertPath(sf->GetFullPath(), false); + if(this->LocalGenerator->GetVersion() == cmLocalVisualStudioGenerator::VS10 + && cmSystemTools::FileIsFullPath(sourceFile.c_str())) + { + // Normal path conversion resulted in a full path. VS 10 (but not 11) + // refuses to show the property page in the IDE for a source file with a + // full path (not starting in a '.' or '/' AFAICT). CMake <= 2.8.4 used a + // relative path but to allow deeper build trees CMake 2.8.[5678] used a + // full path except for custom commands. Custom commands do not work + // without a relative path, but they do not seem to be involved in tools + // with the above behavior. For other sources we now use a relative path + // when the combined path will not be too long so property pages appear. + std::string sourceRel = this->ConvertPath(sf->GetFullPath(), true); + size_t const maxLen = 250; + if(sf->GetCustomCommand() || + ((strlen(this->Makefile->GetCurrentOutputDirectory()) + 1 + + sourceRel.length()) <= maxLen)) + { + forceRelative = true; + sourceFile = sourceRel; + } + else + { + this->GlobalGenerator->PathTooLong(this->Target, sf, sourceRel); + } + } this->ConvertToWindowsSlash(sourceFile); this->WriteString("<", 2); (*this->BuildFileStream ) << tool << - " Include=\"" << sourceFile << (end? "\" />\n" : "\" "); + " Include=\"" << sourceFile << "\"" << (end? end : " />\n"); + ToolSource toolSource = {sf, forceRelative}; + this->Tools[tool].push_back(toolSource); } void cmVisualStudio10TargetGenerator::WriteSources( @@ -835,7 +821,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() 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, false); + this->WriteSource(tool, *si, " "); // ouput any flags specific to this source file if(cl && this->OutputSourceSpecificFlags(*si)) { diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 20a443b..2d5ec2a 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -43,11 +43,19 @@ public: ); private: + struct ToolSource + { + cmSourceFile* SourceFile; + bool RelativePath; + }; + struct ToolSources: public std::vector<ToolSource> {}; + + std::string ConvertPath(std::string const& path, bool forceRelative); void ConvertToWindowsSlash(std::string& s); void WriteString(const char* line, int indentLevel); void WriteProjectConfigurations(); void WriteProjectConfigurationValues(); - void WriteSource(const char* tool, cmSourceFile* sf, bool end = true); + void WriteSource(const char* tool, cmSourceFile* sf, const char* end = 0); void WriteSources(const char* tool, std::vector<cmSourceFile*> const&); void WriteAllSources(); void WriteDotNetReferences(); @@ -77,8 +85,7 @@ private: void WriteEvents(std::string const& configName); void WriteEvent(const char* name, std::vector<cmCustomCommand> & commands, std::string const& configName); - void WriteGroupSources(const char* name, - std::vector<cmSourceFile*> const& sources, + void WriteGroupSources(const char* name, ToolSources const& sources, std::vector<cmSourceGroup>& ); void AddMissingSourceGroups(std::set<cmSourceGroup*>& groupsUsed, const std::vector<cmSourceGroup>& allGroups); @@ -99,6 +106,9 @@ private: cmGeneratedFileStream* BuildFileStream; cmLocalVisualStudio7Generator* LocalGenerator; std::set<cmSourceFile*> SourcesVisited; + + typedef std::map<cmStdString, ToolSources> ToolSourceMap; + ToolSourceMap Tools; }; #endif diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 0ef4e28..520cafb 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -123,7 +123,6 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) SET(KWSYS_USE_FundamentalType 1) SET(KWSYS_USE_Terminal 1) SET(KWSYS_USE_IOStream 1) - SET(KWSYS_USE_DateStamp 1) SET(KWSYS_USE_String 1) SET(KWSYS_USE_SystemInformation 1) SET(KWSYS_USE_CPU 1) @@ -553,11 +552,16 @@ SET_SOURCE_FILES_PROPERTIES(ProcessUNIX.c System.c PROPERTIES COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T}" ) -IF(KWSYS_DO_NOT_CLEAN_PUTENV) - # Disable cleanup of putenv memory for issues with GCOV. +IF(KWSYS_USE_SystemTools) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV + "Checking whether CXX compiler has setenv" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UNSETENV + "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_DO_NOT_CLEAN_PUTENV=1) -ENDIF(KWSYS_DO_NOT_CLEAN_PUTENV) + 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}") +ENDIF() #----------------------------------------------------------------------------- # Choose a directory for the generated headers. @@ -690,7 +694,7 @@ ENDFOREACH(cpp) # Add selected C components. FOREACH(c - Process Base64 FundamentalType MD5 Terminal System DateStamp String CPU + Process Base64 FundamentalType MD5 Terminal System String CPU ) IF(KWSYS_USE_${c}) # Use the corresponding header file. diff --git a/Source/kwsys/DateStamp.h.in b/Source/kwsys/DateStamp.h.in deleted file mode 100644 index c3d0099..0000000 --- a/Source/kwsys/DateStamp.h.in +++ /dev/null @@ -1,42 +0,0 @@ -/*============================================================================ - KWSys - Kitware System Library - 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. -============================================================================*/ -#ifndef @KWSYS_NAMESPACE@_DateStamp_h -#define @KWSYS_NAMESPACE@_DateStamp_h - -/** Version date integer year. The format is CCYY. */ -#define @KWSYS_NAMESPACE@_DATE_STAMP_YEAR @KWSYS_DATE_STAMP_YEAR@ - -/** Version date integer month. The format is MM. */ -#define @KWSYS_NAMESPACE@_DATE_STAMP_MONTH @KWSYS_DATE_STAMP_MONTH@ - -/** Version date integer day. The format is DD. */ -#define @KWSYS_NAMESPACE@_DATE_STAMP_DAY @KWSYS_DATE_STAMP_DAY@ - -/** Version date full integer. The format is CCYYMMDD. */ -#define @KWSYS_NAMESPACE@_DATE_STAMP_FULL @KWSYS_DATE_STAMP_YEAR@@KWSYS_DATE_STAMP_MONTH@@KWSYS_DATE_STAMP_DAY@ - -/** Version date string year. The format is "CCYY". */ -#define @KWSYS_NAMESPACE@_DATE_STAMP_STRING_YEAR "@KWSYS_DATE_STAMP_YEAR@" - -/** Version date string month. The format is "MM". */ -#define @KWSYS_NAMESPACE@_DATE_STAMP_STRING_MONTH "@KWSYS_DATE_STAMP_MONTH@" - -/** Version date string day. The format is "DD". */ -#define @KWSYS_NAMESPACE@_DATE_STAMP_STRING_DAY "@KWSYS_DATE_STAMP_DAY@" - -/** Version date full string. The format is "CCYYMMDD". */ -#define @KWSYS_NAMESPACE@_DATE_STAMP_STRING_FULL "@KWSYS_DATE_STAMP_YEAR@@KWSYS_DATE_STAMP_MONTH@@KWSYS_DATE_STAMP_DAY@" - -/** Version date formatted string. The format is "CCYY-MM-DD". */ -#define @KWSYS_NAMESPACE@_DATE_STAMP_STRING "@KWSYS_DATE_STAMP_YEAR@-@KWSYS_DATE_STAMP_MONTH@-@KWSYS_DATE_STAMP_DAY@" - -#endif diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 4d83293..8ab580f 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -25,6 +25,8 @@ #include KWSYS_HEADER(ios/fstream) #include KWSYS_HEADER(ios/sstream) +#include KWSYS_HEADER(stl/set) + // Work-around CMake dependency scanning limitation. This must // duplicate the above list of headers. #if 0 @@ -78,6 +80,14 @@ # undef _WIN32 #endif +#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H +# if defined(_WIN32) +extern __declspec(dllimport) char **environ; +# else +extern char **environ; +# endif +#endif + #ifdef __CYGWIN__ extern "C" void cygwin_conv_to_win32_path(const char *path, char *win32_path); #endif @@ -371,38 +381,224 @@ bool SystemTools::GetEnv(const char* key, kwsys_stl::string& result) } } -#ifdef __INTEL_COMPILER -#pragma warning disable 444 +//---------------------------------------------------------------------------- + +#if defined(__CYGWIN__) || defined(__GLIBC__) +# define KWSYS_PUTENV_NAME /* putenv("A") removes A. */ +#elif defined(_WIN32) +# define KWSYS_PUTENV_EMPTY /* putenv("A=") removes A. */ #endif -class kwsysDeletingCharVector : public kwsys_stl::vector<char*> +#if KWSYS_CXX_HAS_UNSETENV +/* unsetenv("A") removes A from the environment. + On older platforms it returns void instead of int. */ +static int kwsysUnPutEnv(const char* env) { -public: - ~kwsysDeletingCharVector(); -}; + if(const char* eq = strchr(env, '=')) + { + std::string name(env, eq-env); + unsetenv(name.c_str()); + } + else + { + unsetenv(env); + } + return 0; +} -kwsysDeletingCharVector::~kwsysDeletingCharVector() +#elif defined(KWSYS_PUTENV_EMPTY) || defined(KWSYS_PUTENV_NAME) +/* putenv("A=") or putenv("A") removes A from the environment. */ +static int kwsysUnPutEnv(const char* env) { -#ifndef KWSYS_DO_NOT_CLEAN_PUTENV - for(kwsys_stl::vector<char*>::iterator i = this->begin(); - i != this->end(); ++i) + int err = 0; + const char* eq = strchr(env, '='); + size_t const len = eq? (size_t)(eq-env) : strlen(env); +# ifdef KWSYS_PUTENV_EMPTY + size_t const sz = len + 2; +# else + size_t const sz = len + 1; +# endif + char local_buf[256]; + char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf; + if(!buf) + { + return -1; + } + strncpy(buf, env, len); +# ifdef KWSYS_PUTENV_EMPTY + buf[len] = '='; + buf[len+1] = 0; + if(putenv(buf) < 0) + { + err = errno; + } +# else + buf[len] = 0; + if(putenv(buf) < 0 && errno != EINVAL) + { + err = errno; + } +# endif + if(buf != local_buf) + { + free(buf); + } + if(err) + { + errno = err; + return -1; + } + return 0; +} + +#else +/* Manipulate the "environ" global directly. */ +static int kwsysUnPutEnv(const char* env) +{ + const char* eq = strchr(env, '='); + size_t const len = eq? (size_t)(eq-env) : strlen(env); + int in = 0; + int out = 0; + while(environ[in]) + { + if(strlen(environ[in]) > len && + environ[in][len] == '=' && + strncmp(env, environ[in], len) == 0) + { + ++in; + } + else + { + environ[out++] = environ[in++]; + } + } + while(out < in) { - delete []*i; + environ[out++] = 0; } + return 0; +} #endif + +//---------------------------------------------------------------------------- + +#if KWSYS_CXX_HAS_SETENV + +/* setenv("A", "B", 1) will set A=B in the environment and makes its + own copies of the strings. */ +bool SystemTools::PutEnv(const char* env) +{ + if(const char* eq = strchr(env, '=')) + { + std::string name(env, eq-env); + return setenv(name.c_str(), eq+1, 1) == 0; + } + else + { + return kwsysUnPutEnv(env) == 0; + } } -bool SystemTools::PutEnv(const char* value) + +bool SystemTools::UnPutEnv(const char* env) { - static kwsysDeletingCharVector localEnvironment; - char* envVar = new char[strlen(value)+1]; - strcpy(envVar, value); - int ret = putenv(envVar); - // save the pointer in the static vector so that it can - // be deleted on exit - localEnvironment.push_back(envVar); - return ret == 0; + return kwsysUnPutEnv(env) == 0; } +#else + +/* putenv("A=B") will set A=B in the environment. Most putenv implementations + put their argument directly in the environment. They never free the memory + on program exit. Keep an active set of pointers to memory we allocate and + pass to putenv, one per environment key. At program exit remove any + environment values that may still reference memory we allocated. Then free + the memory. This will not affect any environment values we never set. */ + +# ifdef __INTEL_COMPILER +# pragma warning disable 444 /* base has non-virtual destructor */ +# endif + +/* Order by environment key only (VAR from VAR=VALUE). */ +struct kwsysEnvCompare +{ + bool operator() (const char* l, const char* r) const + { + const char* leq = strchr(l, '='); + const char* req = strchr(r, '='); + size_t llen = leq? (leq-l) : strlen(l); + size_t rlen = req? (req-r) : strlen(r); + if(llen == rlen) + { + return strncmp(l,r,llen) < 0; + } + else + { + return strcmp(l,r) < 0; + } + } +}; + +class kwsysEnv: public kwsys_stl::set<const char*, kwsysEnvCompare> +{ + class Free + { + const char* Env; + public: + Free(const char* env): Env(env) {} + ~Free() { free(const_cast<char*>(this->Env)); } + }; +public: + typedef kwsys_stl::set<const char*, kwsysEnvCompare> derived; + ~kwsysEnv() + { + for(derived::iterator i = this->begin(); i != this->end(); ++i) + { + kwsysUnPutEnv(*i); + free(const_cast<char*>(*i)); + } + } + const char* Release(const char* env) + { + const char* old = 0; + derived::iterator i = this->find(env); + if(i != this->end()) + { + old = *i; + this->erase(i); + } + return old; + } + bool Put(const char* env) + { + Free oldEnv(this->Release(env)); + static_cast<void>(oldEnv); + char* newEnv = strdup(env); + this->insert(newEnv); + return putenv(newEnv) == 0; + } + bool UnPut(const char* env) + { + Free oldEnv(this->Release(env)); + static_cast<void>(oldEnv); + return kwsysUnPutEnv(env) == 0; + } +}; + +static kwsysEnv kwsysEnvInstance; + +bool SystemTools::PutEnv(const char* env) +{ + return kwsysEnvInstance.Put(env); +} + +bool SystemTools::UnPutEnv(const char* env) +{ + return kwsysEnvInstance.UnPut(env); +} + +#endif + +//---------------------------------------------------------------------------- + const char* SystemTools::GetExecutableExtension() { #if defined(_WIN32) || defined(__CYGWIN__) || defined(__VMS) diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index 04f1978..5171125 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -749,7 +749,11 @@ public: /** Put a string into the environment of the form var=value */ - static bool PutEnv(const char* value); + static bool PutEnv(const char* env); + + /** Remove a string from the environment. + Input is of the form "var" or "var=value" (value is ignored). */ + static bool UnPutEnv(const char* env); /** * Get current working directory CWD diff --git a/Source/kwsys/kwsysDateStamp.cmake b/Source/kwsys/kwsysDateStamp.cmake deleted file mode 100644 index 3d0f03d..0000000 --- a/Source/kwsys/kwsysDateStamp.cmake +++ /dev/null @@ -1,21 +0,0 @@ -# Do not edit! Generated by kwsysDateStamp.py -#============================================================================= -# KWSys - Kitware System Library -# 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. -#============================================================================= - -# KWSys version date year component. Format is CCYY. -SET(KWSYS_DATE_STAMP_YEAR 2012) - -# KWSys version date month component. Format is MM. -SET(KWSYS_DATE_STAMP_MONTH 04) - -# KWSys version date day component. Format is DD. -SET(KWSYS_DATE_STAMP_DAY 20) diff --git a/Source/kwsys/kwsysDateStamp.py b/Source/kwsys/kwsysDateStamp.py deleted file mode 100755 index bd2e49a..0000000 --- a/Source/kwsys/kwsysDateStamp.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/python -#============================================================================= -# KWSys - Kitware System Library -# 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. -#============================================================================= - -import sys,os -import time - -# Get the path to the directory containing this script. -if __name__ == '__main__': - selfdir = os.path.abspath(sys.path[0] or os.curdir) -else: - selfdir = os.path.abspath(os.path.dirname(__file__)) - -# Open the CMake code file. -fname = os.path.join(selfdir, 'kwsysDateStamp.cmake') -fout = open(fname, 'w'); - -# Get the current time. -ct = time.localtime() - -# Write the CMake code describing the date. -fout.write("""# Do not edit! Generated by kwsysDateStamp.py -#============================================================================= -# KWSys - Kitware System Library -# 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. -#============================================================================= - -# KWSys version date year component. Format is CCYY. -SET(KWSYS_DATE_STAMP_YEAR %04u) - -# KWSys version date month component. Format is MM. -SET(KWSYS_DATE_STAMP_MONTH %02u) - -# KWSys version date day component. Format is DD. -SET(KWSYS_DATE_STAMP_DAY %02u) -""" % (ct.tm_year, ct.tm_mon, ct.tm_mday)) - -fout.close() diff --git a/Source/kwsys/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx index 903be9b..16124d3 100644 --- a/Source/kwsys/kwsysPlatformTestsCXX.cxx +++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx @@ -393,6 +393,32 @@ int main(int, char **argv) } #endif +#ifdef TEST_KWSYS_CXX_HAS_SETENV +#include <stdlib.h> +int main() +{ + return setenv("A", "B", 1); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_UNSETENV +#include <stdlib.h> +int main() +{ + unsetenv("A"); + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H +#include <stdlib.h> +int main() +{ + char* e = environ[0]; + return e? 0:1; +} +#endif + #ifdef TEST_KWSYS_CXX_TYPE_INFO /* Collect fundamental type information and save it to a CMake script. */ diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index c0e74af..3ac0cb3 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -328,6 +328,58 @@ bool CheckStringOperations() } //---------------------------------------------------------------------------- + +bool CheckPutEnv(const char* env, const char* name, const char* value) +{ + if(!kwsys::SystemTools::PutEnv(env)) + { + kwsys_ios::cerr << "PutEnv(\"" << env + << "\") failed!" << kwsys_ios::endl; + return false; + } + const char* v = kwsys::SystemTools::GetEnv(name); + v = v? v : "(null)"; + if(strcmp(v, value) != 0) + { + kwsys_ios::cerr << "GetEnv(\"" << name << "\") returned \"" + << v << "\", not \"" << value << "\"!" << kwsys_ios::endl; + return false; + } + return true; +} + +bool CheckUnPutEnv(const char* env, const char* name) +{ + if(!kwsys::SystemTools::UnPutEnv(env)) + { + kwsys_ios::cerr << "UnPutEnv(\"" << env << "\") failed!" + << kwsys_ios::endl; + return false; + } + if(const char* v = kwsys::SystemTools::GetEnv(name)) + { + kwsys_ios::cerr << "GetEnv(\"" << name << "\") returned \"" + << v << "\", not (null)!" << kwsys_ios::endl; + return false; + } + return true; +} + +bool CheckEnvironmentOperations() +{ + bool res = true; + res &= CheckPutEnv("A=B", "A", "B"); + res &= CheckPutEnv("B=C", "B", "C"); + res &= CheckPutEnv("C=D", "C", "D"); + res &= CheckPutEnv("D=E", "D", "E"); + res &= CheckUnPutEnv("A", "A"); + res &= CheckUnPutEnv("B=", "B"); + res &= CheckUnPutEnv("C=D", "C"); + /* Leave "D=E" in environment so a memory checker can test for leaks. */ + return res; +} + +//---------------------------------------------------------------------------- int testSystemTools(int, char*[]) { bool res = true; @@ -356,5 +408,7 @@ int testSystemTools(int, char*[]) res &= CheckStringOperations(); + res &= CheckEnvironmentOperations(); + return res ? 0 : 1; } |