diff options
author | Brad King <brad.king@kitware.com> | 2015-09-22 17:57:08 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2015-09-22 17:57:08 (GMT) |
commit | 2e6063068c94d4045e699fed51e6d1e9af344bbf (patch) | |
tree | d11025f71134b3238e52655640dcdf2158425597 /Source | |
parent | 81739e9215ef10d870f14404b0ec5eb4bee16ce4 (diff) | |
parent | 3bb707f0a1408dc0381ecbf4ec934e9f14d8927c (diff) | |
download | CMake-2e6063068c94d4045e699fed51e6d1e9af344bbf.zip CMake-2e6063068c94d4045e699fed51e6d1e9af344bbf.tar.gz CMake-2e6063068c94d4045e699fed51e6d1e9af344bbf.tar.bz2 |
Merge branch 'improve-variable-help-formatting' into revert-cmake-W-options
Resolve conflicts in
Help/variable/CMAKE_ERROR_DEPRECATED.rst
Help/variable/CMAKE_WARN_DEPRECATED.rst
by integrating changes from both sides.
Diffstat (limited to 'Source')
100 files changed, 4805 insertions, 3361 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 92fee8a..428b364 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -288,6 +288,7 @@ set(SRCS cmInstallDirectoryGenerator.h cmInstallDirectoryGenerator.cxx cmLinkedTree.h + cmLinkItem.h cmListFileCache.cxx cmListFileCache.h cmListFileLexer.c diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 612ab7e..f0a7cbd 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 3) -set(CMake_VERSION_PATCH 20150728) +set(CMake_VERSION_PATCH 20150819) #set(CMake_VERSION_RC 1) diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 6369e17..65599e0 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -1474,7 +1474,12 @@ int cmCTestCoverageHandler::HandleLCovCoverage( << std::endl, this->Quiet); std::vector<std::string> files; - this->FindLCovFiles(files); + if (!this->FindLCovFiles(files)) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Error while finding LCov files.\n"); + return 0; + } std::vector<std::string>::iterator it; if (files.empty()) @@ -1745,18 +1750,28 @@ void cmCTestCoverageHandler::FindGCovFiles(std::vector<std::string>& files) } //---------------------------------------------------------------------------- -void cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files) +bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files) { cmsys::Glob gl; gl.RecurseOff(); // No need of recurse if -prof_dir${BUILD_DIR} flag is // used while compiling. gl.RecurseThroughSymlinksOff(); std::string prevBinaryDir; - cmSystemTools::ChangeDirectory( - this->CTest->GetCTestConfiguration("BuildDirectory")); + std::string buildDir = this->CTest->GetCTestConfiguration("BuildDirectory"); + if (cmSystemTools::ChangeDirectory(buildDir)) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Error changing directory to " << buildDir << std::endl); + return false; + } // Run profmerge to merge all *.dyn files into dpi files - cmSystemTools::RunSingleCommand("profmerge"); + if (!cmSystemTools::RunSingleCommand("profmerge")) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Error while running profmerge.\n"); + return false; + } prevBinaryDir = cmSystemTools::GetCurrentWorkingDirectory().c_str(); @@ -1766,10 +1781,16 @@ void cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files) daGlob += "/*.dpi"; cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " looking for dpi files in: " << daGlob << std::endl, this->Quiet); - gl.FindFiles(daGlob); + if (!gl.FindFiles(daGlob)) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Error while finding files matching " << daGlob << std::endl); + return false; + } files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end()); cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Now searching in: " << daGlob << std::endl, this->Quiet); + return true; } //---------------------------------------------------------------------- diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h index 2ca123a..7102d1e 100644 --- a/Source/CTest/cmCTestCoverageHandler.h +++ b/Source/CTest/cmCTestCoverageHandler.h @@ -75,7 +75,7 @@ private: //! Handle coverage using Intel's LCov int HandleLCovCoverage(cmCTestCoverageHandlerContainer* cont); - void FindLCovFiles(std::vector<std::string>& files); + bool FindLCovFiles(std::vector<std::string>& files); //! Handle coverage using xdebug php coverage int HandlePHPCoverage(cmCTestCoverageHandlerContainer* cont); diff --git a/Source/QtDialog/Info.plist.in b/Source/QtDialog/Info.plist.in index b9c4af5..00a27c3 100644 --- a/Source/QtDialog/Info.plist.in +++ b/Source/QtDialog/Info.plist.in @@ -28,5 +28,7 @@ <string>public.app-category.developer-tools</string> <key>NSHumanReadableCopyright</key> <string>${MACOSX_BUNDLE_COPYRIGHT}</string> + <key>NSHighResolutionCapable</key> + <true/> </dict> </plist> diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index f65bd29..b976469 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -1546,9 +1546,8 @@ void cmCTest::StartXML(cmXMLWriter& xml, bool append) xml.Attribute("Append", "true"); } xml.Attribute("CompilerName", this->GetCTestConfiguration("Compiler")); -#ifdef _COMPILER_VERSION - xml.Attribute("CompilerVersion", _COMPILER_VERSION); -#endif + xml.Attribute("CompilerVersion", + this->GetCTestConfiguration("CompilerVersion")); xml.Attribute("OSName", info.GetOSName()); xml.Attribute("Hostname", info.GetHostname()); xml.Attribute("OSRelease", info.GetOSRelease()); diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 2225fdc..4840e89 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -20,8 +20,12 @@ #include "cmSystemTools.h" #include "cmTarget.h" -cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt) - : GeneratorTarget(gt) +cmCommonTargetGenerator::cmCommonTargetGenerator( + cmOutputConverter::RelativeRoot wd, + cmGeneratorTarget* gt + ) + : WorkingDirectory(wd) + , GeneratorTarget(gt) , Target(gt->Target) , Makefile(gt->Makefile) , LocalGenerator(static_cast<cmLocalCommonGenerator*>(gt->LocalGenerator)) @@ -101,47 +105,47 @@ void cmCommonTargetGenerator::AddModuleDefinitionFlag(std::string& flags) } //---------------------------------------------------------------------------- -const char* cmCommonTargetGenerator::GetFortranModuleDirectory() +std::string cmCommonTargetGenerator::ComputeFortranModuleDirectory() const { - // Compute the module directory. - if(!this->FortranModuleDirectoryComputed) + std::string mod_dir; + const char* target_mod_dir = + this->Target->GetProperty("Fortran_MODULE_DIRECTORY"); + const char* moddir_flag = + this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG"); + if(target_mod_dir && moddir_flag) { - const char* target_mod_dir = - this->Target->GetProperty("Fortran_MODULE_DIRECTORY"); - const char* moddir_flag = - this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG"); - if(target_mod_dir && moddir_flag) + // Compute the full path to the module directory. + if(cmSystemTools::FileIsFullPath(target_mod_dir)) { - // Compute the full path to the module directory. - if(cmSystemTools::FileIsFullPath(target_mod_dir)) - { - // Already a full path. - this->FortranModuleDirectory = target_mod_dir; - } - else - { - // Interpret relative to the current output directory. - this->FortranModuleDirectory = - this->Makefile->GetCurrentBinaryDirectory(); - this->FortranModuleDirectory += "/"; - this->FortranModuleDirectory += target_mod_dir; - } - - // Make sure the module output directory exists. - cmSystemTools::MakeDirectory(this->FortranModuleDirectory.c_str()); + // Already a full path. + mod_dir = target_mod_dir; + } + else + { + // Interpret relative to the current output directory. + mod_dir = this->Makefile->GetCurrentBinaryDirectory(); + mod_dir += "/"; + mod_dir += target_mod_dir; } - this->FortranModuleDirectoryComputed = true; - } - // Return the computed directory. - if(this->FortranModuleDirectory.empty()) - { - return 0; + // Make sure the module output directory exists. + cmSystemTools::MakeDirectory(mod_dir); } - else + return mod_dir; +} + +//---------------------------------------------------------------------------- +std::string cmCommonTargetGenerator::GetFortranModuleDirectory() +{ + // Compute the module directory. + if(!this->FortranModuleDirectoryComputed) { - return this->FortranModuleDirectory.c_str(); + this->FortranModuleDirectoryComputed = true; + this->FortranModuleDirectory = this->ComputeFortranModuleDirectory(); } + + // Return the computed directory. + return this->FortranModuleDirectory; } //---------------------------------------------------------------------------- @@ -155,19 +159,24 @@ void cmCommonTargetGenerator::AddFortranFlags(std::string& flags) } // Add a module output directory flag if necessary. - const char* mod_dir = this->GetFortranModuleDirectory(); - if(!mod_dir) + std::string mod_dir = this->GetFortranModuleDirectory(); + if (!mod_dir.empty()) + { + mod_dir = this->Convert(mod_dir, + this->WorkingDirectory, + cmLocalGenerator::SHELL); + } + else { - mod_dir = this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_DEFAULT"); + mod_dir = + this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODDIR_DEFAULT"); } - if(mod_dir) + if (!mod_dir.empty()) { const char* moddir_flag = this->Makefile->GetRequiredDefinition("CMAKE_Fortran_MODDIR_FLAG"); std::string modflag = moddir_flag; - modflag += this->Convert(mod_dir, - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL); + modflag += mod_dir; this->LocalGenerator->AppendFlags(flags, modflag); } @@ -267,7 +276,8 @@ std::string cmCommonTargetGenerator::GetFrameworkFlags(std::string const& l) std::string flags; const char* cfg = this->LocalGenerator->GetConfigName().c_str(); - if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(cfg)) + if(cmComputeLinkInformation* cli = + this->GeneratorTarget->GetLinkInformation(cfg)) { std::vector<std::string> const& frameworks = cli->GetFrameworkPaths(); for(std::vector<std::string>::const_iterator i = frameworks.begin(); @@ -368,3 +378,37 @@ std::string cmCommonTargetGenerator::GetIncludes(std::string const& l) } return i->second; } + +std::vector<std::string> +cmCommonTargetGenerator::GetLinkedTargetDirectories() const +{ + std::vector<std::string> dirs; + std::set<cmTarget const*> emitted; + if (cmComputeLinkInformation* cli = + this->GeneratorTarget->GetLinkInformation(this->ConfigName)) + { + cmComputeLinkInformation::ItemVector const& items = cli->GetItems(); + for(cmComputeLinkInformation::ItemVector::const_iterator + i = items.begin(); i != items.end(); ++i) + { + cmTarget const* linkee = i->Target; + if(linkee && !linkee->IsImported() + // We can ignore the INTERFACE_LIBRARY items because + // Target->GetLinkInformation already processed their + // link interface and they don't have any output themselves. + && linkee->GetType() != cmTarget::INTERFACE_LIBRARY + && emitted.insert(linkee).second) + { + cmGeneratorTarget* gt = + this->GlobalGenerator->GetGeneratorTarget(linkee); + cmLocalGenerator* lg = gt->GetLocalGenerator(); + cmMakefile* mf = linkee->GetMakefile(); + std::string di = mf->GetCurrentBinaryDirectory(); + di += "/"; + di += lg->GetTargetDirectory(*linkee); + dirs.push_back(di); + } + } + } + return dirs; +} diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index 5451a5a..0a49e12 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -29,7 +29,8 @@ class cmTarget; class cmCommonTargetGenerator { public: - cmCommonTargetGenerator(cmGeneratorTarget* gt); + cmCommonTargetGenerator(cmOutputConverter::RelativeRoot wd, + cmGeneratorTarget* gt); virtual ~cmCommonTargetGenerator(); std::string const& GetConfigName() const; @@ -46,6 +47,7 @@ protected: // Helper to add flag for windows .def file. void AddModuleDefinitionFlag(std::string& flags); + cmOutputConverter::RelativeRoot WorkingDirectory; cmGeneratorTarget* GeneratorTarget; cmTarget* Target; cmMakefile* Makefile; @@ -59,7 +61,8 @@ protected: // Target-wide Fortran module output directory. bool FortranModuleDirectoryComputed; std::string FortranModuleDirectory; - const char* GetFortranModuleDirectory(); + std::string GetFortranModuleDirectory(); + virtual std::string ComputeFortranModuleDirectory() const; // Compute target-specific Fortran language flags. void AddFortranFlags(std::string& flags); @@ -85,6 +88,8 @@ protected: ByLanguageMap DefinesByLanguage; std::string GetIncludes(std::string const& l); ByLanguageMap IncludesByLanguage; + + std::vector<std::string> GetLinkedTargetDirectories() const; }; #endif diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index abd9877..8ba8847 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -173,18 +173,19 @@ items that we know the linker will re-use automatically (shared libs). //---------------------------------------------------------------------------- cmComputeLinkDepends -::cmComputeLinkDepends(cmTarget const* target, const std::string& config) +::cmComputeLinkDepends(const cmGeneratorTarget* target, + const std::string& config) { // Store context information. this->Target = target; - this->Makefile = this->Target->GetMakefile(); + this->Makefile = this->Target->Target->GetMakefile(); this->GlobalGenerator = this->Makefile->GetGlobalGenerator(); this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance(); // The configuration being linked. this->HasConfig = !config.empty(); this->Config = (this->HasConfig)? config : std::string(); - this->LinkType = this->Target->ComputeLinkType(this->Config); + this->LinkType = this->Target->Target->ComputeLinkType(this->Config); // Enable debug mode if requested. this->DebugMode = this->Makefile->IsOn("CMAKE_LINK_DEPENDS_DEBUG_MODE"); @@ -363,7 +364,7 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe) { // Follow the target dependencies. if(cmTarget::LinkInterface const* iface = - entry.Target->GetLinkInterface(this->Config, this->Target)) + entry.Target->GetLinkInterface(this->Config, this->Target->Target)) { const bool isIface = entry.Target->GetType() == cmTarget::INTERFACE_LIBRARY; @@ -461,7 +462,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep) if(entry.Target) { if(cmTarget::LinkInterface const* iface = - entry.Target->GetLinkInterface(this->Config, this->Target)) + entry.Target->GetLinkInterface(this->Config, this->Target->Target)) { // Follow public and private dependencies transitively. this->FollowSharedDeps(index, iface, true); @@ -552,7 +553,7 @@ void cmComputeLinkDepends::AddDirectLinkEntries() { // Add direct link dependencies in this configuration. cmTarget::LinkImplementation const* impl = - this->Target->GetLinkImplementation(this->Config); + this->Target->Target->GetLinkImplementation(this->Config); this->AddLinkEntries(-1, impl->Libraries); for(std::vector<cmLinkItem>::const_iterator wi = impl->WrongConfigLibraries.begin(); @@ -634,7 +635,7 @@ cmTarget const* cmComputeLinkDepends::FindTargetToLink(int depender_index, const std::string& name) { // Look for a target in the scope of the depender. - cmTarget const* from = this->Target; + cmTarget const* from = this->Target->Target; if(depender_index >= 0) { if(cmTarget const* depender = this->EntryList[depender_index].Target) @@ -932,7 +933,7 @@ int cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl) if(cmTarget const* target = this->EntryList[*ni].Target) { if(cmTarget::LinkInterface const* iface = - target->GetLinkInterface(this->Config, this->Target)) + target->GetLinkInterface(this->Config, this->Target->Target)) { if(iface->Multiplicity > count) { diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 51a08c5..b925a4f 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -22,6 +22,7 @@ class cmComputeComponentGraph; class cmGlobalGenerator; class cmMakefile; +class cmGeneratorTarget; class cmTarget; class cmake; @@ -31,7 +32,8 @@ class cmake; class cmComputeLinkDepends { public: - cmComputeLinkDepends(cmTarget const* target, const std::string& config); + cmComputeLinkDepends(cmGeneratorTarget const* target, + const std::string& config); ~cmComputeLinkDepends(); // Basic information about each link item. @@ -57,7 +59,7 @@ public: private: // Context information. - cmTarget const* Target; + cmGeneratorTarget const* Target; cmMakefile* Makefile; cmGlobalGenerator const* GlobalGenerator; cmake* CMakeInstance; diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index e63b44f..6ba0eed 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -14,11 +14,13 @@ #include "cmComputeLinkDepends.h" #include "cmOrderDirectories.h" +#include "cmLocalGenerator.h" #include "cmGlobalGenerator.h" #include "cmState.h" #include "cmOutputConverter.h" #include "cmMakefile.h" #include "cmTarget.h" +#include "cmGeneratorTarget.h" #include "cmake.h" #include "cmAlgorithms.h" @@ -241,12 +243,14 @@ because this need be done only for shared libraries without soname-s. //---------------------------------------------------------------------------- cmComputeLinkInformation -::cmComputeLinkInformation(cmTarget const* target, const std::string& config) +::cmComputeLinkInformation(const cmGeneratorTarget* target, + const std::string& config) { // Store context information. this->Target = target; - this->Makefile = this->Target->GetMakefile(); - this->GlobalGenerator = this->Makefile->GetGlobalGenerator(); + this->Makefile = this->Target->Target->GetMakefile(); + this->GlobalGenerator = + this->Target->GetLocalGenerator()->GetGlobalGenerator(); this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance(); // Check whether to recognize OpenBSD-style library versioned names. @@ -280,14 +284,14 @@ cmComputeLinkInformation // Check whether we should skip dependencies on shared library files. this->LinkDependsNoShared = - this->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED"); + this->Target->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED"); // On platforms without import libraries there may be a special flag // to use when creating a plugin (module) that obtains symbols from // the program that will load it. this->LoaderFlag = 0; if(!this->UseImportLibrary && - this->Target->GetType() == cmTarget::MODULE_LIBRARY) + this->Target->Target->GetType() == cmTarget::MODULE_LIBRARY) { std::string loader_flag_var = "CMAKE_SHARED_MODULE_LOADER_"; loader_flag_var += this->LinkLanguage; @@ -305,10 +309,10 @@ cmComputeLinkInformation // Get options needed to specify RPATHs. this->RuntimeUseChrpath = false; - if(this->Target->GetType() != cmTarget::STATIC_LIBRARY) + if(this->Target->Target->GetType() != cmTarget::STATIC_LIBRARY) { const char* tType = - ((this->Target->GetType() == cmTarget::EXECUTABLE)? + ((this->Target->Target->GetType() == cmTarget::EXECUTABLE)? "EXECUTABLE" : "SHARED_LIBRARY"); std::string rtVar = "CMAKE_"; rtVar += tType; @@ -321,6 +325,7 @@ cmComputeLinkInformation this->RuntimeAlways = (this->Makefile-> GetSafeDefinition("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH")); + this->RuntimeUseChrpath = this->Target->IsChrpathUsed(config); // Get options needed to help find dependent libraries. @@ -373,9 +378,9 @@ cmComputeLinkInformation // Add the search path entries requested by the user to path ordering. this->OrderLinkerSearchPath - ->AddUserDirectories(this->Target->GetLinkDirectories()); + ->AddUserDirectories(this->Target->Target->GetLinkDirectories()); this->OrderRuntimeSearchPath - ->AddUserDirectories(this->Target->GetLinkDirectories()); + ->AddUserDirectories(this->Target->Target->GetLinkDirectories()); // Set up the implicit link directories. this->LoadImplicitLinkInfo(); @@ -403,12 +408,13 @@ cmComputeLinkInformation // order to support such projects we need to add the directories // containing libraries linked with a full path to the -L path. this->OldLinkDirMode = - this->Target->GetPolicyStatusCMP0003() != cmPolicies::NEW; + this->Target->Target->GetPolicyStatusCMP0003() != cmPolicies::NEW; if(this->OldLinkDirMode) { // Construct a mask to not bother with this behavior for link // directories already specified by the user. - std::vector<std::string> const& dirs = this->Target->GetLinkDirectories(); + std::vector<std::string> const& dirs = + this->Target->Target->GetLinkDirectories(); this->OldLinkDirMask.insert(dirs.begin(), dirs.end()); } @@ -514,10 +520,12 @@ bool cmComputeLinkInformation::Compute() // Restore the target link type so the correct system runtime // libraries are found. - const char* lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC"); - if(cmSystemTools::IsOn(lss)) + const char* lss = + this->Target->Target->GetProperty("LINK_SEARCH_END_STATIC"); + if(lss) { - this->SetCurrentLinkType(LinkStatic); + this->SetCurrentLinkType( + cmSystemTools::IsOn(lss) ? LinkStatic : LinkShared); } else { @@ -535,9 +543,7 @@ bool cmComputeLinkInformation::Compute() i != wrongItems.end(); ++i) { cmTarget const* tgt = *i; - cmGeneratorTarget *gtgt = tgt->GetMakefile() - ->GetGlobalGenerator() - ->GetGeneratorTarget(tgt); + cmGeneratorTarget *gtgt = this->GlobalGenerator->GetGeneratorTarget(tgt); bool implib = (this->UseImportLibrary && (tgt->GetType() == cmTarget::SHARED_LIBRARY)); @@ -567,7 +573,7 @@ bool cmComputeLinkInformation::Compute() "name." ; this->CMakeInstance->IssueMessage(cmake::AUTHOR_WARNING, w.str(), - this->Target->GetBacktrace()); + this->Target->Target->GetBacktrace()); } return true; @@ -577,7 +583,8 @@ bool cmComputeLinkInformation::Compute() void cmComputeLinkInformation::AddImplicitLinkInfo() { // The link closure lists all languages whose implicit info is needed. - cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config); + cmGeneratorTarget::LinkClosure const* lc = + this->Target->GetLinkClosure(this->Config); for(std::vector<std::string>::const_iterator li = lc->Languages.begin(); li != lc->Languages.end(); ++li) { @@ -640,9 +647,7 @@ void cmComputeLinkInformation::AddItem(std::string const& item, if(tgt && tgt->IsLinkable()) { - cmGeneratorTarget *gtgt = tgt->GetMakefile() - ->GetGlobalGenerator() - ->GetGeneratorTarget(tgt); + cmGeneratorTarget *gtgt = this->GlobalGenerator->GetGeneratorTarget(tgt); // This is a CMake target. Ask the target for its real name. if(impexe && this->LoaderFlag) { @@ -756,15 +761,16 @@ void cmComputeLinkInformation::AddSharedDepItem(std::string const& item, return; } + cmGeneratorTarget *gtgt = 0; + // Get a full path to the dependent shared library. // Add it to the runtime path computation so that the target being // linked will be able to find it. std::string lib; if(tgt) { - cmGeneratorTarget *gtgt = tgt->GetMakefile() - ->GetGlobalGenerator() - ->GetGeneratorTarget(tgt); + gtgt = tgt->GetMakefile()->GetGlobalGenerator()->GetGeneratorTarget(tgt); + lib = gtgt->GetFullPath(this->Config, this->UseImportLibrary); this->AddLibraryRuntimeInfo(lib, tgt); } @@ -790,9 +796,9 @@ void cmComputeLinkInformation::AddSharedDepItem(std::string const& item, } if(order) { - if(tgt) + if(gtgt) { - std::string soName = tgt->GetSOName(this->Config); + std::string soName = gtgt->GetSOName(this->Config); const char* soname = soName.empty()? 0 : soName.c_str(); order->AddRuntimeLibrary(lib, soname); } @@ -854,9 +860,11 @@ void cmComputeLinkInformation::ComputeLinkTypeInfo() } // Lookup the starting link type from the target (linked statically?). - const char* lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC"); + const char* lss = + this->Target->Target->GetProperty("LINK_SEARCH_START_STATIC"); this->StartLinkType = cmSystemTools::IsOn(lss)? LinkStatic : LinkShared; - this->CurrentLinkType = this->StartLinkType; + this->CurrentLinkType = LinkUnknown; + this->SetCurrentLinkType(this->StartLinkType); } //---------------------------------------------------------------------------- @@ -1140,7 +1148,7 @@ void cmComputeLinkInformation::AddFullItem(std::string const& item) // Full path libraries should specify a valid library file name. // See documentation of CMP0008. std::string generator = this->GlobalGenerator->GetName(); - if(this->Target->GetPolicyStatusCMP0008() != cmPolicies::NEW && + if(this->Target->Target->GetPolicyStatusCMP0008() != cmPolicies::NEW && (generator.find("Visual Studio") != generator.npos || generator.find("Xcode") != generator.npos)) { @@ -1221,7 +1229,7 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) } // Check the policy for whether we should use the approach below. - switch (this->Target->GetPolicyStatusCMP0060()) + switch (this->Target->Target->GetPolicyStatusCMP0060()) { case cmPolicies::WARN: if (this->CMP0060Warn) @@ -1531,7 +1539,7 @@ void cmComputeLinkInformation::HandleBadFullItem(std::string const& item, this->OrderLinkerSearchPath->AddLinkLibrary(item); // Produce any needed message. - switch(this->Target->GetPolicyStatusCMP0008()) + switch(this->Target->Target->GetPolicyStatusCMP0008()) { case cmPolicies::WARN: { @@ -1548,7 +1556,7 @@ void cmComputeLinkInformation::HandleBadFullItem(std::string const& item, << " " << item << "\n" << "which is a full-path but not a valid library file name."; this->CMakeInstance->IssueMessage(cmake::AUTHOR_WARNING, w.str(), - this->Target->GetBacktrace()); + this->Target->Target->GetBacktrace()); } } case cmPolicies::OLD: @@ -1566,7 +1574,7 @@ void cmComputeLinkInformation::HandleBadFullItem(std::string const& item, << " " << item << "\n" << "which is a full-path but not a valid library file name."; this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR, e.str(), - this->Target->GetBacktrace()); + this->Target->Target->GetBacktrace()); } break; } @@ -1583,7 +1591,7 @@ bool cmComputeLinkInformation::FinishLinkerSearchDirectories() } // Enforce policy constraints. - switch(this->Target->GetPolicyStatusCMP0003()) + switch(this->Target->Target->GetPolicyStatusCMP0003()) { case cmPolicies::WARN: if(!this->CMakeInstance->GetState() @@ -1594,7 +1602,7 @@ bool cmComputeLinkInformation::FinishLinkerSearchDirectories() std::ostringstream w; this->PrintLinkPolicyDiagnosis(w); this->CMakeInstance->IssueMessage(cmake::AUTHOR_WARNING, w.str(), - this->Target->GetBacktrace()); + this->Target->Target->GetBacktrace()); } case cmPolicies::OLD: // OLD behavior is to add the paths containing libraries with @@ -1610,7 +1618,7 @@ bool cmComputeLinkInformation::FinishLinkerSearchDirectories() e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0003) << "\n"; this->PrintLinkPolicyDiagnosis(e); this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR, e.str(), - this->Target->GetBacktrace()); + this->Target->Target->GetBacktrace()); return false; } } @@ -1804,7 +1812,8 @@ cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath, // Try to get the soname of the library. Only files with this name // could possibly conflict. - std::string soName = target->GetSOName(this->Config); + cmGeneratorTarget *gtgt = this->GlobalGenerator->GetGeneratorTarget(target); + std::string soName = gtgt->GetSOName(this->Config); const char* soname = soName.empty()? 0 : soName.c_str(); // Include this library in the runtime path ordering. @@ -1911,23 +1920,24 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, // build tree. bool linking_for_install = (for_install || - this->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")); + this->Target->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")); bool use_install_rpath = - (outputRuntime && this->Target->HaveInstallTreeRPATH() && + (outputRuntime && this->Target->Target->HaveInstallTreeRPATH() && linking_for_install); bool use_build_rpath = - (outputRuntime && this->Target->HaveBuildTreeRPATH(this->Config) && + (outputRuntime && this->Target->Target->HaveBuildTreeRPATH(this->Config) && !linking_for_install); bool use_link_rpath = outputRuntime && linking_for_install && !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH") && - this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH"); + this->Target->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH"); // Construct the RPATH. std::set<std::string> emitted; if(use_install_rpath) { - const char* install_rpath = this->Target->GetProperty("INSTALL_RPATH"); + const char* install_rpath = + this->Target->Target->GetProperty("INSTALL_RPATH"); cmCLI_ExpandListUnique(install_rpath, runtimeDirs, emitted); } if(use_build_rpath || use_link_rpath) @@ -1999,7 +2009,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, // Add runtime paths required by the languages to always be // present. This is done even when skipping rpath support. { - cmTarget::LinkClosure const* lc = + cmGeneratorTarget::LinkClosure const* lc = this->Target->GetLinkClosure(this->Config); for(std::vector<std::string>::const_iterator li = lc->Languages.begin(); li != lc->Languages.end(); ++li) diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 3afbb92..8b83574 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -20,6 +20,7 @@ class cmake; class cmGlobalGenerator; class cmMakefile; class cmTarget; +class cmGeneratorTarget; class cmOrderDirectories; /** \class cmComputeLinkInformation @@ -28,7 +29,8 @@ class cmOrderDirectories; class cmComputeLinkInformation { public: - cmComputeLinkInformation(cmTarget const* target, const std::string& config); + cmComputeLinkInformation(cmGeneratorTarget const* target, + const std::string& config); ~cmComputeLinkInformation(); bool Compute(); @@ -72,7 +74,7 @@ private: std::set<cmTarget const*> SharedLibrariesLinked; // Context information. - cmTarget const* Target; + cmGeneratorTarget const* Target; cmMakefile* Makefile; cmGlobalGenerator* GlobalGenerator; cmake* CMakeInstance; diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 420bfdf..7874803 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -16,7 +16,8 @@ cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile): Makefile(makefile), Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012)), Policy54Status(makefile.GetPolicyStatus(cmPolicies::CMP0054)), - Policy57Status(makefile.GetPolicyStatus(cmPolicies::CMP0057)) + Policy57Status(makefile.GetPolicyStatus(cmPolicies::CMP0057)), + Policy64Status(makefile.GetPolicyStatus(cmPolicies::CMP0064)) { } @@ -493,6 +494,29 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList &newArgs, this->Makefile.FindTargetToUse(argP1->GetValue())?true:false, reducible, arg, newArgs, argP1, argP2); } + // does a test exist + if(this->Policy64Status != cmPolicies::OLD && + this->Policy64Status != cmPolicies::WARN) + { + if (this->IsKeyword("TEST", *arg) && argP1 != newArgs.end()) + { + const cmTest* haveTest = this->Makefile.GetTest(argP1->c_str()); + this->HandlePredicate( + haveTest?true:false, + reducible, arg, newArgs, argP1, argP2); + } + } + else if(this->Policy64Status == cmPolicies::WARN && + this->IsKeyword("TEST", *arg)) + { + std::ostringstream e; + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0064) << "\n"; + e << "TEST will be interpreted as an operator " + "when the policy is set to NEW. " + "Since the policy is not set the OLD behavior will be used."; + + this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str()); + } // is a variable defined if (this->IsKeyword("DEFINED", *arg) && argP1 != newArgs.end()) { diff --git a/Source/cmConditionEvaluator.h b/Source/cmConditionEvaluator.h index c923d76..c4e2d11 100644 --- a/Source/cmConditionEvaluator.h +++ b/Source/cmConditionEvaluator.h @@ -94,6 +94,7 @@ private: cmPolicies::PolicyStatus Policy12Status; cmPolicies::PolicyStatus Policy54Status; cmPolicies::PolicyStatus Policy57Status; + cmPolicies::PolicyStatus Policy64Status; }; #endif diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index ffb349e..9411555 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -470,6 +470,16 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) { fprintf(fout, "set(CMAKE_POSITION_INDEPENDENT_CODE \"ON\")\n"); } + if (const char *lssDef = this->Makefile->GetDefinition( + "CMAKE_LINK_SEARCH_START_STATIC")) + { + fprintf(fout, "set(CMAKE_LINK_SEARCH_START_STATIC \"%s\")\n", lssDef); + } + if (const char *lssDef = this->Makefile->GetDefinition( + "CMAKE_LINK_SEARCH_END_STATIC")) + { + fprintf(fout, "set(CMAKE_LINK_SEARCH_END_STATIC \"%s\")\n", lssDef); + } /* Put the executable at a known location (for COPY_FILE). */ fprintf(fout, "set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n", diff --git a/Source/cmCurl.cxx b/Source/cmCurl.cxx index 96d3547..ad0c7d3 100644 --- a/Source/cmCurl.cxx +++ b/Source/cmCurl.cxx @@ -13,7 +13,7 @@ #include "cmSystemTools.h" #define check_curl_result(result, errstr) \ - if (result != CURLE_OK) \ + if (result != CURLE_OK && result != CURLE_NOT_BUILT_IN) \ { \ e += e.empty()? "" : "\n"; \ e += errstr; \ diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index 13c6409..856dcd4 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -154,14 +154,10 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends, const char* stamp_dir = this->TargetDirectory.c_str(); // Get the directory in which module files will be created. - const char* mod_dir; cmMakefile* mf = this->LocalGenerator->GetMakefile(); - if(const char* target_mod_dir = - mf->GetDefinition("CMAKE_Fortran_TARGET_MODULE_DIR")) - { - mod_dir = target_mod_dir; - } - else + std::string mod_dir = + mf->GetSafeDefinition("CMAKE_Fortran_TARGET_MODULE_DIR"); + if (mod_dir.empty()) { mod_dir = this->LocalGenerator->GetMakefile()->GetCurrentBinaryDirectory(); @@ -356,7 +352,8 @@ bool cmDependsFortran ::WriteDependenciesReal(const char *obj, cmFortranSourceInfo const& info, - const char* mod_dir, const char* stamp_dir, + std::string const& mod_dir, + const char* stamp_dir, std::ostream& makeDepends, std::ostream& internalDepends) { diff --git a/Source/cmDependsFortran.h b/Source/cmDependsFortran.h index d6ec7d7..a8a4013 100644 --- a/Source/cmDependsFortran.h +++ b/Source/cmDependsFortran.h @@ -66,7 +66,8 @@ protected: // Actually write the depenencies to the streams. bool WriteDependenciesReal(const char *obj, cmFortranSourceInfo const& info, - const char* mod_dir, const char* stamp_dir, + std::string const& mod_dir, + const char* stamp_dir, std::ostream& makeDepends, std::ostream& internalDepends); diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 355fc00..fed0dbc 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -27,6 +27,7 @@ cmExportBuildFileGenerator::cmExportBuildFileGenerator() //---------------------------------------------------------------------------- bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) { + std::vector<cmGeneratorTarget*> allTargets; { std::string expectedTargets; std::string sep; @@ -68,7 +69,8 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) tei = this->Exports.begin(); tei != this->Exports.end(); ++tei) { - cmTarget* te = (*tei)->Target; + cmGeneratorTarget* gte = *tei; + cmTarget* te = gte->Target; this->GenerateImportTargetCode(os, te); te->AppendBuildInterfaceIncludes(); @@ -104,7 +106,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) cmGeneratorExpression::BuildInterface, properties, missingTargets); } - this->PopulateCompatibleInterfaceProperties(te, properties); + this->PopulateCompatibleInterfaceProperties(gte, properties); this->GenerateInterfaceProperties(te, os, properties); } @@ -331,12 +333,12 @@ cmExportBuildFileGenerator } std::string -cmExportBuildFileGenerator::InstallNameDir(cmTarget* target, +cmExportBuildFileGenerator::InstallNameDir(cmGeneratorTarget* target, const std::string& config) { std::string install_name_dir; - cmMakefile* mf = target->GetMakefile(); + cmMakefile* mf = target->Target->GetMakefile(); if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { install_name_dir = diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 4d8e062..ff3d2e1 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -71,7 +71,8 @@ protected: cmGeneratorTarget* target, ImportPropertyMap& properties); - std::string InstallNameDir(cmTarget* target, const std::string& config); + std::string InstallNameDir(cmGeneratorTarget* target, + const std::string& config); std::vector<std::string> FindNamespaces(cmMakefile* mf, const std::string& name); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index a33cd59..cae60b7 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -525,7 +525,7 @@ void getPropertyContents(cmTarget const* tgt, const std::string& prop, } //---------------------------------------------------------------------------- -void getCompatibleInterfaceProperties(cmTarget *target, +void getCompatibleInterfaceProperties(cmGeneratorTarget *target, std::set<std::string> &ifaceProperties, const std::string& config) { @@ -533,7 +533,7 @@ void getCompatibleInterfaceProperties(cmTarget *target, if (!info) { - cmMakefile* mf = target->GetMakefile(); + cmMakefile* mf = target->Target->GetMakefile(); std::ostringstream e; e << "Exporting the target \"" << target->GetName() << "\" is not " "allowed since its linker language cannot be determined"; @@ -568,9 +568,10 @@ void getCompatibleInterfaceProperties(cmTarget *target, //---------------------------------------------------------------------------- void cmExportFileGenerator::PopulateCompatibleInterfaceProperties( - cmTarget *target, + cmGeneratorTarget *gtarget, ImportPropertyMap &properties) { + cmTarget *target = gtarget->Target; this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_BOOL", target, properties); this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_STRING", @@ -591,7 +592,7 @@ void cmExportFileGenerator::PopulateCompatibleInterfaceProperties( if (target->GetType() != cmTarget::INTERFACE_LIBRARY) { - getCompatibleInterfaceProperties(target, ifaceProperties, ""); + getCompatibleInterfaceProperties(gtarget, ifaceProperties, ""); std::vector<std::string> configNames; target->GetMakefile()->GetConfigurations(configNames); @@ -599,7 +600,7 @@ void cmExportFileGenerator::PopulateCompatibleInterfaceProperties( for (std::vector<std::string>::const_iterator ci = configNames.begin(); ci != configNames.end(); ++ci) { - getCompatibleInterfaceProperties(target, ifaceProperties, *ci); + getCompatibleInterfaceProperties(gtarget, ifaceProperties, *ci); } } @@ -888,14 +889,14 @@ cmExportFileGenerator { std::string prop; std::string value; - if(target->Target->HasSOName(config)) + if(target->HasSOName(config)) { if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { - value = this->InstallNameDir(target->Target, config); + value = this->InstallNameDir(target, config); } prop = "IMPORTED_SONAME"; - value += target->Target->GetSOName(config); + value += target->GetSOName(config); } else { diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 2f33200..44f779b 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -132,7 +132,7 @@ protected: std::vector<std::string> &missingTargets); void PopulateInterfaceProperty(const std::string& propName, cmTarget *target, ImportPropertyMap &properties); - void PopulateCompatibleInterfaceProperties(cmTarget *target, + void PopulateCompatibleInterfaceProperties(cmGeneratorTarget *target, ImportPropertyMap &properties); void GenerateInterfaceProperties(cmTarget const* target, std::ostream& os, const ImportPropertyMap &properties); @@ -200,7 +200,7 @@ private: virtual void ReplaceInstallPrefix(std::string &input); - virtual std::string InstallNameDir(cmTarget* target, + virtual std::string InstallNameDir(cmGeneratorTarget* target, const std::string& config) = 0; }; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 6c7d97e..d55be11 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -193,7 +193,11 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", te, properties); - this->PopulateCompatibleInterfaceProperties(te, properties); + cmGeneratorTarget *gtgt = te->GetMakefile() + ->GetGlobalGenerator() + ->GetGeneratorTarget(te); + + this->PopulateCompatibleInterfaceProperties(gtgt, properties); this->GenerateInterfaceProperties(te, os, properties); } @@ -358,7 +362,7 @@ cmExportInstallFileGenerator if(!properties.empty()) { // Get the rest of the target details. - cmGeneratorTarget *gtgt = te->Target->GetMakefile()->GetLocalGenerator() + cmGeneratorTarget *gtgt = te->Target->GetMakefile() ->GetGlobalGenerator()->GetGeneratorTarget(te->Target); this->SetImportDetailProperties(config, suffix, gtgt, properties, missingTargets); @@ -398,7 +402,7 @@ cmExportInstallFileGenerator } // Get the target to be installed. - cmTarget* target = itgen->GetTarget(); + cmTarget* target = itgen->GetTarget()->Target; // Construct the installed location of the target. std::string dest = itgen->GetDestination(config); @@ -542,12 +546,12 @@ cmExportInstallFileGenerator } std::string -cmExportInstallFileGenerator::InstallNameDir(cmTarget* target, +cmExportInstallFileGenerator::InstallNameDir(cmGeneratorTarget* target, const std::string&) { std::string install_name_dir; - cmMakefile* mf = target->GetMakefile(); + cmMakefile* mf = target->Target->GetMakefile(); if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { install_name_dir = diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index 6f86ac9..b06fee5 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -83,7 +83,8 @@ protected: std::set<std::string>& importedLocations ); - std::string InstallNameDir(cmTarget* target, const std::string& config); + std::string InstallNameDir(cmGeneratorTarget* target, + const std::string& config); cmInstallExportGenerator* IEGen; diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx index cb150a7..fde8fb1 100644 --- a/Source/cmExportLibraryDependenciesCommand.cxx +++ b/Source/cmExportLibraryDependenciesCommand.cxx @@ -11,7 +11,6 @@ ============================================================================*/ #include "cmExportLibraryDependenciesCommand.h" #include "cmGlobalGenerator.h" -#include "cmLocalGenerator.h" #include "cmGeneratedFileStream.h" #include "cmake.h" #include "cmVersion.h" @@ -82,15 +81,14 @@ void cmExportLibraryDependenciesCommand::ConstFinalPass() const // the project. cmake* cm = this->Makefile->GetCMakeInstance(); cmGlobalGenerator* global = cm->GetGlobalGenerator(); - const std::vector<cmLocalGenerator *>& locals = global->GetLocalGenerators(); + const std::vector<cmMakefile*>& locals = global->GetMakefiles(); std::map<std::string, std::string> libDepsOld; std::map<std::string, std::string> libDepsNew; std::map<std::string, std::string> libTypes; - for(std::vector<cmLocalGenerator *>::const_iterator i = locals.begin(); + for(std::vector<cmMakefile*>::const_iterator i = locals.begin(); i != locals.end(); ++i) { - const cmLocalGenerator* gen = *i; - const cmTargets &tgts = gen->GetMakefile()->GetTargets(); + const cmTargets &tgts = (*i)->GetTargets(); for(cmTargets::const_iterator l = tgts.begin(); l != tgts.end(); ++l) { diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index 94831f8..ba66531 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -125,12 +125,12 @@ cmExportTryCompileFileGenerator::PopulateProperties(cmTarget const* target, } std::string -cmExportTryCompileFileGenerator::InstallNameDir(cmTarget* target, +cmExportTryCompileFileGenerator::InstallNameDir(cmGeneratorTarget* target, const std::string& config) { std::string install_name_dir; - cmMakefile* mf = target->GetMakefile(); + cmMakefile* mf = target->Target->GetMakefile(); if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { install_name_dir = diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h index 0d84896..8838eca 100644 --- a/Source/cmExportTryCompileFileGenerator.h +++ b/Source/cmExportTryCompileFileGenerator.h @@ -9,8 +9,8 @@ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more information. ============================================================================*/ -#ifndef cmExportInstallFileGenerator_h -#define cmExportInstallFileGenerator_h +#ifndef cmExportTryCompileFileGenerator_h +#define cmExportTryCompileFileGenerator_h #include "cmExportFileGenerator.h" @@ -45,7 +45,7 @@ protected: ImportPropertyMap& properties, std::set<cmTarget const*> &emitted); - std::string InstallNameDir(cmTarget* target, + std::string InstallNameDir(cmGeneratorTarget* target, const std::string& config); private: std::string FindTargets(const std::string& prop, cmTarget const* tgt, diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 0daed66..87faf84 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -3573,11 +3573,8 @@ void cmFileCommand::AddEvaluationFile(const std::string &inputName, cmsys::auto_ptr<cmCompiledGeneratorExpression> conditionCge = conditionGe.Parse(condition); - this->Makefile->GetGlobalGenerator()->AddEvaluationFile(inputName, - outputCge, - this->Makefile, - conditionCge, - inputIsContent); + this->Makefile->AddEvaluationFile(inputName, outputCge, + conditionCge, inputIsContent); } //---------------------------------------------------------------------------- diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx index 92ff314..e4d9f10 100644 --- a/Source/cmGeneratorExpressionEvaluationFile.cxx +++ b/Source/cmGeneratorExpressionEvaluationFile.cxx @@ -25,19 +25,18 @@ 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 std::string& config, +void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg, + const std::string& config, const std::string& lang, cmCompiledGeneratorExpression* inputExpression, std::map<std::string, std::string> &outputFiles, mode_t perm) @@ -45,7 +44,8 @@ void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config, std::string rawCondition = this->Condition->GetInput(); if (!rawCondition.empty()) { - std::string condResult = this->Condition->Evaluate(this->Makefile, config, + std::string condResult = this->Condition->Evaluate(lg->GetMakefile(), + config, false, 0, 0, 0, lang); if (condResult == "0") { @@ -56,16 +56,17 @@ void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config, std::ostringstream e; e << "Evaluation file condition \"" << rawCondition << "\" did " "not evaluate to valid content. Got \"" << condResult << "\"."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + lg->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } } const std::string outputFileName - = this->OutputFileExpr->Evaluate(this->Makefile, config, + = this->OutputFileExpr->Evaluate(lg->GetMakefile(), config, false, 0, 0, 0, lang); const std::string outputContent - = inputExpression->Evaluate(this->Makefile, config, + = inputExpression->Evaluate(lg->GetMakefile(), + config, false, 0, 0, 0, lang); std::map<std::string, std::string>::iterator it @@ -81,11 +82,11 @@ void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config, e << "Evaluation file to be written multiple times for different " "configurations or languages with different content:\n " << outputFileName; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + lg->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } - this->Makefile->AddCMakeOutputFile(outputFileName.c_str()); + lg->GetMakefile()->AddCMakeOutputFile(outputFileName.c_str()); this->Files.push_back(outputFileName); outputFiles[outputFileName] = outputContent; @@ -100,18 +101,19 @@ void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config, //---------------------------------------------------------------------------- void cmGeneratorExpressionEvaluationFile::CreateOutputFile( - std::string const& config) + cmLocalGenerator *lg, std::string const& config) { std::vector<std::string> enabledLanguages; - cmGlobalGenerator *gg = this->Makefile->GetGlobalGenerator(); + cmGlobalGenerator *gg = lg->GetGlobalGenerator(); gg->GetEnabledLanguages(enabledLanguages); for(std::vector<std::string>::const_iterator le = enabledLanguages.begin(); le != enabledLanguages.end(); ++le) { - std::string name = this->OutputFileExpr->Evaluate(this->Makefile, config, + std::string name = this->OutputFileExpr->Evaluate(lg->GetMakefile(), + config, false, 0, 0, 0, *le); - cmSourceFile* sf = this->Makefile->GetOrCreateSource(name); + cmSourceFile* sf = lg->GetMakefile()->GetOrCreateSource(name); sf->SetProperty("GENERATED", "1"); gg->SetFilenameTargetDepends(sf, @@ -120,7 +122,7 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile( } //---------------------------------------------------------------------------- -void cmGeneratorExpressionEvaluationFile::Generate() +void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator *lg) { mode_t perm = 0; std::string inputContent; @@ -130,14 +132,14 @@ void cmGeneratorExpressionEvaluationFile::Generate() } else { - this->Makefile->AddCMakeDependFile(this->Input.c_str()); + lg->GetMakefile()->AddCMakeDependFile(this->Input.c_str()); cmSystemTools::GetPermissions(this->Input.c_str(), perm); cmsys::ifstream fin(this->Input.c_str()); if(!fin) { std::ostringstream e; e << "Evaluation file \"" << this->Input << "\" cannot be read."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + lg->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } @@ -159,7 +161,7 @@ void cmGeneratorExpressionEvaluationFile::Generate() std::map<std::string, std::string> outputFiles; std::vector<std::string> allConfigs; - this->Makefile->GetConfigurations(allConfigs); + lg->GetMakefile()->GetConfigurations(allConfigs); if (allConfigs.empty()) { @@ -167,7 +169,7 @@ void cmGeneratorExpressionEvaluationFile::Generate() } std::vector<std::string> enabledLanguages; - cmGlobalGenerator *gg = this->Makefile->GetGlobalGenerator(); + cmGlobalGenerator *gg = lg->GetGlobalGenerator(); gg->GetEnabledLanguages(enabledLanguages); for(std::vector<std::string>::const_iterator le = enabledLanguages.begin(); @@ -176,7 +178,7 @@ void cmGeneratorExpressionEvaluationFile::Generate() for(std::vector<std::string>::const_iterator li = allConfigs.begin(); li != allConfigs.end(); ++li) { - this->Generate(*li, *le, inputExpression.get(), outputFiles, perm); + this->Generate(lg, *li, *le, inputExpression.get(), outputFiles, perm); if(cmSystemTools::GetFatalErrorOccured()) { return; diff --git a/Source/cmGeneratorExpressionEvaluationFile.h b/Source/cmGeneratorExpressionEvaluationFile.h index 5d8b54c..ad41274 100644 --- a/Source/cmGeneratorExpressionEvaluationFile.h +++ b/Source/cmGeneratorExpressionEvaluationFile.h @@ -18,31 +18,32 @@ #include "cmGeneratorExpression.h" +class cmLocalGenerator; + //---------------------------------------------------------------------------- class cmGeneratorExpressionEvaluationFile { public: cmGeneratorExpressionEvaluationFile(const std::string &input, cmsys::auto_ptr<cmCompiledGeneratorExpression> outputFileExpr, - cmMakefile *makefile, cmsys::auto_ptr<cmCompiledGeneratorExpression> condition, bool inputIsContent); - void Generate(); + void Generate(cmLocalGenerator* lg); std::vector<std::string> GetFiles() const { return this->Files; } - void CreateOutputFile(std::string const& config); + void CreateOutputFile(cmLocalGenerator* lg, std::string const& config); private: - void Generate(const std::string& config, const std::string& lang, - cmCompiledGeneratorExpression* inputExpression, - std::map<std::string, std::string> &outputFiles, mode_t perm); + void Generate(cmLocalGenerator* lg, const std::string& config, + const std::string& lang, + cmCompiledGeneratorExpression* inputExpression, + std::map<std::string, std::string> &outputFiles, mode_t perm); 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; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 3daa7b8..03bc83a 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -990,6 +990,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode assert(target); + cmGeneratorTarget* gtgt = + context->Makefile->GetGlobalGenerator()->GetGeneratorTarget(target); + if (propertyName == "LINKER_LANGUAGE") { if (target->LinkLanguagePropagatesToDependents() && @@ -1001,7 +1004,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode "link libraries for a static library"); return std::string(); } - return target->GetLinkerLanguage(context->Config); + return gtgt->GetLinkerLanguage(context->Config); } cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, @@ -1117,7 +1120,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } else if(!interfacePropertyName.empty()) { - if(cmTarget::LinkImplementationLibraries const* impl = + if(cmLinkImplementationLibraries const* impl = target->GetLinkImplementationLibraries(context->Config)) { linkedTargetsContent = @@ -1135,40 +1138,40 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode { return linkedTargetsContent; } - if (target->IsLinkInterfaceDependentBoolProperty(propertyName, - context->Config)) + if (gtgt->IsLinkInterfaceDependentBoolProperty(propertyName, + context->Config)) { context->HadContextSensitiveCondition = true; - return target->GetLinkInterfaceDependentBoolProperty( + return gtgt->GetLinkInterfaceDependentBoolProperty( propertyName, context->Config) ? "1" : "0"; } - if (target->IsLinkInterfaceDependentStringProperty(propertyName, - context->Config)) + if (gtgt->IsLinkInterfaceDependentStringProperty(propertyName, + context->Config)) { context->HadContextSensitiveCondition = true; const char *propContent = - target->GetLinkInterfaceDependentStringProperty( + gtgt->GetLinkInterfaceDependentStringProperty( propertyName, context->Config); return propContent ? propContent : ""; } - if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName, - context->Config)) + if (gtgt->IsLinkInterfaceDependentNumberMinProperty(propertyName, + context->Config)) { context->HadContextSensitiveCondition = true; const char *propContent = - target->GetLinkInterfaceDependentNumberMinProperty( + gtgt->GetLinkInterfaceDependentNumberMinProperty( propertyName, context->Config); return propContent ? propContent : ""; } - if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName, - context->Config)) + if (gtgt->IsLinkInterfaceDependentNumberMaxProperty(propertyName, + context->Config)) { context->HadContextSensitiveCondition = true; const char *propContent = - target->GetLinkInterfaceDependentNumberMaxProperty( + gtgt->GetLinkInterfaceDependentNumberMaxProperty( propertyName, context->Config); return propContent ? propContent : ""; @@ -1180,22 +1183,22 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode if (!target->IsImported() && dagCheckerParent && !dagCheckerParent->EvaluatingLinkLibraries()) { - if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName, - context->Config)) + if (gtgt->IsLinkInterfaceDependentNumberMinProperty(propertyName, + context->Config)) { context->HadContextSensitiveCondition = true; const char *propContent = - target->GetLinkInterfaceDependentNumberMinProperty( + gtgt->GetLinkInterfaceDependentNumberMinProperty( propertyName, context->Config); return propContent ? propContent : ""; } - if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName, - context->Config)) + if (gtgt->IsLinkInterfaceDependentNumberMaxProperty(propertyName, + context->Config)) { context->HadContextSensitiveCondition = true; const char *propContent = - target->GetLinkInterfaceDependentNumberMaxProperty( + gtgt->GetLinkInterfaceDependentNumberMaxProperty( propertyName, context->Config); return propContent ? propContent : ""; @@ -1369,8 +1372,6 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries(); - std::string result; - for (LangMap::const_iterator lit = testedFeatures.begin(); lit != testedFeatures.end(); ++lit) { @@ -1586,7 +1587,7 @@ struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag> } std::string result = target->Target->GetDirectory(context->Config); result += "/"; - result += target->Target->GetSOName(context->Config); + result += target->GetSOName(context->Config); return result; } }; @@ -1599,7 +1600,14 @@ struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag> cmGeneratorExpressionContext *context, const GeneratorExpressionContent *content) { - std::string language = target->Target->GetLinkerLanguage(context->Config); + if (target->IsImported()) + { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_PDB_FILE not allowed for IMPORTED targets."); + return std::string(); + } + + std::string language = target->GetLinkerLanguage(context->Config); std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB"; @@ -1624,7 +1632,7 @@ struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag> std::string result = target->Target->GetPDBDirectory(context->Config); result += "/"; - result += target->Target->GetPDBName(context->Config); + result += target->GetPDBName(context->Config); return result; } }; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index edd89e8..299c112 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -24,11 +24,19 @@ #include <queue> +#include <errno.h> #include "assert.h" +#if defined(CMAKE_BUILD_WITH_CMAKE) +#include <cmsys/hash_set.hxx> +#define UNORDERED_SET cmsys::hash_set +#else +#define UNORDERED_SET std::set +#endif + //---------------------------------------------------------------------------- void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib, - cmTarget *target, cmake *cm) + cmGeneratorTarget const* target, cmake *cm) { if(!badObjLib.empty()) { @@ -42,7 +50,7 @@ void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib, e << "but may contain only sources that compile, header files, and " "other files that would not affect linking of a normal library."; cm->IssueMessage(cmake::FATAL_ERROR, e.str(), - target->GetBacktrace()); + target->Target->GetBacktrace()); } } @@ -125,14 +133,14 @@ struct TagVisitor { DataType& Data; std::vector<cmSourceFile*> BadObjLibFiles; - cmTarget *Target; + cmGeneratorTarget const* Target; cmGlobalGenerator *GlobalGenerator; cmsys::RegularExpression Header; bool IsObjLib; - TagVisitor(cmTarget *target, DataType& data) + TagVisitor(cmGeneratorTarget const* target, DataType& data) : Data(data), Target(target), - GlobalGenerator(target->GetMakefile()->GetGlobalGenerator()), + GlobalGenerator(target->GetLocalGenerator()->GetGlobalGenerator()), Header(CM_HEADER_REGEX), IsObjLib(target->GetType() == cmTarget::OBJECT_LIBRARY) { @@ -226,7 +234,13 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) { this->Makefile = this->Target->GetMakefile(); this->LocalGenerator = lg; - this->GlobalGenerator = this->Makefile->GetGlobalGenerator(); + this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator(); +} + +cmGeneratorTarget::~cmGeneratorTarget() +{ + cmDeleteAll(this->LinkInformation); + this->LinkInformation.clear(); } cmLocalGenerator* cmGeneratorTarget::GetLocalGenerator() const @@ -253,6 +267,54 @@ const char *cmGeneratorTarget::GetProperty(const std::string& prop) const } //---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetOutputName(const std::string& config, + bool implib) const +{ + std::vector<std::string> props; + std::string type = this->Target->GetOutputTargetType(implib); + std::string configUpper = cmSystemTools::UpperCase(config); + if(!type.empty() && !configUpper.empty()) + { + // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG> + props.push_back(type + "_OUTPUT_NAME_" + configUpper); + } + if(!type.empty()) + { + // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME + props.push_back(type + "_OUTPUT_NAME"); + } + if(!configUpper.empty()) + { + // OUTPUT_NAME_<CONFIG> + props.push_back("OUTPUT_NAME_" + configUpper); + // <CONFIG>_OUTPUT_NAME + props.push_back(configUpper + "_OUTPUT_NAME"); + } + // OUTPUT_NAME + props.push_back("OUTPUT_NAME"); + + std::string outName; + for(std::vector<std::string>::const_iterator i = props.begin(); + i != props.end(); ++i) + { + if (const char* outNameProp = this->Target->GetProperty(*i)) + { + outName = outNameProp; + break; + } + } + + if (outName.empty()) + { + outName = this->GetName(); + } + + cmGeneratorExpression ge; + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName); + return cge->Evaluate(this->Makefile, config); +} + +//---------------------------------------------------------------------------- std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(cmSourceFile const* sf) const { @@ -300,7 +362,7 @@ static void handleSystemIncludesDep(cmMakefile *mf, cmTarget const* depTgt, { \ std::vector<cmSourceFile*> sourceFiles; \ this->Target->GetSourceFiles(sourceFiles, config); \ - TagVisitor<DATA ## Tag DATATYPE> visitor(this->Target, data); \ + TagVisitor<DATA ## Tag DATATYPE> visitor(this, data); \ for(std::vector<cmSourceFile*>::const_iterator si = sourceFiles.begin(); \ si != sourceFiles.end(); ++si) \ { \ @@ -560,7 +622,7 @@ const char* cmGeneratorTarget::GetLocationForBuild() const if(this->Target->IsAppBundleOnApple()) { - std::string macdir = this->Target->BuildMacContentDirectory("", "", + std::string macdir = this->BuildMacContentDirectory("", "", false); if(!macdir.empty()) { @@ -569,7 +631,7 @@ const char* cmGeneratorTarget::GetLocationForBuild() const } } location += "/"; - location += this->Target->GetFullName("", false); + location += this->GetFullName("", false); return location.c_str(); } @@ -611,7 +673,7 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(const std::string& dir, } std::vector<cmTarget const*> const& deps = - this->Target->GetLinkImplementationClosure(config); + this->GetLinkImplementationClosure(config); for(std::vector<cmTarget const*>::const_iterator li = deps.begin(), le = deps.end(); li != le; ++li) { @@ -651,6 +713,692 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*> &files, //---------------------------------------------------------------------------- std::string +cmGeneratorTarget::GetCompilePDBName(const std::string& config) const +{ + std::string prefix; + std::string base; + std::string suffix; + this->GetFullNameInternal(config, false, prefix, base, suffix); + + // Check for a per-configuration output directory target property. + std::string configUpper = cmSystemTools::UpperCase(config); + std::string configProp = "COMPILE_PDB_NAME_"; + configProp += configUpper; + const char* config_name = this->Target->GetProperty(configProp); + if(config_name && *config_name) + { + return prefix + config_name + ".pdb"; + } + + const char* name = this->Target->GetProperty("COMPILE_PDB_NAME"); + if(name && *name) + { + return prefix + name + ".pdb"; + } + + return ""; +} + +//---------------------------------------------------------------------------- +std::string +cmGeneratorTarget::GetCompilePDBPath(const std::string& config) const +{ + std::string dir = this->GetCompilePDBDirectory(config); + std::string name = this->GetCompilePDBName(config); + if(dir.empty() && !name.empty()) + { + dir = this->Target->GetPDBDirectory(config); + } + if(!dir.empty()) + { + dir += "/"; + } + return dir + name; +} + +//---------------------------------------------------------------------------- +bool cmGeneratorTarget::HasSOName(const std::string& config) const +{ + // soname is supported only for shared libraries and modules, + // and then only when the platform supports an soname flag. + return ((this->GetType() == cmTarget::SHARED_LIBRARY || + this->GetType() == cmTarget::MODULE_LIBRARY) && + !this->GetPropertyAsBool("NO_SONAME") && + this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config))); +} + +//---------------------------------------------------------------------------- +bool +cmGeneratorTarget::NeedRelinkBeforeInstall(const std::string& config) const +{ + // Only executables and shared libraries can have an rpath and may + // need relinking. + if(this->GetType() != cmTarget::EXECUTABLE && + this->GetType() != cmTarget::SHARED_LIBRARY && + this->GetType() != cmTarget::MODULE_LIBRARY) + { + return false; + } + + // If there is no install location this target will not be installed + // and therefore does not need relinking. + if(!this->Target->GetHaveInstallRule()) + { + return false; + } + + // If skipping all rpaths completely then no relinking is needed. + if(this->Makefile->IsOn("CMAKE_SKIP_RPATH")) + { + return false; + } + + // If building with the install-tree rpath no relinking is needed. + if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) + { + return false; + } + + // If chrpath is going to be used no relinking is needed. + if(this->IsChrpathUsed(config)) + { + return false; + } + + // Check for rpath support on this platform. + std::string ll = this->GetLinkerLanguage(config); + if(!ll.empty()) + { + std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; + flagVar += ll; + flagVar += "_FLAG"; + if(!this->Makefile->IsSet(flagVar)) + { + // There is no rpath support on this platform so nothing needs + // relinking. + return false; + } + } + else + { + // No linker language is known. This error will be reported by + // other code. + return false; + } + + // If either a build or install tree rpath is set then the rpath + // will likely change between the build tree and install tree and + // this target must be relinked. + return this->Target->HaveBuildTreeRPATH(config) + || this->Target->HaveInstallTreeRPATH(); +} + +//---------------------------------------------------------------------------- +bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const +{ + // Only certain target types have an rpath. + if(!(this->GetType() == cmTarget::SHARED_LIBRARY || + this->GetType() == cmTarget::MODULE_LIBRARY || + this->GetType() == cmTarget::EXECUTABLE)) + { + return false; + } + + // If the target will not be installed we do not need to change its + // rpath. + if(!this->Target->GetHaveInstallRule()) + { + return false; + } + + // Skip chrpath if skipping rpath altogether. + if(this->Makefile->IsOn("CMAKE_SKIP_RPATH")) + { + return false; + } + + // Skip chrpath if it does not need to be changed at install time. + if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) + { + return false; + } + + // Allow the user to disable builtin chrpath explicitly. + if(this->Makefile->IsOn("CMAKE_NO_BUILTIN_CHRPATH")) + { + 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. + std::string ll = this->GetLinkerLanguage(config); + if(!ll.empty()) + { + std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; + sepVar += ll; + sepVar += "_FLAG_SEP"; + const char* sep = this->Makefile->GetDefinition(sepVar); + if(sep && *sep) + { + // TODO: Add ELF check to ABI detection and get rid of + // CMAKE_EXECUTABLE_FORMAT. + if(const char* fmt = + this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) + { + return strcmp(fmt, "ELF") == 0; + } + } + } +#endif + static_cast<void>(config); + return false; +} + + +//---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetSOName(const std::string& config) const +{ + if(this->Target->IsImported()) + { + // Lookup the imported soname. + if(cmTarget::ImportInfo const* info = this->Target->GetImportInfo(config)) + { + if(info->NoSOName) + { + // The imported library has no builtin soname so the name + // searched at runtime will be just the filename. + return cmSystemTools::GetFilenameName(info->Location); + } + else + { + // Use the soname given if any. + if(info->SOName.find("@rpath/") == 0) + { + return info->SOName.substr(6); + } + return info->SOName; + } + } + else + { + return ""; + } + } + else + { + // Compute the soname that will be built. + std::string name; + std::string soName; + std::string realName; + std::string impName; + std::string pdbName; + this->GetLibraryNames(name, soName, realName, + impName, pdbName, config); + return soName; + } +} + + +//---------------------------------------------------------------------------- +std::string +cmGeneratorTarget::GetAppBundleDirectory(const std::string& config, + bool contentOnly) const +{ + std::string fpath = this->GetFullName(config, false); + fpath += ".app/Contents"; + if(!contentOnly) + fpath += "/MacOS"; + return fpath; +} + +//---------------------------------------------------------------------------- +bool cmGeneratorTarget::IsBundleOnApple() const +{ + return this->Target->IsFrameworkOnApple() + || this->Target->IsAppBundleOnApple() + || this->Target->IsCFBundleOnApple(); +} + +//---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetCFBundleDirectory(const std::string& config, + bool contentOnly) const +{ + std::string fpath; + fpath += this->GetOutputName(config, false); + fpath += "."; + const char *ext = this->Target->GetProperty("BUNDLE_EXTENSION"); + if (!ext) + { + if (this->Target->IsXCTestOnApple()) + { + ext = "xctest"; + } + else + { + ext = "bundle"; + } + } + fpath += ext; + fpath += "/Contents"; + if(!contentOnly) + fpath += "/MacOS"; + return fpath; +} + +//---------------------------------------------------------------------------- +std::string +cmGeneratorTarget::GetFrameworkDirectory(const std::string& config, + bool rootDir) const +{ + std::string fpath; + fpath += this->GetOutputName(config, false); + fpath += ".framework"; + if(!rootDir) + { + fpath += "/Versions/"; + fpath += this->Target->GetFrameworkVersion(); + } + return fpath; +} + +//---------------------------------------------------------------------------- +std::string +cmGeneratorTarget::GetFullName(const std::string& config, bool implib) const +{ + if(this->Target->IsImported()) + { + return this->Target->GetFullNameImported(config, implib); + } + else + { + return this->GetFullNameInternal(config, implib); + } +} + +//---------------------------------------------------------------------------- +std::string +cmGeneratorTarget::GetInstallNameDirForBuildTree( + const std::string& config) const +{ + // 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 this->GetInstallNameDirForInstallTree(); + } + + // Use the build tree directory for the target. + if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME") && + !this->Makefile->IsOn("CMAKE_SKIP_RPATH") && + !this->GetPropertyAsBool("SKIP_BUILD_RPATH")) + { + std::string dir; + if(this->Target->MacOSXRpathInstallNameDirDefault()) + { + dir = "@rpath"; + } + else + { + dir = this->Target->GetDirectory(config); + } + dir += "/"; + return dir; + } + else + { + return ""; + } +} + +//---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetInstallNameDirForInstallTree() const +{ + 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")) + { + if(install_name_dir && *install_name_dir) + { + dir = install_name_dir; + dir += "/"; + } + } + if(!install_name_dir) + { + if(this->Target->MacOSXRpathInstallNameDirDefault()) + { + dir = "@rpath/"; + } + } + return dir; + } + else + { + return ""; + } +} + +//---------------------------------------------------------------------------- +class cmTargetCollectLinkLanguages +{ +public: + cmTargetCollectLinkLanguages(cmGeneratorTarget const* target, + const std::string& config, + UNORDERED_SET<std::string>& languages, + cmTarget const* head): + Config(config), Languages(languages), HeadTarget(head), + Makefile(target->Target->GetMakefile()), Target(target) + { this->Visited.insert(target->Target); } + + void Visit(cmLinkItem const& item) + { + if(!item.Target) + { + if(item.find("::") != std::string::npos) + { + bool noMessage = false; + cmake::MessageType messageType = cmake::FATAL_ERROR; + std::stringstream e; + switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0028)) + { + case cmPolicies::WARN: + { + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\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; + } + + if(!noMessage) + { + e << "Target \"" << this->Target->GetName() + << "\" links to target \"" << item + << "\" but the target was not found. Perhaps a find_package() " + "call is missing for an IMPORTED target, or an ALIAS target is " + "missing?"; + this->Makefile->GetCMakeInstance()->IssueMessage( + messageType, e.str(), this->Target->Target->GetBacktrace()); + } + } + return; + } + if(!this->Visited.insert(item.Target).second) + { + return; + } + + cmTarget::LinkInterface const* iface = + item.Target->GetLinkInterface(this->Config, this->HeadTarget); + if(!iface) { return; } + + for(std::vector<std::string>::const_iterator + li = iface->Languages.begin(); li != iface->Languages.end(); ++li) + { + this->Languages.insert(*li); + } + + for(std::vector<cmLinkItem>::const_iterator + li = iface->Libraries.begin(); li != iface->Libraries.end(); ++li) + { + this->Visit(*li); + } + } +private: + std::string Config; + UNORDERED_SET<std::string>& Languages; + cmTarget const* HeadTarget; + cmMakefile* Makefile; + const cmGeneratorTarget* Target; + std::set<cmTarget const*> Visited; +}; + +//---------------------------------------------------------------------------- +cmGeneratorTarget::LinkClosure const* +cmGeneratorTarget::GetLinkClosure(const std::string& config) const +{ + std::string key(cmSystemTools::UpperCase(config)); + LinkClosureMapType::iterator + i = this->LinkClosureMap.find(key); + if(i == this->LinkClosureMap.end()) + { + LinkClosure lc; + this->ComputeLinkClosure(config, lc); + LinkClosureMapType::value_type entry(key, lc); + i = this->LinkClosureMap.insert(entry).first; + } + return &i->second; +} + +//---------------------------------------------------------------------------- +class cmTargetSelectLinker +{ + int Preference; + cmGeneratorTarget const* Target; + cmMakefile* Makefile; + cmGlobalGenerator* GG; + std::set<std::string> Preferred; +public: + cmTargetSelectLinker(cmGeneratorTarget const* target) + : Preference(0), Target(target) + { + this->Makefile = this->Target->Makefile; + this->GG = this->Makefile->GetGlobalGenerator(); + } + void Consider(const char* lang) + { + int preference = this->GG->GetLinkerPreference(lang); + if(preference > this->Preference) + { + this->Preference = preference; + this->Preferred.clear(); + } + if(preference == this->Preference) + { + this->Preferred.insert(lang); + } + } + std::string Choose() + { + if(this->Preferred.empty()) + { + return ""; + } + else if(this->Preferred.size() > 1) + { + std::stringstream e; + e << "Target " << this->Target->GetName() + << " contains multiple languages with the highest linker preference" + << " (" << this->Preference << "):\n"; + for(std::set<std::string>::const_iterator + li = this->Preferred.begin(); li != this->Preferred.end(); ++li) + { + e << " " << *li << "\n"; + } + e << "Set the LINKER_LANGUAGE property for this target."; + cmake* cm = this->Makefile->GetCMakeInstance(); + cm->IssueMessage(cmake::FATAL_ERROR, e.str(), + this->Target->Target->GetBacktrace()); + } + return *this->Preferred.begin(); + } +}; + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::ComputeLinkClosure(const std::string& config, + LinkClosure& lc) const +{ + // Get languages built in this target. + UNORDERED_SET<std::string> languages; + cmTarget::LinkImplementation const* impl = + this->Target->GetLinkImplementation(config); + assert(impl); + for(std::vector<std::string>::const_iterator li = impl->Languages.begin(); + li != impl->Languages.end(); ++li) + { + languages.insert(*li); + } + + // Add interface languages from linked targets. + cmTargetCollectLinkLanguages cll(this, config, languages, this->Target); + for(std::vector<cmLinkImplItem>::const_iterator li = impl->Libraries.begin(); + li != impl->Libraries.end(); ++li) + { + cll.Visit(*li); + } + + // Store the transitive closure of languages. + for(UNORDERED_SET<std::string>::const_iterator li = languages.begin(); + li != languages.end(); ++li) + { + lc.Languages.push_back(*li); + } + + // Choose the language whose linker should be used. + if(this->GetProperty("HAS_CXX")) + { + lc.LinkerLanguage = "CXX"; + } + else if(const char* linkerLang = this->GetProperty("LINKER_LANGUAGE")) + { + lc.LinkerLanguage = linkerLang; + } + else + { + // Find the language with the highest preference value. + cmTargetSelectLinker tsl(this); + + // First select from the languages compiled directly in this target. + for(std::vector<std::string>::const_iterator li = impl->Languages.begin(); + li != impl->Languages.end(); ++li) + { + tsl.Consider(li->c_str()); + } + + // Now consider languages that propagate from linked targets. + for(UNORDERED_SET<std::string>::const_iterator sit = languages.begin(); + sit != languages.end(); ++sit) + { + std::string propagates = "CMAKE_"+*sit+"_LINKER_PREFERENCE_PROPAGATES"; + if(this->Makefile->IsOn(propagates)) + { + tsl.Consider(sit->c_str()); + } + } + + lc.LinkerLanguage = tsl.Choose(); + } +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::GetFullNameComponents(std::string& prefix, + std::string& base, + std::string& suffix, + const std::string& config, + bool implib) const +{ + this->GetFullNameInternal(config, implib, prefix, base, suffix); +} + +//---------------------------------------------------------------------------- +std::string +cmGeneratorTarget::BuildMacContentDirectory(const std::string& base, + const std::string& config, + bool contentOnly) const +{ + std::string fpath = base; + if(this->Target->IsAppBundleOnApple()) + { + fpath += this->GetAppBundleDirectory(config, contentOnly); + } + if(this->Target->IsFrameworkOnApple()) + { + fpath += this->GetFrameworkDirectory(config, contentOnly); + } + if(this->Target->IsCFBundleOnApple()) + { + fpath += this->GetCFBundleDirectory(config, contentOnly); + } + return fpath; +} + +//---------------------------------------------------------------------------- +std::string +cmGeneratorTarget::GetMacContentDirectory(const std::string& config, + bool implib) const +{ + // Start with the output directory for the target. + std::string fpath = this->Target->GetDirectory(config, implib); + fpath += "/"; + bool contentOnly = true; + if(this->Target->IsFrameworkOnApple()) + { + // additional files with a framework go into the version specific + // directory + contentOnly = false; + } + fpath = this->BuildMacContentDirectory(fpath, config, contentOnly); + return fpath; +} + + +//---------------------------------------------------------------------------- +cmGeneratorTarget::CompileInfo const* cmGeneratorTarget::GetCompileInfo( + const std::string& config) const +{ + // There is no compile information for imported targets. + if(this->IsImported()) + { + return 0; + } + + if(this->GetType() > cmTarget::OBJECT_LIBRARY) + { + std::string msg = "cmTarget::GetCompileInfo called for "; + msg += this->GetName(); + msg += " which has type "; + msg += cmTarget::GetTargetTypeName(this->Target->GetType()); + this->Makefile->IssueMessage(cmake::INTERNAL_ERROR, msg); + return 0; + } + + // Lookup/compute/cache the compile information for this configuration. + std::string config_upper; + if(!config.empty()) + { + config_upper = cmSystemTools::UpperCase(config); + } + CompileInfoMapType::const_iterator i = + this->CompileInfoMap.find(config_upper); + if(i == this->CompileInfoMap.end()) + { + CompileInfo info; + this->Target + ->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir); + CompileInfoMapType::value_type entry(config_upper, info); + i = this->CompileInfoMap.insert(entry).first; + } + return &i->second; +} + +//---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetModuleDefinitionFile(const std::string& config) const { std::string data; @@ -700,6 +1448,79 @@ cmGeneratorTarget::UseObjectLibraries(std::vector<std::string>& objs, } //---------------------------------------------------------------------------- +void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string> &result, + const std::string& config) const +{ + const char *prop + = this->GetLinkInterfaceDependentStringProperty("AUTOUIC_OPTIONS", + config); + if (!prop) + { + return; + } + cmGeneratorExpression ge; + + cmGeneratorExpressionDAGChecker dagChecker( + this->GetName(), + "AUTOUIC_OPTIONS", 0, 0); + cmSystemTools::ExpandListArgument(ge.Parse(prop) + ->Evaluate(this->Makefile, + config, + false, + this->Target, + &dagChecker), + result); +} + +//---------------------------------------------------------------------------- +void processILibs(const std::string& config, + cmTarget const* headTarget, + cmLinkItem const& item, + std::vector<cmTarget const*>& tgts, + std::set<cmTarget const*>& emitted) +{ + if (item.Target && emitted.insert(item.Target).second) + { + tgts.push_back(item.Target); + if(cmTarget::LinkInterfaceLibraries const* iface = + item.Target->GetLinkInterfaceLibraries(config, headTarget, true)) + { + for(std::vector<cmLinkItem>::const_iterator + it = iface->Libraries.begin(); + it != iface->Libraries.end(); ++it) + { + processILibs(config, headTarget, *it, tgts, emitted); + } + } + } +} + +//---------------------------------------------------------------------------- +const std::vector<const cmTarget*>& +cmGeneratorTarget::GetLinkImplementationClosure( + const std::string& config) const +{ + LinkImplClosure& tgts = + this->LinkImplClosureMap[config]; + if(!tgts.Done) + { + tgts.Done = true; + std::set<cmTarget const*> emitted; + + cmLinkImplementationLibraries const* impl + = this->Target->GetLinkImplementationLibraries(config); + + for(std::vector<cmLinkImplItem>::const_iterator + it = impl->Libraries.begin(); + it != impl->Libraries.end(); ++it) + { + processILibs(config, this->Target, *it, tgts , emitted); + } + } + return tgts; +} + +//---------------------------------------------------------------------------- class cmTargetTraceDependencies { public: @@ -736,7 +1557,7 @@ cmTargetTraceDependencies { // Convenience. this->Makefile = this->Target->GetMakefile(); - this->GlobalGenerator = this->Makefile->GetGlobalGenerator(); + this->GlobalGenerator = target->GetLocalGenerator()->GetGlobalGenerator(); this->CurrentEntry = 0; // Queue all the source files already specified for the target. @@ -1044,6 +1865,16 @@ void cmGeneratorTarget::TraceDependencies() tracer.Trace(); } +std::string +cmGeneratorTarget::GetCompilePDBDirectory(const std::string& config) const +{ + if(CompileInfo const* info = this->GetCompileInfo(config)) + { + return info->CompilePdbDir; + } + return ""; +} + //---------------------------------------------------------------------------- void cmGeneratorTarget::GetAppleArchs(const std::string& config, std::vector<std::string>& archVec) const @@ -1114,8 +1945,7 @@ void cmGeneratorTarget::GenerateTargetManifest( { return; } - cmMakefile* mf = this->Target->GetMakefile(); - cmGlobalGenerator* gg = mf->GetGlobalGenerator(); + cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator(); // Get the names. std::string name; @@ -1125,14 +1955,13 @@ void cmGeneratorTarget::GenerateTargetManifest( std::string pdbName; if(this->GetType() == cmTarget::EXECUTABLE) { - this->Target->GetExecutableNames(name, realName, impName, pdbName, - config); + this->GetExecutableNames(name, realName, impName, pdbName, config); } else if(this->GetType() == cmTarget::STATIC_LIBRARY || this->GetType() == cmTarget::SHARED_LIBRARY || this->GetType() == cmTarget::MODULE_LIBRARY) { - this->Target->GetLibraryNames(name, soName, realName, impName, pdbName, + this->GetLibraryNames(name, soName, realName, impName, pdbName, config); } else @@ -1150,35 +1979,35 @@ void cmGeneratorTarget::GenerateTargetManifest( f = dir; f += "/"; f += name; - gg->AddToManifest(config, f); + gg->AddToManifest(f); } if(!soName.empty()) { f = dir; f += "/"; f += soName; - gg->AddToManifest(config, f); + gg->AddToManifest(f); } if(!realName.empty()) { f = dir; f += "/"; f += realName; - gg->AddToManifest(config, f); + gg->AddToManifest(f); } if(!pdbName.empty()) { f = dir; f += "/"; f += pdbName; - gg->AddToManifest(config, f); + gg->AddToManifest(f); } if(!impName.empty()) { f = this->Target->GetDirectory(config, true); f += "/"; f += impName; - gg->AddToManifest(config, f); + gg->AddToManifest(f); } } @@ -1204,14 +2033,14 @@ std::string cmGeneratorTarget::NormalGetFullPath(const std::string& config, fpath += "/"; if(this->Target->IsAppBundleOnApple()) { - fpath = this->Target->BuildMacContentDirectory(fpath, config, false); + fpath = this->BuildMacContentDirectory(fpath, config, false); fpath += "/"; } // Add the full name of the target. if(implib) { - fpath += this->Target->GetFullName(config, true); + fpath += this->GetFullName(config, true); } else if(realname) { @@ -1219,7 +2048,7 @@ std::string cmGeneratorTarget::NormalGetFullPath(const std::string& config, } else { - fpath += this->Target->GetFullName(config, false); + fpath += this->GetFullName(config, false); } return fpath; } @@ -1245,7 +2074,7 @@ cmGeneratorTarget::NormalGetRealName(const std::string& config) const std::string realName; std::string impName; std::string pdbName; - this->Target->GetExecutableNames(name, realName, impName, pdbName, config); + this->GetExecutableNames(name, realName, impName, pdbName, config); return realName; } else @@ -1256,12 +2085,344 @@ cmGeneratorTarget::NormalGetRealName(const std::string& config) const std::string realName; std::string impName; std::string pdbName; - this->Target->GetLibraryNames(name, soName, realName, - impName, pdbName, config); + this->GetLibraryNames(name, soName, realName, + impName, pdbName, config); return realName; } } +//---------------------------------------------------------------------------- +void cmGeneratorTarget::GetLibraryNames(std::string& name, + std::string& soName, + std::string& realName, + std::string& impName, + std::string& pdbName, + const std::string& config) const +{ + // This should not be called for imported targets. + // TODO: Split cmTarget into a class hierarchy to get compile-time + // enforcement of the limited imported target API. + if(this->Target->IsImported()) + { + std::string msg = "GetLibraryNames called on imported target: "; + msg += this->GetName(); + this->LocalGenerator->IssueMessage(cmake::INTERNAL_ERROR, + msg); + return; + } + + // Check for library version properties. + const char* version = this->GetProperty("VERSION"); + const char* soversion = this->GetProperty("SOVERSION"); + if(!this->HasSOName(config) || + this->Target->IsFrameworkOnApple()) + { + // Versioning is supported only for shared libraries and modules, + // and then only when the platform supports an soname flag. + version = 0; + soversion = 0; + } + if(version && !soversion) + { + // The soversion must be set if the library version is set. Use + // the library version as the soversion. + soversion = version; + } + if(!version && soversion) + { + // Use the soversion as the library version. + version = soversion; + } + + // Get the components of the library name. + std::string prefix; + std::string base; + std::string suffix; + this->GetFullNameInternal(config, false, prefix, base, suffix); + + // The library name. + name = prefix+base+suffix; + + if(this->Target->IsFrameworkOnApple()) + { + realName = prefix; + realName += "Versions/"; + realName += this->Target->GetFrameworkVersion(); + realName += "/"; + realName += base; + soName = realName; + } + else + { + // The library's soname. + this->Target->ComputeVersionedName(soName, prefix, base, suffix, + name, soversion); + + // The library's real name on disk. + this->Target->ComputeVersionedName(realName, prefix, base, suffix, + name, version); + } + + // The import library name. + if(this->GetType() == cmTarget::SHARED_LIBRARY || + this->GetType() == cmTarget::MODULE_LIBRARY) + { + impName = this->GetFullNameInternal(config, true); + } + else + { + impName = ""; + } + + // The program database file name. + pdbName = this->GetPDBName(config); +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::GetExecutableNames(std::string& name, + std::string& realName, + std::string& impName, + std::string& pdbName, + const std::string& config) const +{ + // This should not be called for imported targets. + // TODO: Split cmTarget into a class hierarchy to get compile-time + // enforcement of the limited imported target API. + if(this->Target->IsImported()) + { + std::string msg = + "GetExecutableNames called on imported target: "; + msg += this->GetName(); + this->LocalGenerator->IssueMessage(cmake::INTERNAL_ERROR, msg); + } + + // This versioning is supported only for executables and then only + // when the platform supports symbolic links. +#if defined(_WIN32) && !defined(__CYGWIN__) + const char* version = 0; +#else + // Check for executable version properties. + const char* version = this->GetProperty("VERSION"); + if(this->GetType() != cmTarget::EXECUTABLE || this->Makefile->IsOn("XCODE")) + { + version = 0; + } +#endif + + // Get the components of the executable name. + std::string prefix; + std::string base; + std::string suffix; + this->GetFullNameInternal(config, false, prefix, base, suffix); + + // The executable name. + name = prefix+base+suffix; + + // The executable's real name on disk. +#if defined(__CYGWIN__) + realName = prefix+base; +#else + realName = name; +#endif + if(version) + { + realName += "-"; + realName += version; + } +#if defined(__CYGWIN__) + realName += suffix; +#endif + + // The import library name. + impName = this->GetFullNameInternal(config, true); + + // The program database file name. + pdbName = this->GetPDBName(config); +} + +//---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetFullNameInternal(const std::string& config, + bool implib) const +{ + std::string prefix; + std::string base; + std::string suffix; + this->GetFullNameInternal(config, implib, prefix, base, suffix); + return prefix+base+suffix; +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::GetFullNameInternal(const std::string& config, + bool implib, + std::string& outPrefix, + std::string& outBase, + std::string& outSuffix) const +{ + // Use just the target name for non-main target types. + if(this->GetType() != cmTarget::STATIC_LIBRARY && + this->GetType() != cmTarget::SHARED_LIBRARY && + this->GetType() != cmTarget::MODULE_LIBRARY && + this->GetType() != cmTarget::EXECUTABLE) + { + outPrefix = ""; + outBase = this->GetName(); + outSuffix = ""; + return; + } + + // Return an empty name for the import library if this platform + // does not support import libraries. + if(implib && + !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) + { + outPrefix = ""; + outBase = ""; + outSuffix = ""; + return; + } + + // The implib option is only allowed for shared libraries, module + // libraries, and executables. + if(this->GetType() != cmTarget::SHARED_LIBRARY && + this->GetType() != cmTarget::MODULE_LIBRARY && + this->GetType() != cmTarget::EXECUTABLE) + { + implib = false; + } + + // Compute the full name for main target types. + const char* targetPrefix = (implib + ? this->GetProperty("IMPORT_PREFIX") + : this->GetProperty("PREFIX")); + const char* targetSuffix = (implib + ? this->GetProperty("IMPORT_SUFFIX") + : this->GetProperty("SUFFIX")); + const char* configPostfix = 0; + if(!config.empty()) + { + std::string configProp = cmSystemTools::UpperCase(config); + configProp += "_POSTFIX"; + configPostfix = this->GetProperty(configProp); + // Mac application bundles and frameworks have no postfix. + if(configPostfix && + (this->Target->IsAppBundleOnApple() + || this->Target->IsFrameworkOnApple())) + { + configPostfix = 0; + } + } + const char* prefixVar = this->Target->GetPrefixVariableInternal(implib); + const char* suffixVar = this->Target->GetSuffixVariableInternal(implib); + + // Check for language-specific default prefix and suffix. + std::string ll = this->GetLinkerLanguage(config); + if(!ll.empty()) + { + if(!targetSuffix && suffixVar && *suffixVar) + { + std::string langSuff = suffixVar + std::string("_") + ll; + targetSuffix = this->Makefile->GetDefinition(langSuff); + } + if(!targetPrefix && prefixVar && *prefixVar) + { + std::string langPrefix = prefixVar + std::string("_") + ll; + targetPrefix = this->Makefile->GetDefinition(langPrefix); + } + } + + // if there is no prefix on the target use the cmake definition + if(!targetPrefix && prefixVar) + { + targetPrefix = this->Makefile->GetSafeDefinition(prefixVar); + } + // if there is no suffix on the target use the cmake definition + if(!targetSuffix && suffixVar) + { + targetSuffix = this->Makefile->GetSafeDefinition(suffixVar); + } + + // frameworks have directory prefix but no suffix + std::string fw_prefix; + if(this->Target->IsFrameworkOnApple()) + { + fw_prefix = this->GetOutputName(config, false); + fw_prefix += ".framework/"; + targetPrefix = fw_prefix.c_str(); + targetSuffix = 0; + } + + if(this->Target->IsCFBundleOnApple()) + { + fw_prefix = this->GetCFBundleDirectory(config, false); + fw_prefix += "/"; + targetPrefix = fw_prefix.c_str(); + targetSuffix = 0; + } + + // Begin the final name with the prefix. + outPrefix = targetPrefix?targetPrefix:""; + + // Append the target name or property-specified name. + outBase += this->GetOutputName(config, implib); + + // Append the per-configuration postfix. + outBase += configPostfix?configPostfix:""; + + // Name shared libraries with their version number on some platforms. + if(const char* soversion = this->GetProperty("SOVERSION")) + { + if(this->GetType() == cmTarget::SHARED_LIBRARY && !implib && + this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")) + { + outBase += "-"; + outBase += soversion; + } + } + + // Append the suffix. + outSuffix = targetSuffix?targetSuffix:""; +} + + +//---------------------------------------------------------------------------- +std::string +cmGeneratorTarget::GetLinkerLanguage(const std::string& config) const +{ + return this->GetLinkClosure(config)->LinkerLanguage; +} + +//---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetPDBName(const std::string& config) const +{ + std::string prefix; + std::string base; + std::string suffix; + this->GetFullNameInternal(config, false, prefix, base, suffix); + + std::vector<std::string> props; + std::string configUpper = + cmSystemTools::UpperCase(config); + if(!configUpper.empty()) + { + // PDB_NAME_<CONFIG> + props.push_back("PDB_NAME_" + configUpper); + } + + // PDB_NAME + props.push_back("PDB_NAME"); + + for(std::vector<std::string>::const_iterator i = props.begin(); + i != props.end(); ++i) + { + if(const char* outName = this->GetProperty(*i)) + { + base = outName; + break; + } + } + return prefix+base+".pdb"; +} + bool cmStrictTargetComparison::operator()(cmTarget const* t1, cmTarget const* t2) const { @@ -1367,3 +2528,797 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const } } } + +//---------------------------------------------------------------------------- +const cmGeneratorTarget::CompatibleInterfacesBase& +cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const +{ + cmGeneratorTarget::CompatibleInterfaces& compat = + this->CompatibleInterfacesMap[config]; + if(!compat.Done) + { + compat.Done = true; + compat.PropsBool.insert("POSITION_INDEPENDENT_CODE"); + compat.PropsString.insert("AUTOUIC_OPTIONS"); + std::vector<cmTarget const*> const& deps = + this->GetLinkImplementationClosure(config); + for(std::vector<cmTarget const*>::const_iterator li = deps.begin(); + li != deps.end(); ++li) + { +#define CM_READ_COMPATIBLE_INTERFACE(X, x) \ + if(const char* prop = (*li)->GetProperty("COMPATIBLE_INTERFACE_" #X)) \ + { \ + std::vector<std::string> props; \ + cmSystemTools::ExpandListArgument(prop, props); \ + compat.Props##x.insert(props.begin(), props.end()); \ + } + CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool) + CM_READ_COMPATIBLE_INTERFACE(STRING, String) + CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin) + CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax) +#undef CM_READ_COMPATIBLE_INTERFACE + } + } + return compat; +} + +//---------------------------------------------------------------------------- +bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty( + const std::string &p, const std::string& config) const +{ + if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY + || this->Target->GetType() == cmTarget::INTERFACE_LIBRARY) + { + return false; + } + return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0; +} + +//---------------------------------------------------------------------------- +bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty( + const std::string &p, const std::string& config) const +{ + if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY + || this->Target->GetType() == cmTarget::INTERFACE_LIBRARY) + { + return false; + } + return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0; +} + +//---------------------------------------------------------------------------- +bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty( + const std::string &p, const std::string& config) const +{ + if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY + || this->Target->GetType() == cmTarget::INTERFACE_LIBRARY) + { + return false; + } + return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0; +} + +//---------------------------------------------------------------------------- +bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty( + const std::string &p, const std::string& config) const +{ + if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY + || this->Target->GetType() == cmTarget::INTERFACE_LIBRARY) + { + return false; + } + return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0; +} + +enum CompatibleType +{ + BoolType, + StringType, + NumberMinType, + NumberMaxType +}; + +template<typename PropertyType> +PropertyType getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt, + const std::string& prop, + const std::string& config, + CompatibleType, + PropertyType *); + +template<> +bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt, + const std::string& prop, + const std::string& config, + CompatibleType, bool *) +{ + return tgt->GetLinkInterfaceDependentBoolProperty(prop, config); +} + +template<> +const char * getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt, + const std::string& prop, + const std::string& config, + CompatibleType t, + const char **) +{ + switch(t) + { + case BoolType: + assert(0 && "String compatibility check function called for boolean"); + return 0; + case StringType: + return tgt->GetLinkInterfaceDependentStringProperty(prop, config); + case NumberMinType: + return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config); + case NumberMaxType: + return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config); + } + assert(0 && "Unreachable!"); + return 0; +} + +//---------------------------------------------------------------------------- +template<typename PropertyType> +void checkPropertyConsistency(cmGeneratorTarget const* depender, + cmTarget const* dependee, + const std::string& propName, + std::set<std::string> &emitted, + const std::string& config, + CompatibleType t, + PropertyType *) +{ + const char *prop = dependee->GetProperty(propName); + if (!prop) + { + return; + } + + std::vector<std::string> props; + cmSystemTools::ExpandListArgument(prop, props); + std::string pdir = + dependee->GetMakefile()->GetRequiredDefinition("CMAKE_ROOT"); + pdir += "/Help/prop_tgt/"; + + for(std::vector<std::string>::iterator pi = props.begin(); + pi != props.end(); ++pi) + { + std::string pname = cmSystemTools::HelpFileName(*pi); + std::string pfile = pdir + pname + ".rst"; + if(cmSystemTools::FileExists(pfile.c_str(), true)) + { + std::ostringstream e; + e << "Target \"" << dependee->GetName() << "\" has property \"" + << *pi << "\" listed in its " << propName << " property. " + "This is not allowed. Only user-defined properties may appear " + "listed in the " << propName << " property."; + depender->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } + if(emitted.insert(*pi).second) + { + getLinkInterfaceDependentProperty<PropertyType>(depender, *pi, config, + t, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + } + } +} + +static std::string intersect(const std::set<std::string> &s1, + const std::set<std::string> &s2) +{ + std::set<std::string> intersect; + std::set_intersection(s1.begin(),s1.end(), + s2.begin(),s2.end(), + std::inserter(intersect,intersect.begin())); + if (!intersect.empty()) + { + return *intersect.begin(); + } + return ""; +} + +static std::string intersect(const std::set<std::string> &s1, + const std::set<std::string> &s2, + const std::set<std::string> &s3) +{ + std::string result; + result = intersect(s1, s2); + if (!result.empty()) + return result; + result = intersect(s1, s3); + if (!result.empty()) + return result; + return intersect(s2, s3); +} + +static std::string intersect(const std::set<std::string> &s1, + const std::set<std::string> &s2, + const std::set<std::string> &s3, + const std::set<std::string> &s4) +{ + std::string result; + result = intersect(s1, s2); + if (!result.empty()) + return result; + result = intersect(s1, s3); + if (!result.empty()) + return result; + result = intersect(s1, s4); + if (!result.empty()) + return result; + return intersect(s2, s3, s4); +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::CheckPropertyCompatibility( + cmComputeLinkInformation *info, const std::string& config) const +{ + const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); + + std::set<std::string> emittedBools; + static std::string strBool = "COMPATIBLE_INTERFACE_BOOL"; + std::set<std::string> emittedStrings; + static std::string strString = "COMPATIBLE_INTERFACE_STRING"; + std::set<std::string> emittedMinNumbers; + static std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN"; + std::set<std::string> emittedMaxNumbers; + static std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX"; + + for(cmComputeLinkInformation::ItemVector::const_iterator li = + deps.begin(); li != deps.end(); ++li) + { + if (!li->Target) + { + continue; + } + + checkPropertyConsistency<bool>(this, li->Target, + strBool, + emittedBools, config, BoolType, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + checkPropertyConsistency<const char *>(this, li->Target, + strString, + emittedStrings, config, + StringType, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + checkPropertyConsistency<const char *>(this, li->Target, + strNumMin, + emittedMinNumbers, config, + NumberMinType, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + checkPropertyConsistency<const char *>(this, li->Target, + strNumMax, + emittedMaxNumbers, config, + NumberMaxType, 0); + if (cmSystemTools::GetErrorOccuredFlag()) + { + return; + } + } + + std::string prop = intersect(emittedBools, + emittedStrings, + emittedMinNumbers, + emittedMaxNumbers); + + if (!prop.empty()) + { + // Use a sorted std::vector to keep the error message sorted. + std::vector<std::string> props; + std::set<std::string>::const_iterator i = emittedBools.find(prop); + if (i != emittedBools.end()) + { + props.push_back(strBool); + } + i = emittedStrings.find(prop); + if (i != emittedStrings.end()) + { + props.push_back(strString); + } + i = emittedMinNumbers.find(prop); + if (i != emittedMinNumbers.end()) + { + props.push_back(strNumMin); + } + i = emittedMaxNumbers.find(prop); + if (i != emittedMaxNumbers.end()) + { + props.push_back(strNumMax); + } + std::sort(props.begin(), props.end()); + + std::string propsString = cmJoin(cmMakeRange(props).retreat(1), ", "); + propsString += " and the " + props.back(); + + std::ostringstream e; + e << "Property \"" << prop << "\" appears in both the " + << propsString << + " property in the dependencies of target \"" << this->GetName() << + "\". This is not allowed. A property may only require compatibility " + "in a boolean interpretation, a numeric minimum, a numeric maximum or a " + "string interpretation, but not a mixture."; + this->LocalGenerator->IssueMessage(cmake::FATAL_ERROR, e.str()); + } +} + +//---------------------------------------------------------------------------- +std::string compatibilityType(CompatibleType t) +{ + switch(t) + { + case BoolType: + return "Boolean compatibility"; + case StringType: + return "String compatibility"; + case NumberMaxType: + return "Numeric maximum compatibility"; + case NumberMinType: + return "Numeric minimum compatibility"; + } + assert(0 && "Unreachable!"); + return ""; +} + +//---------------------------------------------------------------------------- +std::string compatibilityAgree(CompatibleType t, bool dominant) +{ + switch(t) + { + case BoolType: + case StringType: + return dominant ? "(Disagree)\n" : "(Agree)\n"; + case NumberMaxType: + case NumberMinType: + return dominant ? "(Dominant)\n" : "(Ignored)\n"; + } + assert(0 && "Unreachable!"); + return ""; +} + +//---------------------------------------------------------------------------- +template<typename PropertyType> +PropertyType getTypedProperty(cmTarget const* tgt, const std::string& prop); + +//---------------------------------------------------------------------------- +template<> +bool getTypedProperty<bool>(cmTarget const* tgt, const std::string& prop) +{ + return tgt->GetPropertyAsBool(prop); +} + +//---------------------------------------------------------------------------- +template<> +const char *getTypedProperty<const char *>(cmTarget const* tgt, + const std::string& prop) +{ + return tgt->GetProperty(prop); +} + +template<typename PropertyType> +std::string valueAsString(PropertyType); +template<> +std::string valueAsString<bool>(bool value) +{ + return value ? "TRUE" : "FALSE"; +} +template<> +std::string valueAsString<const char*>(const char* value) +{ + return value ? value : "(unset)"; +} + +template<typename PropertyType> +PropertyType impliedValue(PropertyType); +template<> +bool impliedValue<bool>(bool) +{ + return false; +} +template<> +const char* impliedValue<const char*>(const char*) +{ + return ""; +} + +//---------------------------------------------------------------------------- +template<typename PropertyType> +std::pair<bool, PropertyType> consistentProperty(PropertyType lhs, + PropertyType rhs, + CompatibleType t); + +//---------------------------------------------------------------------------- +template<> +std::pair<bool, bool> consistentProperty(bool lhs, bool rhs, + CompatibleType) +{ + return std::make_pair(lhs == rhs, lhs); +} + +//---------------------------------------------------------------------------- +std::pair<bool, const char*> consistentStringProperty(const char *lhs, + const char *rhs) +{ + const bool b = strcmp(lhs, rhs) == 0; + return std::make_pair(b, b ? lhs : 0); +} + +//---------------------------------------------------------------------------- +std::pair<bool, const char*> consistentNumberProperty(const char *lhs, + const char *rhs, + CompatibleType t) +{ + char *pEnd; + + const char* const null_ptr = 0; + + long lnum = strtol(lhs, &pEnd, 0); + if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) + { + return std::pair<bool, const char*>(false, null_ptr); + } + + long rnum = strtol(rhs, &pEnd, 0); + if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) + { + return std::pair<bool, const char*>(false, null_ptr); + } + + if (t == NumberMaxType) + { + return std::make_pair(true, std::max(lnum, rnum) == lnum ? lhs : rhs); + } + else + { + return std::make_pair(true, std::min(lnum, rnum) == lnum ? lhs : rhs); + } +} + +//---------------------------------------------------------------------------- +template<> +std::pair<bool, const char*> consistentProperty(const char *lhs, + const char *rhs, + CompatibleType t) +{ + if (!lhs && !rhs) + { + return std::make_pair(true, lhs); + } + if (!lhs) + { + return std::make_pair(true, rhs); + } + if (!rhs) + { + return std::make_pair(true, lhs); + } + + const char* const null_ptr = 0; + + switch(t) + { + case BoolType: + assert(0 && "consistentProperty for strings called with BoolType"); + return std::pair<bool, const char*>(false, null_ptr); + case StringType: + return consistentStringProperty(lhs, rhs); + case NumberMinType: + case NumberMaxType: + return consistentNumberProperty(lhs, rhs, t); + } + assert(0 && "Unreachable!"); + return std::pair<bool, const char*>(false, null_ptr); +} + +//---------------------------------------------------------------------------- +template<typename PropertyType> +PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, + const std::string &p, + const std::string& config, + const char *defaultValue, + CompatibleType t, + PropertyType *) +{ + PropertyType propContent = getTypedProperty<PropertyType>(tgt->Target, p); + const bool explicitlySet = tgt->Target->GetProperties() + .find(p) + != tgt->Target->GetProperties().end(); + const bool impliedByUse = + tgt->Target->IsNullImpliedByLinkLibraries(p); + assert((impliedByUse ^ explicitlySet) + || (!impliedByUse && !explicitlySet)); + + std::vector<cmTarget const*> const& deps = + tgt->GetLinkImplementationClosure(config); + + if(deps.empty()) + { + return propContent; + } + bool propInitialized = explicitlySet; + + std::string report = " * Target \""; + report += tgt->GetName(); + if (explicitlySet) + { + report += "\" has property content \""; + report += valueAsString<PropertyType>(propContent); + report += "\"\n"; + } + else if (impliedByUse) + { + report += "\" property is implied by use.\n"; + } + else + { + report += "\" property not set.\n"; + } + + std::string interfaceProperty = "INTERFACE_" + p; + for(std::vector<cmTarget const*>::const_iterator li = + deps.begin(); + li != deps.end(); ++li) + { + // An error should be reported if one dependency + // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other + // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the + // target itself has a POSITION_INDEPENDENT_CODE which disagrees + // with a dependency. + + cmTarget const* theTarget = *li; + + const bool ifaceIsSet = theTarget->GetProperties() + .find(interfaceProperty) + != theTarget->GetProperties().end(); + PropertyType ifacePropContent = + getTypedProperty<PropertyType>(theTarget, + interfaceProperty); + + std::string reportEntry; + if (ifaceIsSet) + { + reportEntry += " * Target \""; + reportEntry += theTarget->GetName(); + reportEntry += "\" property value \""; + reportEntry += valueAsString<PropertyType>(ifacePropContent); + reportEntry += "\" "; + } + + if (explicitlySet) + { + if (ifaceIsSet) + { + std::pair<bool, PropertyType> consistent = + consistentProperty(propContent, + ifacePropContent, t); + report += reportEntry; + report += compatibilityAgree(t, propContent != consistent.second); + if (!consistent.first) + { + std::ostringstream e; + e << "Property " << p << " on target \"" + << tgt->GetName() << "\" does\nnot match the " + "INTERFACE_" << p << " property requirement\nof " + "dependency \"" << theTarget->GetName() << "\".\n"; + cmSystemTools::Error(e.str().c_str()); + break; + } + else + { + propContent = consistent.second; + continue; + } + } + else + { + // Explicitly set on target and not set in iface. Can't disagree. + continue; + } + } + else if (impliedByUse) + { + propContent = impliedValue<PropertyType>(propContent); + + if (ifaceIsSet) + { + std::pair<bool, PropertyType> consistent = + consistentProperty(propContent, + ifacePropContent, t); + report += reportEntry; + report += compatibilityAgree(t, propContent != consistent.second); + if (!consistent.first) + { + std::ostringstream e; + e << "Property " << p << " on target \"" + << tgt->GetName() << "\" is\nimplied to be " << defaultValue + << " because it was used to determine the link libraries\n" + "already. The INTERFACE_" << p << " property on\ndependency \"" + << theTarget->GetName() << "\" is in conflict.\n"; + cmSystemTools::Error(e.str().c_str()); + break; + } + else + { + propContent = consistent.second; + continue; + } + } + else + { + // Implicitly set on target and not set in iface. Can't disagree. + continue; + } + } + else + { + if (ifaceIsSet) + { + if (propInitialized) + { + std::pair<bool, PropertyType> consistent = + consistentProperty(propContent, + ifacePropContent, t); + report += reportEntry; + report += compatibilityAgree(t, propContent != consistent.second); + if (!consistent.first) + { + std::ostringstream e; + e << "The INTERFACE_" << p << " property of \"" + << theTarget->GetName() << "\" does\nnot agree with the value " + "of " << p << " already determined\nfor \"" + << tgt->GetName() << "\".\n"; + cmSystemTools::Error(e.str().c_str()); + break; + } + else + { + propContent = consistent.second; + continue; + } + } + else + { + report += reportEntry + "(Interface set)\n"; + propContent = ifacePropContent; + propInitialized = true; + } + } + else + { + // Not set. Nothing to agree on. + continue; + } + } + } + + tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent), + report, compatibilityType(t)); + return propContent; +} + +//---------------------------------------------------------------------------- +bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty( + const std::string &p, const std::string& config) const +{ + return checkInterfacePropertyCompatibility<bool>(this, p, config, + "FALSE", + BoolType, 0); +} + +//---------------------------------------------------------------------------- +const char* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty( + const std::string &p, + const std::string& config) const +{ + return checkInterfacePropertyCompatibility<const char *>(this, + p, + config, + "empty", + StringType, 0); +} + +//---------------------------------------------------------------------------- +const char * cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty( + const std::string &p, + const std::string& config) const +{ + return checkInterfacePropertyCompatibility<const char *>(this, + p, + config, + "empty", + NumberMinType, 0); +} + +//---------------------------------------------------------------------------- +const char * cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty( + const std::string &p, + const std::string& config) const +{ + return checkInterfacePropertyCompatibility<const char *>(this, + p, + config, + "empty", + NumberMaxType, 0); +} + +//---------------------------------------------------------------------------- +cmComputeLinkInformation* +cmGeneratorTarget::GetLinkInformation(const std::string& config) const +{ + // Lookup any existing information for this configuration. + std::string key(cmSystemTools::UpperCase(config)); + cmTargetLinkInformationMap::iterator + i = this->LinkInformation.find(key); + if(i == this->LinkInformation.end()) + { + // Compute information for this configuration. + cmComputeLinkInformation* info = + new cmComputeLinkInformation(this, config); + if(!info || !info->Compute()) + { + delete info; + info = 0; + } + + // Store the information for this configuration. + cmTargetLinkInformationMap::value_type entry(key, info); + i = this->LinkInformation.insert(entry).first; + + if (info) + { + this->CheckPropertyCompatibility(info, config); + } + } + return i->second; +} + +//---------------------------------------------------------------------------- +void +cmGeneratorTarget::ReportPropertyOrigin(const std::string &p, + const std::string &result, + const std::string &report, + const std::string &compatibilityType) const +{ + std::vector<std::string> debugProperties; + const char *debugProp = this->Target->GetMakefile() + ->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); + if (debugProp) + { + cmSystemTools::ExpandListArgument(debugProp, debugProperties); + } + + bool debugOrigin = !this->DebugCompatiblePropertiesDone[p] + && std::find(debugProperties.begin(), + debugProperties.end(), + p) + != debugProperties.end(); + + if (this->Target->GetMakefile()->IsConfigured()) + { + this->DebugCompatiblePropertiesDone[p] = true; + } + if (!debugOrigin) + { + return; + } + + std::string areport = compatibilityType; + areport += std::string(" of property \"") + p + "\" for target \""; + areport += std::string(this->GetName()); + areport += "\" (result: \""; + areport += result; + areport += "\"):\n" + report; + + this->Makefile->GetCMakeInstance()->IssueMessage(cmake::LOG, areport); +} diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index a584c71..68e7a8a 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -20,11 +20,13 @@ class cmLocalGenerator; class cmMakefile; class cmSourceFile; class cmTarget; +class cmComputeLinkInformation; class cmGeneratorTarget { public: cmGeneratorTarget(cmTarget*, cmLocalGenerator* lg); + ~cmGeneratorTarget(); cmLocalGenerator* GetLocalGenerator() const; @@ -36,6 +38,9 @@ public: location is suitable for use as the LOCATION target property. */ const char* GetLocationForBuild() const; + cmComputeLinkInformation* + GetLinkInformation(const std::string& config) const; + int GetType() const; std::string GetName() const; const char *GetProperty(const std::string& prop) const; @@ -82,6 +87,26 @@ public: bool GetFeatureAsBool(const std::string& feature, const std::string& config) const; + bool IsLinkInterfaceDependentBoolProperty(const std::string &p, + const std::string& config) const; + bool IsLinkInterfaceDependentStringProperty(const std::string &p, + const std::string& config) const; + bool IsLinkInterfaceDependentNumberMinProperty(const std::string &p, + const std::string& config) const; + bool IsLinkInterfaceDependentNumberMaxProperty(const std::string &p, + const std::string& config) const; + + bool GetLinkInterfaceDependentBoolProperty(const std::string &p, + const std::string& config) const; + + const char *GetLinkInterfaceDependentStringProperty(const std::string &p, + const std::string& config) const; + const char *GetLinkInterfaceDependentNumberMinProperty(const std::string &p, + const std::string& config) const; + const char *GetLinkInterfaceDependentNumberMaxProperty(const std::string &p, + const std::string& config) const; + + /** Get the full path to the target according to the settings in its makefile and the configuration type. */ std::string GetFullPath(const std::string& config="", bool implib = false, @@ -90,6 +115,53 @@ public: bool realname) const; std::string NormalGetRealName(const std::string& config) const; + /** @return the Mac App directory without the base */ + std::string GetAppBundleDirectory(const std::string& config, + bool contentOnly) const; + + /** Return whether this target is an executable Bundle, a framework + or CFBundle on Apple. */ + bool IsBundleOnApple() const; + + /** Get the full name of the target according to the settings in its + makefile. */ + std::string GetFullName(const std::string& config="", + bool implib = false) const; + + /** @return the Mac framework directory without the base. */ + std::string GetFrameworkDirectory(const std::string& config, + bool rootDir) const; + + /** @return the Mac CFBundle directory without the base */ + std::string GetCFBundleDirectory(const std::string& config, + bool contentOnly) const; + + /** 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 std::string& config) const; + + /** Return the install name directory for the target in the + * install tree. For example: "\@rpath/" or "\@loader_path/". */ + std::string GetInstallNameDirForInstallTree() const; + + /** Get the soname of the target. Allowed only for a shared library. */ + std::string GetSOName(const std::string& config) const; + + void GetFullNameComponents(std::string& prefix, + std::string& base, std::string& suffix, + const std::string& config="", + bool implib = false) const; + + /** Append to @a base the mac content directory and return it. */ + std::string BuildMacContentDirectory(const std::string& base, + const std::string& config = "", + bool contentOnly = true) const; + + /** @return the mac content directory for this target. */ + std::string GetMacContentDirectory(const std::string& config = 0, + bool implib = false) const; + cmTarget* Target; cmMakefile* Makefile; cmLocalGenerator* LocalGenerator; @@ -97,6 +169,20 @@ public: std::string GetModuleDefinitionFile(const std::string& config) const; + /** Link information from the transitive closure of the link + implementation and the interfaces of its dependencies. */ + struct LinkClosure + { + // The preferred linker language. + std::string LinkerLanguage; + + // Languages whose runtime libraries must be linked. + std::vector<std::string> Languages; + }; + + LinkClosure const* GetLinkClosure(const std::string& config) const; + void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const; + /** 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. */ @@ -128,10 +214,41 @@ public: */ void TraceDependencies(); + /** Get the directory in which to place the target compiler .pdb file. + If the configuration name is given then the generator will add its + subdirectory for that configuration. Otherwise just the canonical + compiler pdb output directory is given. */ + std::string GetCompilePDBDirectory(const std::string& config = "") const; + /** Get sources that must be built before the given source. */ std::vector<cmSourceFile*> const* GetSourceDepends(cmSourceFile const* sf) const; + /** Get the name of the pdb file for the target. */ + std::string GetPDBName(const std::string& config="") const; + + /** Whether this library has soname enabled and platform supports it. */ + bool HasSOName(const std::string& config) const; + + struct CompileInfo + { + std::string CompilePdbDir; + }; + + CompileInfo const* GetCompileInfo(const std::string& config) const; + + typedef std::map<std::string, CompileInfo> CompileInfoMapType; + mutable CompileInfoMapType CompileInfoMap; + + /** Get the name of the compiler pdb file for the target. */ + std::string GetCompilePDBName(const std::string& config="") const; + + /** Get the path for the MSVC /Fd option for this target. */ + std::string GetCompilePDBPath(const std::string& config="") const; + + // Get the target base name. + std::string GetOutputName(const std::string& config, bool implib) const; + /** * Flags for a given source file as used in this target. Typically assigned * via SET_TARGET_PROPERTIES when the property is a list of source files. @@ -153,6 +270,33 @@ public: SourceFileType Type; const char* MacFolder; // location inside Mac content folders }; + void GetAutoUicOptions(std::vector<std::string> &result, + const std::string& config) const; + + /** Get the names of the executable needed to generate a build rule + that takes into account executable version numbers. This should + be called only on an executable target. */ + void GetExecutableNames(std::string& name, std::string& realName, + std::string& impName, std::string& pdbName, + const std::string& config) const; + + /** Get the names of the library needed to generate a build rule + that takes into account shared library version numbers. This + should be called only on a library target. */ + void GetLibraryNames(std::string& name, std::string& soName, + std::string& realName, std::string& impName, + std::string& pdbName, const std::string& config) const; + + /** + * Compute whether this target must be relinked before installing. + */ + bool NeedRelinkBeforeInstall(const std::string& config) const; + + /** Return true if builtin chrpath will work for this target */ + bool IsChrpathUsed(const std::string& config) const; + + ///! Return the preferred linker language for this target + std::string GetLinkerLanguage(const std::string& config = "") const; struct SourceFileFlags GetTargetSourceFileFlags(const cmSourceFile* sf) const; @@ -168,12 +312,16 @@ public: std::vector<cmSourceFile const*> XamlSources; }; + void ReportPropertyOrigin(const std::string &p, + const std::string &result, + const std::string &report, + const std::string &compatibilityType) const; + private: friend class cmTargetTraceDependencies; struct SourceEntry { std::vector<cmSourceFile*> Depends; }; typedef std::map<cmSourceFile const*, SourceEntry> SourceEntriesType; SourceEntriesType SourceEntries; - mutable std::map<cmSourceFile const*, std::string> Objects; std::set<cmSourceFile const*> ExplicitObjectName; mutable std::map<std::string, std::vector<std::string> > SystemIncludesCache; @@ -182,8 +330,55 @@ private: mutable bool SourceFileFlagsConstructed; mutable std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap; + mutable std::map<std::string, bool> DebugCompatiblePropertiesDone; + + std::string GetFullNameInternal(const std::string& config, + bool implib) const; + void GetFullNameInternal(const std::string& config, bool implib, + std::string& outPrefix, std::string& outBase, + std::string& outSuffix) const; + + typedef std::map<std::string, LinkClosure> LinkClosureMapType; + mutable LinkClosureMapType LinkClosureMap; + + struct CompatibleInterfacesBase + { + std::set<std::string> PropsBool; + std::set<std::string> PropsString; + std::set<std::string> PropsNumberMax; + std::set<std::string> PropsNumberMin; + }; + CompatibleInterfacesBase const& + GetCompatibleInterfaces(std::string const& config) const; + + struct CompatibleInterfaces: public CompatibleInterfacesBase + { + CompatibleInterfaces(): Done(false) {} + bool Done; + }; + mutable std::map<std::string, CompatibleInterfaces> CompatibleInterfacesMap; + + typedef std::map<std::string, cmComputeLinkInformation*> + cmTargetLinkInformationMap; + mutable cmTargetLinkInformationMap LinkInformation; + + void CheckPropertyCompatibility(cmComputeLinkInformation *info, + const std::string& config) const; + cmGeneratorTarget(cmGeneratorTarget const&); void operator=(cmGeneratorTarget const&); + + struct LinkImplClosure: public std::vector<cmTarget const*> + { + LinkImplClosure(): Done(false) {} + bool Done; + }; + mutable std::map<std::string, LinkImplClosure> LinkImplClosureMap; + +public: + std::vector<cmTarget const*> const& + GetLinkImplementationClosure(const std::string& config) const; + }; struct cmStrictTargetComparison { diff --git a/Source/cmGetDirectoryPropertyCommand.cxx b/Source/cmGetDirectoryPropertyCommand.cxx index c056d95..2558876 100644 --- a/Source/cmGetDirectoryPropertyCommand.cxx +++ b/Source/cmGetDirectoryPropertyCommand.cxx @@ -51,10 +51,8 @@ bool cmGetDirectoryPropertyCommand sd = cmSystemTools::CollapseFullPath(sd); // lookup the makefile from the directory name - cmLocalGenerator *lg = - this->Makefile->GetGlobalGenerator()-> - FindLocalGenerator(sd); - if (!lg) + dir = this->Makefile->GetGlobalGenerator()->FindMakefile(sd); + if (!dir) { this->SetError ("DIRECTORY argument provided but requested directory not found. " @@ -62,7 +60,6 @@ bool cmGetDirectoryPropertyCommand "it is valid but has not been processed yet."); return false; } - dir = lg->GetMakefile(); ++i; } diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx index 67f9f2d..13a9afb 100644 --- a/Source/cmGetFilenameComponentCommand.cxx +++ b/Source/cmGetFilenameComponentCommand.cxx @@ -24,7 +24,7 @@ bool cmGetFilenameComponentCommand // Check and see if the value has been stored in the cache // already, if so use that value - if(args.size() == 4 && args[3] == "CACHE") + if(args.size() >= 4 && args[args.size() - 1] == "CACHE") { const char* cacheValue = this->Makefile->GetDefinition(args[0]); if(cacheValue && !cmSystemTools::IsNOTFOUND(cacheValue)) @@ -111,7 +111,7 @@ bool cmGetFilenameComponentCommand return false; } - if(args.size() == 4 && args[3] == "CACHE") + if(args.size() >= 4 && args[args.size() - 1] == "CACHE") { if(!programArgs.empty() && !storeArgs.empty()) { diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx index 33d638b..4c42f53 100644 --- a/Source/cmGetPropertyCommand.cxx +++ b/Source/cmGetPropertyCommand.cxx @@ -262,13 +262,8 @@ bool cmGetPropertyCommand::HandleDirectoryMode() dir = cmSystemTools::CollapseFullPath(dir); // Lookup the generator. - if(cmLocalGenerator* lg = - (this->Makefile->GetGlobalGenerator()->FindLocalGenerator(dir))) - { - // Use the makefile for the directory found. - mf = lg->GetMakefile(); - } - else + mf = this->Makefile->GetGlobalGenerator()->FindMakefile(dir); + if (!mf) { // Could not find the directory. this->SetError diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index 2f9265a..1e57c33 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -128,7 +128,8 @@ void cmGhsMultiTargetGenerator::Generate() { config = "RELEASE"; } - const std::string language(this->Target->GetLinkerLanguage(config)); + const std::string language( + this->GeneratorTarget->GetLinkerLanguage(config)); config = cmSystemTools::UpperCase(config); this->DynamicDownload = this->DetermineIfDynamicDownload(config, language); if (this->DynamicDownload) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 5599854..cda26cd 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -14,6 +14,20 @@ #if defined(_MSC_VER) && _MSC_VER >= 1800 # define KWSYS_WINDOWS_DEPRECATED_GetVersionEx #endif +typedef struct { + ULONG dwOSVersionInfoSize; + ULONG dwMajorVersion; + ULONG dwMinorVersion; + ULONG dwBuildNumber; + ULONG dwPlatformId; + WCHAR szCSDVersion[128]; + USHORT wServicePackMajor; + USHORT wServicePackMinor; + USHORT wSuiteMask; + UCHAR wProductType; + UCHAR wReserved; +} CMRTL_OSVERSIONINFOEXW; + #endif #include "cmGlobalGenerator.h" @@ -30,10 +44,10 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGeneratorExpression.h" -#include "cmGeneratorExpressionEvaluationFile.h" #include "cmExportBuildFileGenerator.h" #include "cmCPackPropertiesGenerator.h" #include "cmAlgorithms.h" +#include "cmInstallGenerator.h" #include <cmsys/Directory.hxx> #include <cmsys/FStream.hxx> @@ -432,23 +446,45 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages, if (!mf->GetDefinition("CMAKE_SYSTEM")) { #if defined(_WIN32) && !defined(__CYGWIN__) - /* Windows version number data. */ - OSVERSIONINFO osvi; - ZeroMemory(&osvi, sizeof(osvi)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + CMRTL_OSVERSIONINFOEXW osviex; + ZeroMemory(&osviex, sizeof(osviex)); + osviex.dwOSVersionInfoSize = sizeof(osviex); + + typedef LONG (FAR WINAPI *cmRtlGetVersion)(CMRTL_OSVERSIONINFOEXW*); + cmRtlGetVersion rtlGetVersion = reinterpret_cast<cmRtlGetVersion>( + GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion")); + if (rtlGetVersion && rtlGetVersion(&osviex) == 0) + { + std::ostringstream windowsVersionString; + windowsVersionString << osviex.dwMajorVersion << "." + << osviex.dwMinorVersion << "." + << osviex.dwBuildNumber; + windowsVersionString.str(); + mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", + windowsVersionString.str().c_str()); + } + else + { + // RtlGetVersion failed, so use the deprecated GetVersionEx function. + /* Windows version number data. */ + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(osvi)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx # pragma warning (push) # pragma warning (disable:4996) #endif - GetVersionEx (&osvi); + GetVersionEx (&osvi); #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx # pragma warning (pop) #endif - std::ostringstream windowsVersionString; - windowsVersionString << osvi.dwMajorVersion << "." << osvi.dwMinorVersion; - windowsVersionString.str(); - mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", - windowsVersionString.str().c_str()); + std::ostringstream windowsVersionString; + windowsVersionString << osvi.dwMajorVersion << "." + << osvi.dwMinorVersion; + windowsVersionString.str(); + mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", + windowsVersionString.str().c_str()); + } #endif // Read the DetermineSystem file std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake"); @@ -1093,6 +1129,7 @@ void cmGlobalGenerator::Configure() // start with this directory cmLocalGenerator *lg = this->MakeLocalGenerator(); + this->Makefiles.push_back(lg->GetMakefile()); this->LocalGenerators.push_back(lg); // set the Start directories @@ -1111,9 +1148,9 @@ void cmGlobalGenerator::Configure() // update the cache entry for the number of local generators, this is used // for progress char num[100]; - sprintf(num,"%d",static_cast<int>(this->LocalGenerators.size())); + sprintf(num,"%d",static_cast<int>(this->Makefiles.size())); this->GetCMakeInstance()->AddCacheEntry - ("CMAKE_NUMBER_OF_LOCAL_GENERATORS", num, + ("CMAKE_NUMBER_OF_MAKEFILES", num, "number of local generators", cmState::INTERNAL); // check for link libraries and include directories containing "NOTFOUND" @@ -1156,9 +1193,9 @@ void cmGlobalGenerator::Configure() cmTargets globalTargets; this->CreateDefaultGlobalTargets(&globalTargets); - for (i = 0; i < this->LocalGenerators.size(); ++i) + for (i = 0; i < this->Makefiles.size(); ++i) { - cmMakefile* mf = this->LocalGenerators[i]->GetMakefile(); + cmMakefile* mf = this->Makefiles[i]; cmTargets* targets = &(mf->GetTargets()); cmTargets::iterator tit; for ( tit = globalTargets.begin(); tit != globalTargets.end(); ++ tit ) @@ -1212,7 +1249,7 @@ bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const return false; } -void cmGlobalGenerator::DoGenerate() +bool cmGlobalGenerator::Compute() { // Some generators track files replaced during the Generate. // Start with an empty vector: @@ -1221,17 +1258,11 @@ void cmGlobalGenerator::DoGenerate() // clear targets to issue warning CMP0042 for this->CMP0042WarnTargets.clear(); - this->Generate(); -} - -void cmGlobalGenerator::Generate() -{ // Check whether this generator is allowed to run. if(!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS()) { - return; + return false; } - this->FinalizeTargetCompileInfo(); this->CreateGenerationObjects(); @@ -1266,6 +1297,24 @@ void cmGlobalGenerator::Generate() } #endif + for (i = 0; i < this->LocalGenerators.size(); ++i) + { + cmMakefile* mf = this->LocalGenerators[i]->GetMakefile(); + std::vector<cmInstallGenerator*>& gens = mf->GetInstallGenerators(); + for (std::vector<cmInstallGenerator*>::const_iterator git = gens.begin(); + git != gens.end(); ++git) + { + (*git)->Compute(this->LocalGenerators[i]); + } + } + + return true; +} + +void cmGlobalGenerator::Generate() +{ + unsigned int i; + // Trace the dependencies, after that no custom commands should be added // because their dependencies might not be handled correctly for (i = 0; i < this->LocalGenerators.size(); ++i) @@ -1433,9 +1482,9 @@ void cmGlobalGenerator::CreateQtAutoGeneratorsTargets(AutogensType &autogens) void cmGlobalGenerator::FinalizeTargetCompileInfo() { // Construct per-target generator information. - for(unsigned int i=0; i < this->LocalGenerators.size(); ++i) + for(unsigned int i=0; i < this->Makefiles.size(); ++i) { - cmMakefile *mf = this->LocalGenerators[i]->GetMakefile(); + cmMakefile *mf = this->Makefiles[i]; const cmStringRange noconfig_compile_definitions = mf->GetCompileDefinitionsEntries(); @@ -1501,6 +1550,7 @@ void cmGlobalGenerator::CreateGeneratorTargets(TargetTypes targetTypes, ti != targets.end(); ++ti) { cmTarget* t = &ti->second; + t->Compute(); cmGeneratorTarget* gt = new cmGeneratorTarget(t, lg); this->GeneratorTargets[t] = gt; generatorTargets[t] = gt; @@ -1548,12 +1598,11 @@ void cmGlobalGenerator::ClearGeneratorMembers() cmDeleteAll(this->GeneratorTargets); this->GeneratorTargets.clear(); - cmDeleteAll(this->EvaluationFiles); - this->EvaluationFiles.clear(); - cmDeleteAll(this->BuildExportSets); this->BuildExportSets.clear(); + this->Makefiles.clear(); + cmDeleteAll(this->LocalGenerators); this->LocalGenerators.clear(); @@ -1593,11 +1642,11 @@ void cmGlobalGenerator::CheckLocalGenerators() // std::set<std::string> notFoundMap; // after it is all done do a ConfigureFinalPass cmState* state = this->GetCMakeInstance()->GetState(); - for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) + for (unsigned int i = 0; i < this->Makefiles.size(); ++i) { - this->LocalGenerators[i]->GetMakefile()->ConfigureFinalPass(); + this->Makefiles[i]->ConfigureFinalPass(); cmTargets &targets = - this->LocalGenerators[i]->GetMakefile()->GetTargets(); + this->Makefiles[i]->GetTargets(); for (cmTargets::iterator l = targets.begin(); l != targets.end(); l++) { @@ -1652,15 +1701,14 @@ void cmGlobalGenerator::CheckLocalGenerators() } std::string text = notFoundMap[varName]; text += "\n used as include directory in directory "; - text += this->LocalGenerators[i] - ->GetMakefile()->GetCurrentSourceDirectory(); + text += this->Makefiles[i]->GetCurrentSourceDirectory(); notFoundMap[varName] = text; } } } this->CMakeInstance->UpdateProgress ("Configuring", 0.9f+0.1f*(static_cast<float>(i)+1.0f)/ - static_cast<float>(this->LocalGenerators.size())); + static_cast<float>(this->Makefiles.size())); } if(!notFoundMap.empty()) @@ -1694,9 +1742,9 @@ int cmGlobalGenerator::TryCompile(const std::string& srcdir, // take the bulk of the time, so try and guess some progress // by getting closer and closer to 100 without actually getting there. if (!this->CMakeInstance->GetState()->GetInitializedCacheValue - ("CMAKE_NUMBER_OF_LOCAL_GENERATORS")) + ("CMAKE_NUMBER_OF_MAKEFILES")) { - // If CMAKE_NUMBER_OF_LOCAL_GENERATORS is not set + // If CMAKE_NUMBER_OF_MAKEFILES is not set // we are in the first time progress and we have no // idea how long it will be. So, just move 1/10th of the way // there each time, and don't go over 95% @@ -1884,19 +1932,19 @@ std::string cmGlobalGenerator::GenerateCMakeBuildCommand( } //---------------------------------------------------------------------------- -void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg) +void cmGlobalGenerator::AddMakefile(cmMakefile *mf) { - this->LocalGenerators.push_back(lg); + this->Makefiles.push_back(mf); // update progress // estimate how many lg there will be const char *numGenC = this->CMakeInstance->GetState()->GetInitializedCacheValue - ("CMAKE_NUMBER_OF_LOCAL_GENERATORS"); + ("CMAKE_NUMBER_OF_MAKEFILES"); if (!numGenC) { - // If CMAKE_NUMBER_OF_LOCAL_GENERATORS is not set + // If CMAKE_NUMBER_OF_MAKEFILES is not set // we are in the first time progress and we have no // idea how long it will be. So, just move half way // there each time, and don't go over 95% @@ -1911,7 +1959,7 @@ void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg) } int numGen = atoi(numGenC); - float prog = 0.9f*static_cast<float>(this->LocalGenerators.size())/ + float prog = 0.9f*static_cast<float>(this->Makefiles.size())/ static_cast<float>(numGen); if (prog > 0.9f) { @@ -1920,6 +1968,12 @@ void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg) this->CMakeInstance->UpdateProgress("Configuring", prog); } +//---------------------------------------------------------------------------- +void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg) +{ + this->LocalGenerators.push_back(lg); +} + void cmGlobalGenerator::AddInstallComponent(const char* component) { if(component && *component) @@ -2009,10 +2063,10 @@ bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root, } bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root, - cmTarget const& target) const + cmGeneratorTarget* target) const { - if(target.GetType() == cmTarget::INTERFACE_LIBRARY - || target.GetPropertyAsBool("EXCLUDE_FROM_ALL")) + if(target->GetType() == cmTarget::INTERFACE_LIBRARY + || target->Target->GetPropertyAsBool("EXCLUDE_FROM_ALL")) { // This target is excluded from its directory. return true; @@ -2021,7 +2075,7 @@ bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root, { // This target is included in its directory. Check whether the // directory is excluded. - return this->IsExcluded(root, target.GetMakefile()->GetLocalGenerator()); + return this->IsExcluded(root, target->GetLocalGenerator()); } } @@ -2082,15 +2136,16 @@ void cmGlobalGenerator::FillLocalGeneratorToTargetMap() { cmTarget const& target = t->second; + cmGeneratorTarget* gt = this->GetGeneratorTarget(&target); + // Consider the directory containing the target and all its // parents until something excludes the target. - for(cmLocalGenerator* clg = lg; clg && !this->IsExcluded(clg, target); + for(cmLocalGenerator* clg = lg; clg && !this->IsExcluded(clg, gt); clg = clg->GetParent()) { // This local generator includes the target. std::set<cmGeneratorTarget const*>& targetSet = this->LocalGeneratorToTargetMap[clg]; - cmGeneratorTarget* gt = this->GetGeneratorTarget(&target); targetSet.insert(gt); // Add dependencies of the included target. An excluded @@ -2107,6 +2162,20 @@ void cmGlobalGenerator::FillLocalGeneratorToTargetMap() } } +cmMakefile* +cmGlobalGenerator::FindMakefile(const std::string& start_dir) const +{ + for(std::vector<cmMakefile*>::const_iterator it = + this->Makefiles.begin(); it != this->Makefiles.end(); ++it) + { + std::string sd = (*it)->GetCurrentSourceDirectory(); + if (sd == start_dir) + { + return *it; + } + } + return 0; +} ///! Find a local generator by its startdirectory cmLocalGenerator* @@ -2194,7 +2263,7 @@ inline std::string removeQuotes(const std::string& s) void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets) { - cmMakefile* mf = this->LocalGenerators[0]->GetMakefile(); + cmMakefile* mf = this->Makefiles[0]; const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); // CPack @@ -2698,12 +2767,8 @@ void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target, //---------------------------------------------------------------------------- -void cmGlobalGenerator::AddToManifest(const std::string& config, - std::string const& f) +void cmGlobalGenerator::AddToManifest(std::string const& f) { - // Add to the main manifest for this configuration. - this->TargetManifest[config].insert(f); - // Add to the content listing for the file's directory. std::string dir = cmSystemTools::GetFilenamePath(f); std::string file = cmSystemTools::GetFilenameName(f); @@ -2771,9 +2836,9 @@ cmGlobalGenerator::AddRuleHash(const std::vector<std::string>& outputs, } // Shorten the output name (in expected use case). - cmLocalGenerator* lg = this->GetLocalGenerators()[0]; - std::string fname = lg->Convert(outputs[0], - cmLocalGenerator::HOME_OUTPUT); + cmOutputConverter converter(this->GetMakefiles()[0]->GetStateSnapshot()); + std::string fname = converter.Convert( + outputs[0], cmLocalGenerator::HOME_OUTPUT); // Associate the hash with this output. this->RuleHashes[fname] = hash; @@ -3023,61 +3088,21 @@ cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const { void cmGlobalGenerator::CreateEvaluationSourceFiles( std::string const& config) const { - for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator - li = this->EvaluationFiles.begin(); - li != this->EvaluationFiles.end(); - ++li) + unsigned int i; + for (i = 0; i < this->LocalGenerators.size(); ++i) { - (*li)->CreateOutputFile(config); + this->LocalGenerators[i]->CreateEvaluationFileOutputs(config); } } //---------------------------------------------------------------------------- -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::vector<std::string> generatedFiles; - for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator - li = this->EvaluationFiles.begin(); - li != this->EvaluationFiles.end(); - ++li) + unsigned int i; + for (i = 0; i < this->LocalGenerators.size(); ++i) { - (*li)->Generate(); - if (cmSystemTools::GetFatalErrorOccured()) - { - return; - } - std::vector<std::string> files = (*li)->GetFiles(); - std::sort(files.begin(), files.end()); - - std::vector<std::string> intersection; - std::set_intersection(files.begin(), files.end(), - generatedFiles.begin(), generatedFiles.end(), - std::back_inserter(intersection)); - if (!intersection.empty()) - { - cmSystemTools::Error("Files to be generated by multiple different " - "commands: ", cmWrap('"', intersection, '"', " ").c_str()); - return; - } - - generatedFiles.insert(generatedFiles.end(), - files.begin(), files.end()); - std::vector<std::string>::iterator newIt = - generatedFiles.end() - files.size(); - std::inplace_merge(generatedFiles.begin(), newIt, generatedFiles.end()); + this->LocalGenerators[i]->ProcessEvaluationFiles(generatedFiles); } } diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index d486003..a13bede 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -34,7 +34,6 @@ class cmake; class cmGeneratorTarget; -class cmGeneratorExpressionEvaluationFile; class cmMakefile; class cmLocalGenerator; class cmExternalMakefileProjectGenerator; @@ -86,6 +85,7 @@ public: */ virtual void Configure(); + virtual bool Compute(); enum TargetTypes { AllTargets, @@ -99,7 +99,7 @@ public: * basically creates a series of LocalGenerators for each directory and * requests that they Generate. */ - void DoGenerate(); + virtual void Generate(); /** * Set/Get and Clear the enabled languages. @@ -173,6 +173,8 @@ public: cmake *GetCMakeInstance() const { return this->CMakeInstance; } void SetConfiguredFilesPath(cmGlobalGenerator* gen); + const std::vector<cmMakefile*>& GetMakefiles() const { + return this->Makefiles;} const std::vector<cmLocalGenerator *>& GetLocalGenerators() const { return this->LocalGenerators;} @@ -184,6 +186,7 @@ public: void SetCurrentMakefile(cmMakefile* mf) {this->CurrentMakefile = mf;} + void AddMakefile(cmMakefile *mf); void AddLocalGenerator(cmLocalGenerator *lg); ///! Set an generator for an "external makefile based project" @@ -200,7 +203,7 @@ public: cmExportSetMap& GetExportSets() {return this->ExportSets;} /** Add a file to the manifest of generated targets for a configuration. */ - void AddToManifest(const std::string& config, std::string const& f); + void AddToManifest(std::string const& f); void EnableInstallTarget(); @@ -253,6 +256,7 @@ public: that is a framework. */ bool NameResolvesToFramework(const std::string& libname) const; + cmMakefile* FindMakefile(const std::string& start_dir) const; ///! Find a local generator by its startdirectory cmLocalGenerator* FindLocalGenerator(const std::string& start_dir) const; @@ -264,11 +268,6 @@ public: const std::string& suffix, std::string& dir); - /** Get the manifest of all targets that will be built for each - configuration. This is valid during generation only. */ - cmTargetManifest const& GetTargetManifest() const - { return this->TargetManifest; } - /** Get the content of a directory. Directory listings are cached and re-loaded from disk only when modified. During the generation step the content will include the target files to be built even if @@ -338,12 +337,6 @@ 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(); std::map<std::string, cmExportBuildFileGenerator*>& GetBuildExportSets() @@ -373,8 +366,6 @@ public: std::string MakeSilentFlag; protected: - virtual void Generate(); - typedef std::vector<cmLocalGenerator*> GeneratorVector; // for a project collect all its targets by following depend // information, and also collect all the targets @@ -387,6 +378,8 @@ protected: void SetLanguageEnabledFlag(const std::string& l, cmMakefile* mf); void SetLanguageEnabledMaps(const std::string& l, cmMakefile* mf); void FillExtensionToLanguageMap(const std::string& l, cmMakefile* mf); + virtual void PrintCompilerAdvice(std::ostream& os, std::string const& lang, + const char* envVar) const; virtual bool ComputeTargetDepends(); @@ -404,7 +397,7 @@ protected: void FillProjectMap(); void CheckLocalGenerators(); bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen) const; - bool IsExcluded(cmLocalGenerator* root, cmTarget const& target) const; + bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) const; void FillLocalGeneratorToTargetMap(); void CreateDefaultGlobalTargets(cmTargets* targets); cmTarget CreateGlobalTarget(const std::string& name, const char* message, @@ -415,6 +408,7 @@ protected: std::string FindMakeProgramFile; std::string ConfiguredFilesPath; cmake *CMakeInstance; + std::vector<cmMakefile*> Makefiles; std::vector<cmLocalGenerator *> LocalGenerators; cmMakefile* CurrentMakefile; // map from project name to vector of local generators in that project @@ -429,10 +423,6 @@ protected: std::map<std::string, cmExportBuildFileGenerator*> BuildExportSets; std::map<std::string, cmExportBuildFileGenerator*> BuildExportExportSets; - // Manifest of all targets that will be built for each configuration. - // This is computed just before local generators generate. - cmTargetManifest TargetManifest; - // All targets in the entire project. #if defined(CMAKE_BUILD_WITH_CMAKE) #ifdef CMake_HAVE_CXX11_UNORDERED_MAP @@ -446,7 +436,6 @@ protected: TargetMap TotalTargets; TargetMap AliasTargets; TargetMap ImportedTargets; - std::vector<cmGeneratorExpressionEvaluationFile*> EvaluationFiles; const char* GetPredefinedTargetsFolder(); virtual bool UseFolderProperty(); @@ -480,8 +469,6 @@ private: virtual void ForceLinkerLanguages(); - virtual void PrintCompilerAdvice(std::ostream& os, std::string const& lang, - const char* envVar) const; void CheckCompilerIdCompatibility(cmMakefile* mf, std::string const& lang) const; diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx index 50e7053..3f33f91 100644 --- a/Source/cmGlobalJOMMakefileGenerator.cxx +++ b/Source/cmGlobalJOMMakefileGenerator.cxx @@ -36,18 +36,6 @@ void cmGlobalJOMMakefileGenerator // pick a default mf->AddDefinition("CMAKE_GENERATOR_CC", "cl"); mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl"); - if(!(cmSystemTools::GetEnv("INCLUDE") && - cmSystemTools::GetEnv("LIB")) - ) - { - std::string message = "To use the JOM generator, cmake must be run " - "from a shell that can use the compiler cl from the command line. " - "This environment does not contain INCLUDE, LIB, or LIBPATH, and " - "these must be set for the cl compiler to work. "; - mf->IssueMessage(cmake::WARNING, - message); - } - this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional); } @@ -58,3 +46,19 @@ void cmGlobalJOMMakefileGenerator entry.Name = cmGlobalJOMMakefileGenerator::GetActualName(); entry.Brief = "Generates JOM makefiles."; } + +//---------------------------------------------------------------------------- +void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(std::ostream& os, + std::string const& lang, + const char* envVar) const +{ + if(lang == "CXX" || lang == "C") + { + os << + "To use the JOM generator with Visual C++, cmake must be run from a " + "shell that can use the compiler cl from the command line. This " + "environment is unable to invoke the cl compiler. To fix this problem, " + "run cmake from the Visual Studio Command Prompt (vcvarsall.bat).\n"; + } + this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar); +} diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h index 2185b23..1869fed 100644 --- a/Source/cmGlobalJOMMakefileGenerator.h +++ b/Source/cmGlobalJOMMakefileGenerator.h @@ -42,6 +42,9 @@ public: */ virtual void EnableLanguage(std::vector<std::string>const& languages, cmMakefile *, bool optional); +private: + void PrintCompilerAdvice(std::ostream& os, std::string const& lang, + const char* envVar) const; }; #endif diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx index 4219c34..7c570a6 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.cxx +++ b/Source/cmGlobalNMakeMakefileGenerator.cxx @@ -36,18 +36,6 @@ void cmGlobalNMakeMakefileGenerator // pick a default mf->AddDefinition("CMAKE_GENERATOR_CC", "cl"); mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl"); - if(!(cmSystemTools::GetEnv("INCLUDE") && - cmSystemTools::GetEnv("LIB")) - ) - { - std::string message = "To use the NMake generator, cmake must be run " - "from a shell that can use the compiler cl from the command line. " - "This environment does not contain INCLUDE, LIB, or LIBPATH, and " - "these must be set for the cl compiler to work. "; - mf->IssueMessage(cmake::WARNING, - message); - } - this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional); } @@ -58,3 +46,19 @@ void cmGlobalNMakeMakefileGenerator entry.Name = cmGlobalNMakeMakefileGenerator::GetActualName(); entry.Brief = "Generates NMake makefiles."; } + +//---------------------------------------------------------------------------- +void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(std::ostream& os, + std::string const& lang, + const char* envVar) const +{ + if(lang == "CXX" || lang == "C") + { + os << + "To use the NMake generator with Visual C++, cmake must be run from a " + "shell that can use the compiler cl from the command line. This " + "environment is unable to invoke the cl compiler. To fix this problem, " + "run cmake from the Visual Studio Command Prompt (vcvarsall.bat).\n"; + } + this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar); +} diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h index dd72c49..3c8375a 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.h +++ b/Source/cmGlobalNMakeMakefileGenerator.h @@ -40,6 +40,9 @@ public: */ virtual void EnableLanguage(std::vector<std::string>const& languages, cmMakefile *, bool optional); +private: + void PrintCompilerAdvice(std::ostream& os, std::string const& lang, + const char* envVar) const; }; #endif diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index d24cce8..b92ad32 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -547,6 +547,18 @@ void cmGlobalNinjaGenerator // Source/cmake.cxx void cmGlobalNinjaGenerator::Generate() { + // Check minimum Ninja version. + if (cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, + CurrentNinjaVersion().c_str(), + RequiredNinjaVersion().c_str())) + { + std::ostringstream msg; + msg << "The detected version of Ninja (" << this->CurrentNinjaVersion(); + msg << ") is less than the version of Ninja required by CMake ("; + msg << this->RequiredNinjaVersion() << ")."; + this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, msg.str()); + return; + } this->OpenBuildFileStream(); this->OpenRulesFileStream(); @@ -911,9 +923,7 @@ cmGlobalNinjaGenerator case cmTarget::STATIC_LIBRARY: case cmTarget::MODULE_LIBRARY: { - cmGeneratorTarget *gtgt = target->GetMakefile()->GetLocalGenerator() - ->GetGlobalGenerator() - ->GetGeneratorTarget(target); + cmGeneratorTarget *gtgt = this->GetGeneratorTarget(target); outputs.push_back(ng->ConvertToNinjaPath( gtgt->GetFullPath(configName, false, realname))); break; @@ -1055,23 +1065,21 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os) { knownDependencies.insert( ng->ConvertToNinjaPath( *j ) ); } - } - knownDependencies.insert( "CMakeCache.txt" ); - - 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) + std::vector<cmGeneratorExpressionEvaluationFile*> const& ef = + (*i)->GetMakefile()->GetEvaluationFiles(); + for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator + li = ef.begin(); li != ef.end(); ++li) { - knownDependencies.insert( ng->ConvertToNinjaPath( *j ) ); + //get all the files created by generator expressions and convert them + //to ninja paths + std::vector<std::string> evaluationFiles = (*li)->GetFiles(); + for(vect_it j = evaluationFiles.begin(); j != evaluationFiles.end(); ++j) + { + knownDependencies.insert( ng->ConvertToNinjaPath( *j ) ); + } } } + knownDependencies.insert( "CMakeCache.txt" ); for(TargetAliasMap::const_iterator i= this->TargetAliases.begin(); i != this->TargetAliases.end(); @@ -1260,7 +1268,7 @@ std::string cmGlobalNinjaGenerator::ninjaCmd() const return "ninja"; } -std::string cmGlobalNinjaGenerator::ninjaVersion() const +std::string cmGlobalNinjaGenerator::CurrentNinjaVersion() const { std::string version; std::string command = ninjaCmd() + " --version"; @@ -1268,13 +1276,14 @@ std::string cmGlobalNinjaGenerator::ninjaVersion() const &version, 0, 0, 0, cmSystemTools::OUTPUT_NONE); - return version; + return cmSystemTools::TrimWhitespace(version); } bool cmGlobalNinjaGenerator::SupportsConsolePool() const { return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, - ninjaVersion().c_str(), "1.5") == false; + CurrentNinjaVersion().c_str(), + RequiredNinjaVersionForConsolePool().c_str()) == false; } void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 2a749c1..f103801 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -289,7 +289,7 @@ public: const std::vector<cmLocalGenerator*>& GetLocalGenerators() const { return LocalGenerators; } - bool IsExcluded(cmLocalGenerator* root, cmTarget& target) { + bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) { return cmGlobalGenerator::IsExcluded(root, target); } int GetRuleCmdLength(const std::string& name) { @@ -299,8 +299,10 @@ public: virtual void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const; - std::string ninjaVersion() const; - + std::string CurrentNinjaVersion() const; + // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3 + static std::string RequiredNinjaVersion() { return "1.3"; } + static std::string RequiredNinjaVersionForConsolePool() { return "1.5"; } bool SupportsConsolePool() const; protected: diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index edf2705..76d059ee 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -482,7 +482,7 @@ cmGlobalUnixMakefileGenerator3 // Add this to the list of depends rules in this directory. if((!check_all || !gtarget->GetPropertyAsBool("EXCLUDE_FROM_ALL")) && (!check_relink || - gtarget->Target + gtarget ->NeedRelinkBeforeInstall(lg->GetConfigName()))) { std::string tname = lg->GetRelativeTargetDirectory(*gtarget->Target); @@ -691,7 +691,7 @@ cmGlobalUnixMakefileGenerator3 // Add a local name for the rule to relink the target before // installation. - if(gtarget->Target + if(gtarget ->NeedRelinkBeforeInstall(lg->GetConfigName())) { makeTargetName = lg->GetRelativeTargetDirectory(*gtarget->Target); @@ -821,7 +821,7 @@ cmGlobalUnixMakefileGenerator3 localName, depends, commands, true); // add the all/all dependency - if(!this->IsExcluded(this->LocalGenerators[0], *gtarget->Target)) + if(!this->IsExcluded(this->LocalGenerators[0], gtarget)) { depends.clear(); depends.push_back(localName); @@ -876,7 +876,7 @@ cmGlobalUnixMakefileGenerator3 name, depends, commands, true); // Add rules to prepare the target for installation. - if(gtarget->Target + if(gtarget ->NeedRelinkBeforeInstall(lg->GetConfigName())) { localName = lg->GetRelativeTargetDirectory(*gtarget->Target); @@ -889,7 +889,7 @@ cmGlobalUnixMakefileGenerator3 "Pre-install relink rule for target.", localName, depends, commands, true); - if(!this->IsExcluded(this->LocalGenerators[0], *gtarget->Target)) + if(!this->IsExcluded(this->LocalGenerators[0], gtarget)) { depends.clear(); depends.push_back(localName); diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 4e8ada4..8ec4fd9 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -314,9 +314,18 @@ cmGlobalVisualStudio10Generator::CreateLocalGenerator(cmLocalGenerator* parent, } //---------------------------------------------------------------------------- -void cmGlobalVisualStudio10Generator::Generate() +bool cmGlobalVisualStudio10Generator::Compute() { + if (!cmGlobalVisualStudio8Generator::Compute()) + { + return false; + } this->LongestSource = LongestSourcePath(); + return true; +} + +void cmGlobalVisualStudio10Generator::Generate() +{ this->cmGlobalVisualStudio8Generator::Generate(); if(this->LongestSource.Length > 0) { diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 74d5022..3d34a3f 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -45,6 +45,8 @@ public: std::vector<std::string> const& makeOptions = std::vector<std::string>() ); + virtual bool Compute(); + ///! create the correct local generator virtual cmLocalGenerator *CreateLocalGenerator(cmLocalGenerator* parent, cmState::Snapshot snapshot); diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index f3cf36e..51dcab0 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -254,6 +254,9 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false, no_working_directory, no_depends, noCommandLines); + tgt->Compute(); + cmGeneratorTarget* gt = new cmGeneratorTarget(tgt, lg); + mf->AddGeneratorTarget(tgt, gt); // Organize in the "predefined targets" folder: // @@ -345,8 +348,13 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() } //---------------------------------------------------------------------------- -void cmGlobalVisualStudio8Generator::Generate() +bool cmGlobalVisualStudio8Generator::Compute() { + if (!cmGlobalVisualStudio7Generator::Compute()) + { + return false; + } + if(this->AddCheckTarget()) { // All targets depend on the build-system check target. @@ -360,9 +368,7 @@ void cmGlobalVisualStudio8Generator::Generate() } } } - - // Now perform the main generation. - this->cmGlobalVisualStudio7Generator::Generate(); + return true; } //---------------------------------------------------------------------------- diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h index cc02b78..1c61103 100644 --- a/Source/cmGlobalVisualStudio8Generator.h +++ b/Source/cmGlobalVisualStudio8Generator.h @@ -67,7 +67,7 @@ public: return !this->WindowsCEVersion.empty(); } protected: - virtual void Generate(); + virtual bool Compute(); virtual const char* GetIDEVersion() { return "8.0"; } virtual std::string FindDevEnvCommand(); diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 1d583eb..c38a35a 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -64,8 +64,13 @@ std::string cmGlobalVisualStudioGenerator::GetRegistryBase( } //---------------------------------------------------------------------------- -void cmGlobalVisualStudioGenerator::Generate() +bool cmGlobalVisualStudioGenerator::Compute() { + if (!cmGlobalGenerator::Compute()) + { + return false; + } + // Add a special target that depends on ALL projects for easy build // of one configuration only. const char* no_working_dir = 0; @@ -85,6 +90,9 @@ void cmGlobalVisualStudioGenerator::Generate() AddUtilityCommand("ALL_BUILD", true, no_working_dir, no_depends, no_commands, false, "Build all projects"); + allBuild->Compute(); + cmGeneratorTarget* gt = new cmGeneratorTarget(allBuild, gen[0]); + allBuild->GetMakefile()->AddGeneratorTarget(allBuild, gt); #if 0 // Can't activate this code because we want ALL_BUILD @@ -104,13 +112,19 @@ void cmGlobalVisualStudioGenerator::Generate() for(std::vector<cmLocalGenerator*>::iterator i = gen.begin(); i != gen.end(); ++i) { - cmTargets& targets = (*i)->GetMakefile()->GetTargets(); - for(cmTargets::iterator t = targets.begin(); + cmGeneratorTargetsType targets = + (*i)->GetMakefile()->GetGeneratorTargets(); + for(cmGeneratorTargetsType::iterator t = targets.begin(); t != targets.end(); ++t) { + if (t->second->GetType() == cmTarget::GLOBAL_TARGET + || t->first->IsImported()) + { + continue; + } if(!this->IsExcluded(gen[0], t->second)) { - allBuild->AddUtility(t->second.GetName()); + allBuild->AddUtility(t->second->GetName()); } } } @@ -130,9 +144,7 @@ void cmGlobalVisualStudioGenerator::Generate() static_cast<cmLocalVisualStudioGenerator*>(*lgi); lg->AddCMakeListsRules(); } - - // Run all the local generators. - this->cmGlobalGenerator::Generate(); + return true; } //---------------------------------------------------------------------------- diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 8e2d6a4..64440ad 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -108,7 +108,7 @@ public: cmGeneratorTarget*, std::vector<cmCustomCommand>& commands, std::string const& configName); protected: - virtual void Generate(); + virtual bool Compute(); // Does this VS version link targets to each other if there are // dependencies in the SLN file? This was done for VS versions diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index ba5ff30..39933cb 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -378,8 +378,13 @@ cmGlobalXCodeGenerator::CreateLocalGenerator(cmLocalGenerator* parent, } //---------------------------------------------------------------------------- -void cmGlobalXCodeGenerator::Generate() +bool cmGlobalXCodeGenerator::Compute() { + if (!cmGlobalGenerator::Compute()) + { + return false; + } + std::map<std::string, std::vector<cmLocalGenerator*> >::iterator it; // make sure extra targets are added before calling // the parent generate which will call trace depends @@ -390,11 +395,17 @@ void cmGlobalXCodeGenerator::Generate() // add ALL_BUILD, INSTALL, etc this->AddExtraTargets(root, it->second); } + return true; +} + +void cmGlobalXCodeGenerator::Generate() +{ this->cmGlobalGenerator::Generate(); if(cmSystemTools::GetErrorOccuredFlag()) { return; } + std::map<std::string, std::vector<cmLocalGenerator*> >::iterator it; for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it) { cmLocalGenerator* root = it->second[0]; @@ -449,10 +460,12 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root, // Add ALL_BUILD const char* no_working_directory = 0; std::vector<std::string> no_depends; - mf->AddUtilityCommand("ALL_BUILD", true, no_depends, + cmTarget* allbuild = mf->AddUtilityCommand("ALL_BUILD", true, no_depends, no_working_directory, "echo", "Build all projects"); - cmTarget* allbuild = mf->FindTarget("ALL_BUILD"); + allbuild->Compute(); + cmGeneratorTarget* allBuildGt = new cmGeneratorTarget(allbuild, root); + mf->AddGeneratorTarget(allbuild, allBuildGt); // Refer to the main build configuration file for easy editing. std::string listfile = mf->GetCurrentSourceDirectory(); @@ -481,9 +494,13 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root, std::string file = this->ConvertToRelativeForMake( this->CurrentReRunCMakeMakefile.c_str()); cmSystemTools::ReplaceString(file, "\\ ", " "); - mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, true, no_depends, + cmTarget* check = mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, + true, no_depends, no_working_directory, "make", "-f", file.c_str()); + check->Compute(); + cmGeneratorTarget* checkGt = new cmGeneratorTarget(check, root); + mf->AddGeneratorTarget(check, checkGt); } // now make the allbuild depend on all the non-utility targets @@ -502,6 +519,11 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root, { cmTarget& target = l->second; + if (target.GetType() == cmTarget::GLOBAL_TARGET) + { + continue; + } + if (regenerate && (l->first != CMAKE_CHECK_BUILD_SYSTEM_TARGET)) { target.AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET); @@ -1356,7 +1378,8 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget) return; } - std::string llang = cmtarget.GetLinkerLanguage("NOCONFIG"); + cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&cmtarget); + std::string llang = gtgt->GetLinkerLanguage("NOCONFIG"); if(llang.empty()) { return; } // If the language is compiled as a source trust Xcode to link with it. @@ -1804,7 +1827,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, AddCompileOptions(flags, &target, lang, configName); } - std::string llang = target.GetLinkerLanguage(configName); + cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target); + std::string llang = gtgt->GetLinkerLanguage(configName); if(binary && llang.empty()) { cmSystemTools::Error @@ -1830,7 +1854,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, // Add the export symbol definition for shared library objects. this->AppendDefines(ppDefs, exportMacro); } - cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target); std::vector<std::string> targetDefines; target.GetCompileDefinitions(targetDefines, configName, "C"); this->AppendDefines(ppDefs, targetDefines); @@ -1920,11 +1943,11 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, std::string pnprefix; std::string pnbase; std::string pnsuffix; - target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName); + gtgt->GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName); const char* version = target.GetProperty("VERSION"); const char* soversion = target.GetProperty("SOVERSION"); - if(!target.HasSOName(configName) || target.IsFrameworkOnApple()) + if(!gtgt->HasSOName(configName) || target.IsFrameworkOnApple()) { version = 0; soversion = 0; @@ -2182,7 +2205,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, } } // Add framework search paths needed for linking. - if(cmComputeLinkInformation* cli = target.GetLinkInformation(configName)) + if(cmComputeLinkInformation* cli = gtgt->GetLinkInformation(configName)) { std::vector<std::string> const& fwDirs = cli->GetFrameworkPaths(); for(std::vector<std::string>::const_iterator fdi = fwDirs.begin(); @@ -2311,7 +2334,7 @@ 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); + install_name_dir = gtgt->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. @@ -2325,7 +2348,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, install_name += install_name_dir; install_name += "/"; } - install_name += target.GetSOName(configName); + install_name += gtgt->GetSOName(configName); if((realName != soName) || install_name_dir.empty()) { @@ -2338,7 +2361,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, this->CreateString(install_name_dir.c_str())); // Create the LD_RUNPATH_SEARCH_PATHS - cmComputeLinkInformation* pcli = target.GetLinkInformation(configName); + cmComputeLinkInformation* pcli = gtgt->GetLinkInformation(configName); if(pcli) { std::string search_paths; @@ -2722,7 +2745,8 @@ cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget, } else { - fullName = cmtarget.GetFullName(defConfig.c_str()); + cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&cmtarget); + fullName = gtgt->GetFullName(defConfig.c_str()); } fileRef->AddAttribute("path", this->CreateString(fullName.c_str())); fileRef->AddAttribute("refType", this->CreateString("0")); @@ -2944,7 +2968,8 @@ void cmGlobalXCodeGenerator } // Compute the link library and directory information. - cmComputeLinkInformation* pcli = cmtarget->GetLinkInformation(configName); + cmGeneratorTarget* gtgt = this->GetGeneratorTarget(cmtarget); + cmComputeLinkInformation* pcli = gtgt->GetLinkInformation(configName); if(!pcli) { continue; @@ -3667,7 +3692,7 @@ cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( std::string universalFile = universal; universalFile += *arch; universalFile += "/"; - universalFile += t->GetFullName(configName); + universalFile += gt->GetFullName(configName); makefileStream << "\t/bin/rm -f " << this->ConvertToRelativeForMake(universalFile.c_str()) diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index c36e4af..ee8bf2c 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -88,6 +88,7 @@ public: virtual bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf); void AppendFlag(std::string& flags, std::string const& flag); protected: + virtual bool Compute(); virtual void Generate(); private: cmXCodeObject* CreateOrGetPBXGroup(cmTarget& cmtarget, diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 899b088..f548f5d 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -27,7 +27,8 @@ static cmInstallTargetGenerator* CreateInstallTargetGenerator(cmTarget& target, { cmInstallGenerator::MessageLevel message = cmInstallGenerator::SelectMessageLevel(target.GetMakefile()); - return new cmInstallTargetGenerator(target, args.GetDestination().c_str(), + return new cmInstallTargetGenerator(target.GetName(), + args.GetDestination().c_str(), impLib, args.GetPermissions().c_str(), args.GetConfigurations(), args.GetComponent().c_str(), message, @@ -752,6 +753,12 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) installsPublicHeader = installsPublicHeader || publicHeaderGenerator != 0; installsResource = installsResource || resourceGenerator; + if (installsArchive || installsRuntime || installsFramework + || installsLibrary || installsBundle) + { + target.SetHaveInstallRule(true); + } + this->Makefile->AddInstallGenerator(archiveGenerator); this->Makefile->AddInstallGenerator(libraryGenerator); this->Makefile->AddInstallGenerator(runtimeGenerator); diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h index c4191e4..b8e5b53 100644 --- a/Source/cmInstallGenerator.h +++ b/Source/cmInstallGenerator.h @@ -62,6 +62,8 @@ public: /** Select message level from CMAKE_INSTALL_MESSAGE or 'never'. */ static MessageLevel SelectMessageLevel(cmMakefile* mf, bool never = false); + virtual void Compute(cmLocalGenerator*) {} + protected: virtual void GenerateScript(std::ostream& os); diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 5115788..30cf175 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -16,26 +16,30 @@ #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmGeneratorTarget.h" #include "cmake.h" +#include "cmGeneratorTarget.h" #include <assert.h> //---------------------------------------------------------------------------- cmInstallTargetGenerator -::cmInstallTargetGenerator(cmTarget& t, const char* dest, bool implib, +::cmInstallTargetGenerator(const std::string& targetName, + const char* dest, bool implib, const char* file_permissions, std::vector<std::string> const& configurations, const char* component, MessageLevel message, bool optional): - cmInstallGenerator(dest, configurations, component, message), Target(&t), + cmInstallGenerator(dest, configurations, component, message), + TargetName(targetName), + Target(0), FilePermissions(file_permissions), ImportLibrary(implib), Optional(optional) { this->ActionsPerConfig = true; this->NamelinkMode = NamelinkModeNone; - this->Target->SetHaveInstallRule(true); } //---------------------------------------------------------------------------- @@ -71,13 +75,15 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, std::string fromDirConfig; if(this->Target->NeedRelinkBeforeInstall(config)) { - fromDirConfig = this->Target->GetMakefile()->GetCurrentBinaryDirectory(); + fromDirConfig = + this->Target->Target->GetMakefile()->GetCurrentBinaryDirectory(); fromDirConfig += cmake::GetCMakeFilesDirectory(); fromDirConfig += "/CMakeRelink.dir/"; } else { - fromDirConfig = this->Target->GetDirectory(config, this->ImportLibrary); + fromDirConfig = + this->Target->Target->GetDirectory(config, this->ImportLibrary); fromDirConfig += "/"; } std::string toDir = @@ -88,7 +94,8 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, std::vector<std::string> filesFrom; std::vector<std::string> filesTo; std::string literal_args; - cmTarget::TargetType targetType = this->Target->GetType(); + cmTarget::TargetType targetType = + static_cast<cmTarget::TargetType>(this->Target->GetType()); cmInstallType type = cmInstallType(); switch(targetType) { @@ -105,7 +112,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, case cmTarget::UTILITY: case cmTarget::GLOBAL_TARGET: case cmTarget::UNKNOWN_LIBRARY: - this->Target->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR, + this->Target->Target->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR, "cmInstallTargetGenerator created with non-installable target."); return; } @@ -128,7 +135,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, filesFrom.push_back(from1); filesTo.push_back(to1); std::string targetNameImportLib; - if(this->Target->GetImplibGNUtoMS(targetNameImport, + if(this->Target->Target->GetImplibGNUtoMS(targetNameImport, targetNameImportLib)) { filesFrom.push_back(fromDirConfig + targetNameImportLib); @@ -144,7 +151,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, std::string to1 = toDir + targetName; // Handle OSX Bundles. - if(this->Target->IsAppBundleOnApple()) + if(this->Target->Target->IsAppBundleOnApple()) { // Install the whole app bundle directory. type = cmInstallType_DIRECTORY; @@ -178,7 +185,8 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, std::string targetNameReal; std::string targetNameImport; std::string targetNamePDB; - this->Target->GetLibraryNames(targetName, targetNameSO, targetNameReal, + this->Target->GetLibraryNames(targetName, targetNameSO, + targetNameReal, targetNameImport, targetNamePDB, config); if(this->ImportLibrary) @@ -191,7 +199,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, filesFrom.push_back(from1); filesTo.push_back(to1); std::string targetNameImportLib; - if(this->Target->GetImplibGNUtoMS(targetNameImport, + if(this->Target->Target->GetImplibGNUtoMS(targetNameImport, targetNameImportLib)) { filesFrom.push_back(fromDirConfig + targetNameImportLib); @@ -201,7 +209,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, // An import library looks like a static library. type = cmInstallType_STATIC_LIBRARY; } - else if(this->Target->IsFrameworkOnApple()) + else if(this->Target->Target->IsFrameworkOnApple()) { // There is a bug in cmInstallCommand if this fails. assert(this->NamelinkMode == NamelinkModeNone); @@ -219,7 +227,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, filesFrom.push_back(from1); filesTo.push_back(to1); } - else if(this->Target->IsCFBundleOnApple()) + else if(this->Target->Target->IsCFBundleOnApple()) { // Install the whole app bundle directory. type = cmInstallType_DIRECTORY; @@ -343,7 +351,7 @@ cmInstallTargetGenerator::GetDestination(std::string const& config) const { cmGeneratorExpression ge; return ge.Parse(this->Destination) - ->Evaluate(this->Target->GetMakefile(), config); + ->Evaluate(this->Target->Target->GetMakefile(), config); } //---------------------------------------------------------------------------- @@ -352,7 +360,7 @@ cmInstallTargetGenerator::GetInstallFilename(const std::string& config) const { NameType nameType = this->ImportLibrary? NameImplib : NameNormal; return - cmInstallTargetGenerator::GetInstallFilename(this->Target, config, + cmInstallTargetGenerator::GetInstallFilename(this->Target->Target, config, nameType); } @@ -364,13 +372,16 @@ cmInstallTargetGenerator::GetInstallFilename(cmTarget const* target, { std::string fname; // Compute the name of the library. + cmGeneratorTarget *gtgt = target->GetMakefile() + ->GetGlobalGenerator() + ->GetGeneratorTarget(target); if(target->GetType() == cmTarget::EXECUTABLE) { std::string targetName; std::string targetNameReal; std::string targetNameImport; std::string targetNamePDB; - target->GetExecutableNames(targetName, targetNameReal, + gtgt->GetExecutableNames(targetName, targetNameReal, targetNameImport, targetNamePDB, config); if(nameType == NameImplib) @@ -400,7 +411,7 @@ cmInstallTargetGenerator::GetInstallFilename(cmTarget const* target, std::string targetNameReal; std::string targetNameImport; std::string targetNamePDB; - target->GetLibraryNames(targetName, targetNameSO, targetNameReal, + gtgt->GetLibraryNames(targetName, targetNameSO, targetNameReal, targetNameImport, targetNamePDB, config); if(nameType == NameImplib) { @@ -431,6 +442,12 @@ cmInstallTargetGenerator::GetInstallFilename(cmTarget const* target, return fname; } +void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg) +{ + this->Target = lg->GetGlobalGenerator()->GetGeneratorTarget( + lg->GetMakefile()->FindTarget(this->TargetName)); +} + //---------------------------------------------------------------------------- void cmInstallTargetGenerator @@ -533,8 +550,8 @@ cmInstallTargetGenerator } // Fix the install_name settings in installed binaries. - std::string installNameTool = - this->Target->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL"); + std::string installNameTool = this->Target->Target->GetMakefile() + ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL"); if(installNameTool.empty()) { @@ -559,11 +576,14 @@ cmInstallTargetGenerator continue; } + cmGeneratorTarget *gtgt = tgt->GetMakefile() + ->GetGlobalGenerator() + ->GetGeneratorTarget(tgt); // If the build tree and install tree use different path // 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(); + std::string for_build = gtgt->GetInstallNameDirForBuildTree(config); + std::string for_install = gtgt->GetInstallNameDirForInstallTree(); if(for_build != for_install) { // The directory portions differ. Append the filename to @@ -592,7 +612,7 @@ cmInstallTargetGenerator std::string for_install = this->Target->GetInstallNameDirForInstallTree(); - if(this->Target->IsFrameworkOnApple() && for_install.empty()) + if(this->Target->Target->IsFrameworkOnApple() && for_install.empty()) { // Frameworks seem to have an id corresponding to their own full // path. @@ -606,7 +626,7 @@ cmInstallTargetGenerator { // Prepare to refer to the install-tree install_name. new_id = for_install; - new_id += this->GetInstallFilename(this->Target, config, NameSO); + new_id += this->GetInstallFilename(this->Target->Target, config, NameSO); } } @@ -643,9 +663,9 @@ cmInstallTargetGenerator { return; } - // Skip if on Apple - if(this->Target->GetMakefile()->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) + if(this->Target->Target->GetMakefile() + ->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { return; } @@ -690,7 +710,7 @@ cmInstallTargetGenerator return; } - cmMakefile* mf = this->Target->GetMakefile(); + cmMakefile* mf = this->Target->Target->GetMakefile(); if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { @@ -802,20 +822,20 @@ cmInstallTargetGenerator::AddStripRule(std::ostream& os, } // Don't handle OSX Bundles. - if(this->Target->GetMakefile()->IsOn("APPLE") && - this->Target->GetPropertyAsBool("MACOSX_BUNDLE")) + if(this->Target->Target->GetMakefile()->IsOn("APPLE") && + this->Target->Target->GetPropertyAsBool("MACOSX_BUNDLE")) { return; } - if(! this->Target->GetMakefile()->IsSet("CMAKE_STRIP")) + if(! this->Target->Target->GetMakefile()->IsSet("CMAKE_STRIP")) { return; } os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n"; os << indent << " execute_process(COMMAND \"" - << this->Target->GetMakefile()->GetDefinition("CMAKE_STRIP") + << this->Target->Target->GetMakefile()->GetDefinition("CMAKE_STRIP") << "\" \"" << toDestDirPath << "\")\n"; os << indent << "endif()\n"; } @@ -834,13 +854,13 @@ cmInstallTargetGenerator::AddRanlibRule(std::ostream& os, // Perform post-installation processing on the file depending // on its type. - if(!this->Target->GetMakefile()->IsOn("APPLE")) + if(!this->Target->Target->GetMakefile()->IsOn("APPLE")) { return; } std::string ranlib = - this->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB"); + this->Target->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB"); if(ranlib.empty()) { return; diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index db69220..a8f4a75 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -13,7 +13,9 @@ #define cmInstallTargetGenerator_h #include "cmInstallGenerator.h" -#include "cmTarget.h" + +class cmTarget; +class cmGeneratorTarget; /** \class cmInstallTargetGenerator * \brief Generate target installation rules. @@ -22,7 +24,7 @@ class cmInstallTargetGenerator: public cmInstallGenerator { public: cmInstallTargetGenerator( - cmTarget& t, const char* dest, bool implib, + std::string const& targetName, const char* dest, bool implib, const char* file_permissions, std::vector<std::string> const& configurations, const char* component, @@ -56,7 +58,10 @@ public: const std::string& config, NameType nameType = NameNormal); - cmTarget* GetTarget() const { return this->Target; } + void Compute(cmLocalGenerator* lg); + + cmGeneratorTarget* GetTarget() const { return this->Target; } + bool IsImportLibrary() const { return this->ImportLibrary; } std::string GetDestination(std::string const& config) const; @@ -98,7 +103,8 @@ protected: void AddRanlibRule(std::ostream& os, Indent const& indent, const std::string& toDestDirPath); - cmTarget* Target; + std::string TargetName; + cmGeneratorTarget* Target; std::string FilePermissions; NamelinkModeType NamelinkMode; bool ImportLibrary; diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h new file mode 100644 index 0000000..a5427de --- /dev/null +++ b/Source/cmLinkItem.h @@ -0,0 +1,59 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2004-2015 Kitware, Inc. + + 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 cmLinkItem_h +#define cmLinkItem_h + +#include "cmListFileCache.h" + +class cmTarget; + +// Basic information about each link item. +class cmLinkItem: public std::string +{ + typedef std::string std_string; +public: + cmLinkItem(): std_string(), Target(0) {} + cmLinkItem(const std_string& n, + cmTarget const* t): std_string(n), Target(t) {} + cmLinkItem(cmLinkItem const& r): std_string(r), Target(r.Target) {} + cmTarget const* Target; +}; + +class cmLinkImplItem: public cmLinkItem +{ +public: + cmLinkImplItem(): cmLinkItem(), Backtrace(), FromGenex(false) {} + cmLinkImplItem(std::string const& n, + cmTarget const* t, + cmListFileBacktrace const& bt, + bool fromGenex): + cmLinkItem(n, t), Backtrace(bt), FromGenex(fromGenex) {} + cmLinkImplItem(cmLinkImplItem const& r): + cmLinkItem(r), Backtrace(r.Backtrace), FromGenex(r.FromGenex) {} + cmListFileBacktrace Backtrace; + bool FromGenex; +}; + +/** The link implementation specifies the direct library + dependencies needed by the object files of the target. */ +struct cmLinkImplementationLibraries +{ + // Libraries linked directly in this configuration. + std::vector<cmLinkImplItem> Libraries; + + // Libraries linked directly in other configurations. + // Needed only for OLD behavior of CMP0003. + std::vector<cmLinkItem> WrongConfigLibraries; +}; + +#endif diff --git a/Source/cmLinkedTree.h b/Source/cmLinkedTree.h index df00b30..3bcb940 100644 --- a/Source/cmLinkedTree.h +++ b/Source/cmLinkedTree.h @@ -155,6 +155,12 @@ public: return iterator(this, 1); } + void Clear() + { + this->UpPositions.clear(); + this->Data.clear(); + } + private: T& GetReference(PositionType pos) { diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2e20ee2..a831d88 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -16,6 +16,7 @@ #include "cmGlobalGenerator.h" #include "cmInstallGenerator.h" #include "cmInstallFilesGenerator.h" +#include "cmGeneratorExpressionEvaluationFile.h" #include "cmInstallScriptGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmMakefile.h" @@ -212,6 +213,53 @@ void cmLocalGenerator::GenerateTestFiles() } } +void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config) +{ + std::vector<cmGeneratorExpressionEvaluationFile*> ef = + this->Makefile->GetEvaluationFiles(); + for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator + li = ef.begin(); li != ef.end(); ++li) + { + (*li)->CreateOutputFile(this, config); + } +} + +void cmLocalGenerator::ProcessEvaluationFiles( + std::vector<std::string>& generatedFiles) +{ + std::vector<cmGeneratorExpressionEvaluationFile*> ef = + this->Makefile->GetEvaluationFiles(); + for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator + li = ef.begin(); + li != ef.end(); + ++li) + { + (*li)->Generate(this); + if (cmSystemTools::GetFatalErrorOccured()) + { + return; + } + std::vector<std::string> files = (*li)->GetFiles(); + std::sort(files.begin(), files.end()); + + std::vector<std::string> intersection; + std::set_intersection(files.begin(), files.end(), + generatedFiles.begin(), generatedFiles.end(), + std::back_inserter(intersection)); + if (!intersection.empty()) + { + cmSystemTools::Error("Files to be generated by multiple different " + "commands: ", cmWrap('"', intersection, '"', " ").c_str()); + return; + } + + generatedFiles.insert(generatedFiles.end(), files.begin(), files.end()); + std::vector<std::string>::iterator newIt = + generatedFiles.end() - files.size(); + std::inplace_merge(generatedFiles.begin(), newIt, generatedFiles.end()); + } +} + //---------------------------------------------------------------------------- void cmLocalGenerator::GenerateInstallRules() { @@ -1353,7 +1401,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, linkFlags += this->Makefile->GetSafeDefinition(build); linkFlags += " "; } - std::string linkLanguage = target->Target->GetLinkerLanguage(buildType); + std::string linkLanguage = target->GetLinkerLanguage(buildType); if(linkLanguage.empty()) { cmSystemTools::Error @@ -1468,7 +1516,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, bool escapeAllowMakeVars = !forResponseFile; std::ostringstream fout; std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); - cmComputeLinkInformation* pcli = tgt.Target->GetLinkInformation(config); + cmComputeLinkInformation* pcli = tgt.GetLinkInformation(config); if(!pcli) { return; @@ -2059,7 +2107,9 @@ void cmLocalGenerator::AddCMP0018Flags(std::string &flags, return; } - if (target->GetLinkInterfaceDependentBoolProperty( + cmGeneratorTarget* gtgt = + this->GlobalGenerator->GetGeneratorTarget(target); + if (gtgt->GetLinkInterfaceDependentBoolProperty( "POSITION_INDEPENDENT_CODE", config)) { @@ -2375,11 +2425,15 @@ cmLocalGenerator::ConstructComment(cmCustomCommandGenerator const& ccg, class cmInstallTargetGeneratorLocal: public cmInstallTargetGenerator { public: - cmInstallTargetGeneratorLocal(cmTarget& t, const char* dest, bool implib): + cmInstallTargetGeneratorLocal(cmLocalGenerator* lg, std::string const& t, + const char* dest, bool implib): cmInstallTargetGenerator( t, dest, implib, "", std::vector<std::string>(), "Unspecified", - cmInstallGenerator::SelectMessageLevel(t.GetMakefile()), - false) {} + cmInstallGenerator::SelectMessageLevel(lg->GetMakefile()), + false) + { + this->Compute(lg); + } }; //---------------------------------------------------------------------------- @@ -2428,7 +2482,7 @@ cmLocalGenerator { // Use a target install generator. cmInstallTargetGeneratorLocal - g(l->second, destination.c_str(), false); + g(this, l->first, destination.c_str(), false); g.Generate(os, config, configurationTypes); } break; @@ -2439,18 +2493,18 @@ cmLocalGenerator // to the normal destination and the DLL to the runtime // destination. cmInstallTargetGeneratorLocal - g1(l->second, destination.c_str(), true); + g1(this, l->first, destination.c_str(), true); g1.Generate(os, config, configurationTypes); // We also skip over the leading slash given by the user. destination = l->second.GetRuntimeInstallPath().substr(1); cmSystemTools::ConvertToUnixSlashes(destination); cmInstallTargetGeneratorLocal - g2(l->second, destination.c_str(), false); + g2(this, l->first, destination.c_str(), false); g2.Generate(os, config, configurationTypes); #else // Use a target install generator. cmInstallTargetGeneratorLocal - g(l->second, destination.c_str(), false); + g(this, l->first, destination.c_str(), false); g.Generate(os, config, configurationTypes); #endif } diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 2971574..1c18788 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -305,6 +305,8 @@ public: void IssueMessage(cmake::MessageType t, std::string const& text) const; + void CreateEvaluationFileOutputs(const std::string& config); + void ProcessEvaluationFiles(std::vector<std::string>& generatedFiles); void ComputeObjectMaxPath(); protected: diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 9889bd4..cfca418 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -90,7 +90,7 @@ void cmLocalNinjaGenerator::Generate() // Add the target to "all" if required. if (!this->GetGlobalNinjaGenerator()->IsExcluded( this->GetGlobalNinjaGenerator()->GetLocalGenerators()[0], - *t->second->Target)) + t->second)) this->GetGlobalNinjaGenerator()->AddDependencyToAll(t->second->Target); delete tg; } @@ -193,16 +193,14 @@ void cmLocalNinjaGenerator::WriteProjectHeader(std::ostream& os) void cmLocalNinjaGenerator::WriteNinjaRequiredVersion(std::ostream& os) { // Default required version - // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3 - std::string requiredVersion = "1.3"; + std::string requiredVersion = + this->GetGlobalNinjaGenerator()->RequiredNinjaVersion(); // Ninja generator uses the 'console' pool if available (>= 1.5) - std::string usedVersion = this->GetGlobalNinjaGenerator()->ninjaVersion(); - if(cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, - usedVersion.c_str(), - "1.5") == false) + if(this->GetGlobalNinjaGenerator()->SupportsConsolePool()) { - requiredVersion = "1.5"; + requiredVersion = + this->GetGlobalNinjaGenerator()->RequiredNinjaVersionForConsolePool(); } cmGlobalNinjaGenerator::WriteComment(os, diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 98bd0ab..ce370bc 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -486,8 +486,7 @@ void cmLocalUnixMakefileGenerator3 // Add a local name for the rule to relink the target before // installation. - if(t->second->Target - ->NeedRelinkBeforeInstall(this->ConfigName)) + if(t->second->NeedRelinkBeforeInstall(this->ConfigName)) { makeTargetName = this->GetRelativeTargetDirectory(*t->second->Target); makeTargetName += "/preinstall"; diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index f1c8def..29e1034 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -88,7 +88,8 @@ void cmLocalVisualStudio6Generator::AddCMakeListsRules() for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) { - if (l->second.GetType() == cmTarget::INTERFACE_LIBRARY) + if (l->second.GetType() == cmTarget::INTERFACE_LIBRARY + || l->second.GetType() == cmTarget::GLOBAL_TARGET) { continue; } @@ -1114,10 +1115,12 @@ void cmLocalVisualStudio6Generator cmTarget* tgt = this->GlobalGenerator->FindTarget(j->first.c_str()); if(tgt) { + cmGeneratorTarget* gt = + this->GlobalGenerator->GetGeneratorTarget(tgt); lib = cmSystemTools::GetFilenameWithoutExtension - (tgt->GetFullName().c_str()); + (gt->GetFullName().c_str()); libDebug = cmSystemTools::GetFilenameWithoutExtension - (tgt->GetFullName("Debug").c_str()); + (gt->GetFullName("Debug").c_str()); lib += ".lib"; libDebug += ".lib"; } @@ -1257,8 +1260,8 @@ void cmLocalVisualStudio6Generator extraLinkOptionsRelWithDebInfo += targetLinkFlags; } - - + cmGeneratorTarget* gt = + this->GlobalGenerator->GetGeneratorTarget(&target); // Get standard libraries for this language. if(targetBuilds) @@ -1267,10 +1270,10 @@ void cmLocalVisualStudio6Generator std::vector<std::string> configs; target.GetMakefile()->GetConfigurations(configs); std::vector<std::string>::const_iterator it = configs.begin(); - const std::string& linkLanguage = target.GetLinkerLanguage(*it); + const std::string& linkLanguage = gt->GetLinkerLanguage(*it); for ( ; it != configs.end(); ++it) { - const std::string& configLinkLanguage = target.GetLinkerLanguage(*it); + const std::string& configLinkLanguage = gt->GetLinkerLanguage(*it); if (configLinkLanguage != linkLanguage) { cmSystemTools::Error @@ -1327,11 +1330,11 @@ void cmLocalVisualStudio6Generator target.GetType() == cmTarget::SHARED_LIBRARY || target.GetType() == cmTarget::MODULE_LIBRARY) { - outputName = target.GetFullName(); - outputNameDebug = target.GetFullName("Debug"); - outputNameRelease = target.GetFullName("Release"); - outputNameMinSizeRel = target.GetFullName("MinSizeRel"); - outputNameRelWithDebInfo = target.GetFullName("RelWithDebInfo"); + outputName = gt->GetFullName(); + outputNameDebug = gt->GetFullName("Debug"); + outputNameRelease = gt->GetFullName("Release"); + outputNameMinSizeRel = gt->GetFullName("MinSizeRel"); + outputNameRelWithDebInfo = gt->GetFullName("RelWithDebInfo"); } else if(target.GetType() == cmTarget::OBJECT_LIBRARY) { @@ -1428,10 +1431,10 @@ void cmLocalVisualStudio6Generator fullPathImpRelease += "/"; fullPathImpMinSizeRel += "/"; fullPathImpRelWithDebInfo += "/"; - fullPathImpDebug += target.GetFullName("Debug", true); - fullPathImpRelease += target.GetFullName("Release", true); - fullPathImpMinSizeRel += target.GetFullName("MinSizeRel", true); - fullPathImpRelWithDebInfo += target.GetFullName("RelWithDebInfo", true); + fullPathImpDebug += gt->GetFullName("Debug", true); + fullPathImpRelease += gt->GetFullName("Release", true); + fullPathImpMinSizeRel += gt->GetFullName("MinSizeRel", true); + fullPathImpRelWithDebInfo += gt->GetFullName("RelWithDebInfo", true); targetImplibFlagDebug = "/implib:"; targetImplibFlagRelease = "/implib:"; @@ -1700,10 +1703,10 @@ void cmLocalVisualStudio6Generator std::vector<std::string> configs; target.GetMakefile()->GetConfigurations(configs); std::vector<std::string>::const_iterator it = configs.begin(); - const std::string& linkLanguage = target.GetLinkerLanguage(*it); + const std::string& linkLanguage = gt->GetLinkerLanguage(*it); for ( ; it != configs.end(); ++it) { - const std::string& configLinkLanguage = target.GetLinkerLanguage(*it); + const std::string& configLinkLanguage = gt->GetLinkerLanguage(*it); if (configLinkLanguage != linkLanguage) { cmSystemTools::Error @@ -1845,8 +1848,10 @@ void cmLocalVisualStudio6Generator const std::string extraOptions, std::string& options) { + cmGeneratorTarget* gt = + this->GlobalGenerator->GetGeneratorTarget(&target); // Compute the link information for this configuration. - cmComputeLinkInformation* pcli = target.GetLinkInformation(configName); + cmComputeLinkInformation* pcli = gt->GetLinkInformation(configName); if(!pcli) { return; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index f199a41..a38a061 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -108,6 +108,10 @@ void cmLocalVisualStudio7Generator::AddCMakeListsRules() // Add the rule to targets that need it. for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); ++l) { + if (l->second.GetType() == cmTarget::GLOBAL_TARGET) + { + continue; + } if(l->first != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { l->second.AddSource(sf->GetFullPath()); @@ -660,6 +664,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, const char* configType = "10"; const char* projectType = 0; bool targetBuilds = true; + + cmGeneratorTarget* gt = + this->GlobalGenerator->GetGeneratorTarget(&target); + switch(target.GetType()) { case cmTarget::OBJECT_LIBRARY: @@ -692,7 +700,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, { const std::string& linkLanguage = (this->FortranProject? std::string("Fortran"): - target.GetLinkerLanguage(configName)); + gt->GetLinkerLanguage(configName)); if(linkLanguage.empty()) { cmSystemTools::Error @@ -754,8 +762,6 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, targetOptions.Parse(flags.c_str()); targetOptions.Parse(defineFlags.c_str()); targetOptions.ParseFinish(); - cmGeneratorTarget* gt = - this->GlobalGenerator->GetGeneratorTarget(&target); std::vector<std::string> targetDefines; target.GetCompileDefinitions(targetDefines, configName, "CXX"); targetOptions.AddDefines(targetDefines); @@ -799,7 +805,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, if (this->FortranProject) { // Intel Fortran >= 15.0 uses TargetName property. - std::string targetNameFull = target.GetFullName(configName); + std::string targetNameFull = gt->GetFullName(configName); std::string targetName = cmSystemTools::GetFilenameWithoutLastExtension(targetNameFull); std::string targetExt = @@ -877,7 +883,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, if(target.GetType() <= cmTarget::OBJECT_LIBRARY) { // Specify the compiler program database file if configured. - std::string pdb = target.GetCompilePDBPath(configName); + std::string pdb = gt->GetCompilePDBPath(configName); if(!pdb.empty()) { fout << "\t\t\t\tProgramDataBaseFileName=\"" @@ -1070,6 +1076,9 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, this->ConvertToOutputFormat(this->ModuleDefinitionFile, SHELL); linkOptions.AddFlag("ModuleDefinitionFile", defFile.c_str()); } + cmGeneratorTarget* gt = + this->GlobalGenerator->GetGeneratorTarget(&target); + if (target.GetType() == cmTarget::SHARED_LIBRARY && this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) { @@ -1100,7 +1109,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, } case cmTarget::STATIC_LIBRARY: { - std::string targetNameFull = target.GetFullName(configName); + std::string targetNameFull = gt->GetFullName(configName); std::string libpath = target.GetDirectory(configName); libpath += "/"; libpath += targetNameFull; @@ -1140,11 +1149,11 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, std::string targetNameFull; std::string targetNameImport; std::string targetNamePDB; - target.GetLibraryNames(targetName, targetNameSO, targetNameFull, + gt->GetLibraryNames(targetName, targetNameSO, targetNameFull, targetNameImport, targetNamePDB, configName); // Compute the link library and directory information. - cmComputeLinkInformation* pcli = target.GetLinkInformation(configName); + cmComputeLinkInformation* pcli = gt->GetLinkInformation(configName); if(!pcli) { return; @@ -1237,11 +1246,11 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, std::string targetNameFull; std::string targetNameImport; std::string targetNamePDB; - target.GetExecutableNames(targetName, targetNameFull, + gt->GetExecutableNames(targetName, targetNameFull, targetNameImport, targetNamePDB, configName); // Compute the link library and directory information. - cmComputeLinkInformation* pcli = target.GetLinkInformation(configName); + cmComputeLinkInformation* pcli = gt->GetLinkInformation(configName); if(!pcli) { return; @@ -1628,7 +1637,7 @@ cmLocalVisualStudio7GeneratorFCInfo lg->GlobalGenerator->GetLanguageFromExtension (sf.GetExtension().c_str()); const std::string& sourceLang = lg->GetSourceFileLanguage(sf); - const std::string& linkLanguage = target.GetLinkerLanguage(i->c_str()); + const std::string& linkLanguage = gt->GetLinkerLanguage(i->c_str()); bool needForceLang = false; // source file does not match its extension language if(lang != sourceLang) diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 57e33df..85bc493 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -21,6 +21,7 @@ #include "cmState.h" #include "cmOutputConverter.h" #include "cmFunctionBlocker.h" +#include "cmGeneratorExpressionEvaluationFile.h" #include "cmListFileCache.h" #include "cmCommandArgumentParserHelper.h" #include "cmGeneratorExpression.h" @@ -189,12 +190,12 @@ cmMakefile::cmMakefile(cmLocalGenerator* localGenerator) this->cmAtVarRegex.compile("(@[A-Za-z_0-9/.+-]+@)"); this->cmNamedCurly.compile("^[A-Za-z0-9/_.+-]+{"); + this->StateSnapshot = this->StateSnapshot.GetState() + ->CreatePolicyScopeSnapshot(this->StateSnapshot); + // Enter a policy level for this directory. this->PushPolicy(); - // Protect the directory-level policies. - this->PushPolicyBarrier(); - // push empty loop block this->PushLoopBlockBarrier(); @@ -235,12 +236,10 @@ cmMakefile::~cmMakefile() cmDeleteAll(this->ImportedTargetsOwned); cmDeleteAll(this->FinalPassCommands); cmDeleteAll(this->FunctionBlockers); + cmDeleteAll(this->EvaluationFiles); + this->EvaluationFiles.clear(); + this->FunctionBlockers.clear(); - if (this->PolicyStack.size() != 1) - { - cmSystemTools::Error("Internal CMake Error, Policy Stack has not been" - " popped properly"); - } } //---------------------------------------------------------------------------- @@ -468,6 +467,14 @@ cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf, Makefile(mf), NoPolicyScope(noPolicyScope), CheckCMP0011(false), ReportError(true) { + this->Makefile->PushFunctionBlockerBarrier(); + + this->Makefile->StateSnapshot = + this->Makefile->GetState()->CreateCallStackSnapshot( + this->Makefile->StateSnapshot, + this->Makefile->ContextStack.back()->Name, + this->Makefile->ContextStack.back()->Line, + filenametoread); if(!this->NoPolicyScope) { // Check CMP0011 to determine the policy scope type. @@ -496,37 +503,19 @@ cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf, break; } } - - // The included file cannot pop our policy scope. - this->Makefile->PushPolicyBarrier(); - this->Makefile->PushFunctionBlockerBarrier(); - - this->Makefile->StateSnapshot = - this->Makefile->GetState()->CreateCallStackSnapshot( - this->Makefile->StateSnapshot, - this->Makefile->ContextStack.back()->Name, - this->Makefile->ContextStack.back()->Line, - filenametoread); } //---------------------------------------------------------------------------- cmMakefile::IncludeScope::~IncludeScope() { - this->Makefile->StateSnapshot = - this->Makefile->GetState()->Pop(this->Makefile->StateSnapshot); - assert(this->Makefile->StateSnapshot.IsValid()); - - this->Makefile->PopFunctionBlockerBarrier(this->ReportError); - // Enforce matching policy scopes inside the included file. - this->Makefile->PopPolicyBarrier(this->ReportError); - if(!this->NoPolicyScope) { // If we need to enforce policy CMP0011 then the top entry is the // one we pushed above. If the entry is empty, then the included // script did not set any policies that might affect the includer so // we do not need to enforce the policy. - if(this->CheckCMP0011 && this->Makefile->PolicyStack.back().IsEmpty()) + if(this->CheckCMP0011 + && !this->Makefile->StateSnapshot.HasDefinedPolicyCMP0011()) { this->CheckCMP0011 = false; } @@ -541,6 +530,9 @@ cmMakefile::IncludeScope::~IncludeScope() this->EnforceCMP0011(); } } + this->Makefile->PopPolicyBarrier(this->ReportError); + + this->Makefile->PopFunctionBlockerBarrier(this->ReportError); } //---------------------------------------------------------------------------- @@ -635,8 +627,6 @@ public: ListFileScope(cmMakefile* mf, std::string const& filenametoread) : Makefile(mf), ReportError(true) { - this->Makefile->PushPolicyBarrier(); - long line = 0; std::string name; if (!this->Makefile->ContextStack.empty()) @@ -648,17 +638,14 @@ public: this->Makefile->GetState()->CreateInlineListFileSnapshot( this->Makefile->StateSnapshot, name, line, filenametoread); assert(this->Makefile->StateSnapshot.IsValid()); + this->Makefile->PushFunctionBlockerBarrier(); } ~ListFileScope() { - this->Makefile->StateSnapshot = - this->Makefile->GetState()->Pop(this->Makefile->StateSnapshot); - assert(this->Makefile->StateSnapshot.IsValid()); - - this->Makefile->PopFunctionBlockerBarrier(this->ReportError); this->Makefile->PopPolicyBarrier(this->ReportError); + this->Makefile->PopFunctionBlockerBarrier(this->ReportError); } void Quiet() { this->ReportError = false; } @@ -777,6 +764,23 @@ void cmMakefile::EnforceDirectoryLevelRules() const } } +void cmMakefile::AddEvaluationFile(const std::string& inputFile, + cmsys::auto_ptr<cmCompiledGeneratorExpression> outputName, + cmsys::auto_ptr<cmCompiledGeneratorExpression> condition, + bool inputIsContent) +{ + this->EvaluationFiles.push_back( + new cmGeneratorExpressionEvaluationFile(inputFile, outputName, + condition, + inputIsContent)); +} + +std::vector<cmGeneratorExpressionEvaluationFile*> +cmMakefile::GetEvaluationFiles() const +{ + return this->EvaluationFiles; +} + namespace { struct file_not_persistent @@ -1205,15 +1209,16 @@ cmMakefile::AddCustomCommandOldStyle(const std::string& target, } //---------------------------------------------------------------------------- -void cmMakefile::AddUtilityCommand(const std::string& utilityName, - bool excludeFromAll, - const std::vector<std::string>& depends, - const char* workingDirectory, - const char* command, - const char* arg1, - const char* arg2, - const char* arg3, - const char* arg4) +cmTarget* +cmMakefile::AddUtilityCommand(const std::string& utilityName, + bool excludeFromAll, + const std::vector<std::string>& depends, + const char* workingDirectory, + const char* command, + const char* arg1, + const char* arg2, + const char* arg3, + const char* arg4) { // Construct the command line for the custom command. cmCustomCommandLine commandLine; @@ -1238,8 +1243,8 @@ void cmMakefile::AddUtilityCommand(const std::string& utilityName, commandLines.push_back(commandLine); // Call the real signature of this method. - this->AddUtilityCommand(utilityName, excludeFromAll, workingDirectory, - depends, commandLines); + return this->AddUtilityCommand(utilityName, excludeFromAll, workingDirectory, + depends, commandLines); } //---------------------------------------------------------------------------- @@ -1640,16 +1645,13 @@ void cmMakefile::PushFunctionScope(std::string const& fileName, this->PushFunctionBlockerBarrier(); this->PushPolicy(true, pm); - this->PushPolicyBarrier(); } void cmMakefile::PopFunctionScope(bool reportError) { - this->PopPolicyBarrier(reportError); this->PopPolicy(); - this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot); - assert(this->StateSnapshot.IsValid()); + this->PopPolicyBarrier(reportError); this->PopFunctionBlockerBarrier(reportError); @@ -1677,16 +1679,12 @@ void cmMakefile::PushMacroScope(std::string const& fileName, this->PushFunctionBlockerBarrier(); this->PushPolicy(true, pm); - this->PushPolicyBarrier(); } void cmMakefile::PopMacroScope(bool reportError) { - this->PopPolicyBarrier(reportError); this->PopPolicy(); - - this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot); - assert(this->StateSnapshot.IsValid()); + this->PopPolicyBarrier(reportError); this->PopFunctionBlockerBarrier(reportError); } @@ -1706,7 +1704,8 @@ public: this->Makefile->StateSnapshot.GetDirectory().GetCurrentSource(); currentStart += "/CMakeLists.txt"; this->Makefile->StateSnapshot.SetListFile(currentStart); - this->Makefile->PushPolicyBarrier(); + this->Makefile->StateSnapshot = this->Makefile->StateSnapshot.GetState() + ->CreatePolicyScopeSnapshot(this->Makefile->StateSnapshot); this->Makefile->PushFunctionBlockerBarrier(); this->GG = mf->GetGlobalGenerator(); @@ -1795,8 +1794,8 @@ void cmMakefile::ConfigureSubDirectory(cmMakefile *mf) cmSystemTools::Message(msg.c_str()); } - currentStart += "/CMakeLists.txt"; - if(!cmSystemTools::FileExists(currentStart.c_str(), true)) + std::string const currentStartFile = currentStart + "/CMakeLists.txt"; + if (!cmSystemTools::FileExists(currentStartFile, true)) { // The file is missing. Check policy CMP0014. std::ostringstream e; @@ -1858,6 +1857,7 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath, // create a new local generator and set its parent cmLocalGenerator *lg2 = this->GetGlobalGenerator() ->MakeLocalGenerator(newSnapshot, this->LocalGenerator); + this->GetGlobalGenerator()->AddMakefile(lg2->GetMakefile()); this->GetGlobalGenerator()->AddLocalGenerator(lg2); cmMakefile* subMf = lg2->GetMakefile(); @@ -1905,6 +1905,12 @@ const char* cmMakefile::GetCurrentBinaryDirectory() const return this->StateSnapshot.GetDirectory().GetCurrentBinary(); } +void cmMakefile::AddGeneratorTarget(cmTarget* t, cmGeneratorTarget* gt) +{ + this->GeneratorTargets[t] = gt; + this->GetGlobalGenerator()->AddGeneratorTarget(t, gt); +} + //---------------------------------------------------------------------------- void cmMakefile::AddIncludeDirectories(const std::vector<std::string> &incs, bool before) @@ -4747,30 +4753,7 @@ const char* cmMakefile::GetDefineFlagsCMP0059() const cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(cmPolicies::PolicyID id) const { - cmPolicies::PolicyStatus status = cmPolicies::GetPolicyStatus(id); - - if(status == cmPolicies::REQUIRED_ALWAYS || - status == cmPolicies::REQUIRED_IF_USED) - { - return status; - } - - cmLocalGenerator* lg = this->LocalGenerator; - while(lg) - { - cmMakefile const* mf = lg->GetMakefile(); - for(PolicyStackType::const_reverse_iterator psi = - mf->PolicyStack.rbegin(); psi != mf->PolicyStack.rend(); ++psi) - { - if(psi->IsDefined(id)) - { - status = psi->Get(id); - return status; - } - } - lg = lg->GetParent(); - } - return status; + return this->StateSnapshot.GetPolicy(id); } //---------------------------------------------------------------------------- @@ -4819,15 +4802,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, return false; } - // Update the policy stack from the top to the top-most strong entry. - bool previous_was_weak = true; - for(PolicyStackType::reverse_iterator psi = this->PolicyStack.rbegin(); - previous_was_weak && psi != this->PolicyStack.rend(); ++psi) - { - psi->Set(id, status); - previous_was_weak = psi->Weak; - } - + this->StateSnapshot.SetPolicy(id, status); return true; } @@ -4836,32 +4811,28 @@ cmMakefile::PolicyPushPop::PolicyPushPop(cmMakefile* m, bool weak, cmPolicies::PolicyMap const& pm): Makefile(m), ReportError(true) { + this->Makefile->StateSnapshot = this->Makefile->StateSnapshot.GetState() + ->CreatePolicyScopeSnapshot(this->Makefile->StateSnapshot); this->Makefile->PushPolicy(weak, pm); - this->Makefile->PushPolicyBarrier(); } //---------------------------------------------------------------------------- cmMakefile::PolicyPushPop::~PolicyPushPop() { - this->Makefile->PopPolicyBarrier(this->ReportError); this->Makefile->PopPolicy(); + this->Makefile->PopPolicyBarrier(this->ReportError); } //---------------------------------------------------------------------------- void cmMakefile::PushPolicy(bool weak, cmPolicies::PolicyMap const& pm) { - // Allocate a new stack entry. - this->PolicyStack.push_back(PolicyStackEntry(pm, weak)); + this->StateSnapshot.PushPolicy(pm, weak); } //---------------------------------------------------------------------------- void cmMakefile::PopPolicy() { - if(this->PolicyStack.size() > this->PolicyBarriers.back()) - { - this->PolicyStack.pop_back(); - } - else + if (!this->StateSnapshot.PopPolicy()) { this->IssueMessage(cmake::FATAL_ERROR, "cmake_policy POP without matching PUSH"); @@ -4869,17 +4840,9 @@ void cmMakefile::PopPolicy() } //---------------------------------------------------------------------------- -void cmMakefile::PushPolicyBarrier() -{ - this->PolicyBarriers.push_back(this->PolicyStack.size()); -} - -//---------------------------------------------------------------------------- void cmMakefile::PopPolicyBarrier(bool reportError) { - // Remove any extra entries pushed on the barrier. - PolicyStackType::size_type barrier = this->PolicyBarriers.back(); - while(this->PolicyStack.size() > barrier) + while (!this->StateSnapshot.CanPopPolicyScope()) { if(reportError) { @@ -4890,8 +4853,8 @@ void cmMakefile::PopPolicyBarrier(bool reportError) this->PopPolicy(); } - // Remove the barrier. - this->PolicyBarriers.pop_back(); + this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot); + assert(this->StateSnapshot.IsValid()); } //---------------------------------------------------------------------------- diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 7938fcc..1c4da00 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -52,6 +52,7 @@ class cmVariableWatch; class cmake; class cmMakefileCall; class cmCMakePolicyCommand; +class cmGeneratorExpressionEvaluationFile; /** \class cmMakefile * \brief Process the input CMakeLists.txt file. @@ -113,10 +114,6 @@ public: bool GetIsSourceFileTryCompile() const; - ///! Get the current makefile generator. - cmLocalGenerator* GetLocalGenerator() const - { return this->LocalGenerator;} - /** * Help enforce global target name uniqueness. */ @@ -194,14 +191,15 @@ public: * Add a utility to the build. A utiltity target is a command that * is run every time the target is built. */ - void AddUtilityCommand(const std::string& utilityName, bool excludeFromAll, - const std::vector<std::string>& depends, - const char* workingDirectory, - const char* command, - const char* arg1=0, - const char* arg2=0, - const char* arg3=0, - const char* arg4=0); + cmTarget* AddUtilityCommand(const std::string& utilityName, + bool excludeFromAll, + const std::vector<std::string>& depends, + const char* workingDirectory, + const char* command, + const char* arg1=0, + const char* arg2=0, + const char* arg3=0, + const char* arg4=0); cmTarget* AddUtilityCommand(const std::string& utilityName, bool excludeFromAll, const char* workingDirectory, @@ -416,10 +414,7 @@ public: { this->GeneratorTargets = targets; } - void AddGeneratorTarget(cmTarget* t, cmGeneratorTarget* gt) - { - this->GeneratorTargets[t] = gt; - } + void AddGeneratorTarget(cmTarget* t, cmGeneratorTarget* gt); cmTarget* FindTarget(const std::string& name, bool excludeAliases = false) const; @@ -801,6 +796,12 @@ public: void EnforceDirectoryLevelRules() const; + void AddEvaluationFile(const std::string &inputFile, + cmsys::auto_ptr<cmCompiledGeneratorExpression> outputName, + cmsys::auto_ptr<cmCompiledGeneratorExpression> condition, + bool inputIsContent); + std::vector<cmGeneratorExpressionEvaluationFile*> GetEvaluationFiles() const; + protected: // add link libraries and directories to the target void AddGlobalLinkInformation(const std::string& name, cmTarget& target); @@ -897,6 +898,8 @@ private: std::vector<cmMakefile*> UnConfiguredDirectories; + std::vector<cmGeneratorExpressionEvaluationFile*> EvaluationFiles; + cmPropertyMap Properties; std::vector<cmCommandContext const*> ContextStack; @@ -911,7 +914,6 @@ private: void PushPolicy(bool weak = false, cmPolicies::PolicyMap const& pm = cmPolicies::PolicyMap()); void PopPolicy(); - void PushPolicyBarrier(); void PopPolicyBarrier(bool reportError = true); friend class cmCMakePolicyCommand; class IncludeScope; @@ -921,18 +923,6 @@ private: class BuildsystemFileScope; friend class BuildsystemFileScope; - // stack of policy settings - struct PolicyStackEntry: public cmPolicies::PolicyMap - { - typedef cmPolicies::PolicyMap derived; - PolicyStackEntry(bool w = false): derived(), Weak(w) {} - PolicyStackEntry(derived const& d, bool w = false): derived(d), Weak(w) {} - PolicyStackEntry(PolicyStackEntry const& r): derived(r), Weak(r.Weak) {} - bool Weak; - }; - typedef std::vector<PolicyStackEntry> PolicyStackType; - PolicyStackType PolicyStack; - std::vector<PolicyStackType::size_type> PolicyBarriers; // CMP0053 == old cmake::MessageType ExpandVariablesInStringOld( diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 416063f..ccb0974 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -25,7 +25,7 @@ cmMakefileExecutableTargetGenerator cmMakefileTargetGenerator(target) { this->CustomCommandDriver = OnDepends; - this->Target->GetExecutableNames( + this->GeneratorTarget->GetExecutableNames( this->TargetNameOut, this->TargetNameReal, this->TargetNameImport, this->TargetNamePDB, this->ConfigName); @@ -58,7 +58,7 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles() // write the link rules this->WriteExecutableRule(false); - if(this->Target->NeedRelinkBeforeInstall(this->ConfigName)) + if(this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) { // Write rules to link an installable version of the target. this->WriteExecutableRule(true); @@ -94,7 +94,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) std::string targetNameReal; std::string targetNameImport; std::string targetNamePDB; - this->Target->GetExecutableNames + this->GeneratorTarget->GetExecutableNames (targetName, targetNameReal, targetNameImport, targetNamePDB, this->ConfigName); @@ -130,7 +130,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) } std::string compilePdbOutputPath = - this->Target->GetCompilePDBDirectory(this->ConfigName); + this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName); cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str()); std::string pdbOutputPath = this->Target->GetPDBDirectory(this->ConfigName); @@ -161,7 +161,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Get the language to use for linking this executable. std::string linkLanguage = - this->Target->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); // Make sure we have a link language. if(linkLanguage.empty()) diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 696dcc4..2f995e8 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -28,7 +28,7 @@ cmMakefileLibraryTargetGenerator this->CustomCommandDriver = OnDepends; if (this->Target->GetType() != cmTarget::INTERFACE_LIBRARY) { - this->Target->GetLibraryNames( + this->GeneratorTarget->GetLibraryNames( this->TargetNameOut, this->TargetNameSO, this->TargetNameReal, this->TargetNameImport, this->TargetNamePDB, this->ConfigName); } @@ -69,7 +69,7 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles() break; case cmTarget::SHARED_LIBRARY: this->WriteSharedLibraryRules(false); - if(this->Target->NeedRelinkBeforeInstall(this->ConfigName)) + if(this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) { // Write rules to link an installable version of the target. this->WriteSharedLibraryRules(true); @@ -77,7 +77,7 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles() break; case cmTarget::MODULE_LIBRARY: this->WriteModuleLibraryRules(false); - if(this->Target->NeedRelinkBeforeInstall(this->ConfigName)) + if(this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) { // Write rules to link an installable version of the target. this->WriteModuleLibraryRules(true); @@ -133,7 +133,7 @@ void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules() void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules() { std::string linkLanguage = - this->Target->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); std::string linkRuleVar = "CMAKE_"; linkRuleVar += linkLanguage; linkRuleVar += "_CREATE_STATIC_LIBRARY"; @@ -159,7 +159,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) return; } std::string linkLanguage = - this->Target->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); std::string linkRuleVar = "CMAKE_"; linkRuleVar += linkLanguage; linkRuleVar += "_CREATE_SHARED_LIBRARY"; @@ -183,7 +183,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink) { std::string linkLanguage = - this->Target->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); std::string linkRuleVar = "CMAKE_"; linkRuleVar += linkLanguage; linkRuleVar += "_CREATE_SHARED_MODULE"; @@ -206,7 +206,7 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink) void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink) { std::string linkLanguage = - this->Target->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); std::string linkRuleVar = "CMAKE_"; linkRuleVar += linkLanguage; linkRuleVar += "_CREATE_MACOSX_FRAMEWORK"; @@ -238,7 +238,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules // Get the language to use for linking this library. std::string linkLanguage = - this->Target->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); // Make sure we have a link language. if(linkLanguage.empty()) @@ -266,7 +266,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules std::string targetNameReal; std::string targetNameImport; std::string targetNamePDB; - this->Target->GetLibraryNames( + this->GeneratorTarget->GetLibraryNames( targetName, targetNameSO, targetNameReal, targetNameImport, targetNamePDB, this->ConfigName); @@ -311,7 +311,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules } std::string compilePdbOutputPath = - this->Target->GetCompilePDBDirectory(this->ConfigName); + this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName); cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str()); std::string pdbOutputPath = this->Target->GetPDBDirectory(this->ConfigName); @@ -653,7 +653,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules vars.Target = target.c_str(); vars.LinkLibraries = linkLibs.c_str(); vars.ObjectsQuoted = buildObjs.c_str(); - if (this->Target->HasSOName(this->ConfigName)) + if (this->GeneratorTarget->HasSOName(this->ConfigName)) { vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage); vars.TargetSOName= targetNameSO.c_str(); @@ -666,7 +666,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules { // Get the install_name directory for the build tree. install_name_dir = - this->Target->GetInstallNameDirForBuildTree(this->ConfigName); + this->GeneratorTarget->GetInstallNameDirForBuildTree(this->ConfigName); // Set the rule variable replacement value. if(install_name_dir.empty()) diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 0f82fb3..0b3df90 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -33,7 +33,7 @@ #include <ctype.h> cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target) - : cmCommonTargetGenerator(target) + : cmCommonTargetGenerator(cmOutputConverter::START_OUTPUT, target) , OSXBundleGenerator(0) , MacOSXContentGenerator(0) { @@ -313,7 +313,7 @@ cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator() (cmSourceFile const& source, const char* pkgloc) { // Skip OS X content when not building a Framework or Bundle. - if(!this->Generator->GetTarget()->IsBundleOnApple()) + if(!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) { return; } @@ -414,7 +414,6 @@ void cmMakefileTargetGenerator // we compute some depends when writing the depend.make that we will also // use in the build.make, same with depMakeFile std::vector<std::string> depends; - std::string depMakeFile; // generate the build rule file this->WriteObjectBuildFile(obj, lang, source, depends); @@ -549,12 +548,12 @@ cmMakefileTargetGenerator this->GeneratorTarget->GetFullPath(this->ConfigName, false, true); targetFullPathPDB = this->Target->GetPDBDirectory(this->ConfigName); targetFullPathPDB += "/"; - targetFullPathPDB += this->Target->GetPDBName(this->ConfigName); + targetFullPathPDB += this->GeneratorTarget->GetPDBName(this->ConfigName); } if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY) { targetFullPathCompilePDB = - this->Target->GetCompilePDBPath(this->ConfigName); + this->GeneratorTarget->GetCompilePDBPath(this->ConfigName); if(targetFullPathCompilePDB.empty()) { targetFullPathCompilePDB = this->Target->GetSupportDirectory() + "/"; @@ -1059,46 +1058,21 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() << "\n" << "# Targets to which this target links.\n" << "set(CMAKE_TARGET_LINKED_INFO_FILES\n"; - std::set<cmTarget const*> emitted; - const char* cfg = this->LocalGenerator->GetConfigName().c_str(); - if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(cfg)) + std::vector<std::string> dirs = this->GetLinkedTargetDirectories(); + for (std::vector<std::string>::iterator i = dirs.begin(); + i != dirs.end(); ++i) { - cmComputeLinkInformation::ItemVector const& items = cli->GetItems(); - for(cmComputeLinkInformation::ItemVector::const_iterator - i = items.begin(); i != items.end(); ++i) - { - cmTarget const* linkee = i->Target; - if(linkee && !linkee->IsImported() - // We can ignore the INTERFACE_LIBRARY items because - // Target->GetLinkInformation already processed their - // link interface and they don't have any output themselves. - && linkee->GetType() != cmTarget::INTERFACE_LIBRARY - && emitted.insert(linkee).second) - { - cmGeneratorTarget* gt = - this->GlobalGenerator->GetGeneratorTarget(linkee); - cmLocalGenerator* lg = gt->GetLocalGenerator(); - cmMakefile* mf = linkee->GetMakefile(); - std::string di = mf->GetCurrentBinaryDirectory(); - di += "/"; - di += lg->GetTargetDirectory(*linkee); - di += "/DependInfo.cmake"; - *this->InfoFileStream << " \"" << di << "\"\n"; - } - } + *this->InfoFileStream << " \"" << *i << "/DependInfo.cmake\"\n"; } *this->InfoFileStream << " )\n"; } - // Check for a target-specific module output directory. - if(const char* mdir = this->GetFortranModuleDirectory()) - { - *this->InfoFileStream - << "\n" - << "# Fortran module output directory.\n" - << "set(CMAKE_Fortran_TARGET_MODULE_DIR \"" << mdir << "\")\n"; - } + *this->InfoFileStream + << "\n" + << "# Fortran module output directory.\n" + << "set(CMAKE_Fortran_TARGET_MODULE_DIR \"" + << this->GetFortranModuleDirectory() << "\")\n"; // and now write the rule to use it std::vector<std::string> depends; @@ -1472,7 +1446,8 @@ void cmMakefileTargetGenerator // Loop over all library dependencies. const char* cfg = this->LocalGenerator->GetConfigName().c_str(); - if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(cfg)) + if(cmComputeLinkInformation* cli = + this->GeneratorTarget->GetLinkInformation(cfg)) { std::vector<std::string> const& libDeps = cli->GetDepends(); depends.insert(depends.end(), libDeps.begin(), libDeps.end()); @@ -1534,7 +1509,7 @@ std::string cmMakefileTargetGenerator::GetLinkRule( if(this->Target->HasImplibGNUtoMS()) { std::string ruleVar = "CMAKE_"; - ruleVar += this->Target->GetLinkerLanguage(this->ConfigName); + ruleVar += this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); ruleVar += "_GNUtoMS_RULE"; if(const char* rule = this->Makefile->GetDefinition(ruleVar)) { @@ -1688,7 +1663,8 @@ cmMakefileTargetGenerator { // Lookup the response file reference flag. std::string responseFlagVar = "CMAKE_"; - responseFlagVar += this->Target->GetLinkerLanguage(this->ConfigName); + responseFlagVar += this->GeneratorTarget + ->GetLinkerLanguage(this->ConfigName); responseFlagVar += "_RESPONSE_FILE_LINK_FLAG"; const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar); @@ -1732,7 +1708,8 @@ cmMakefileTargetGenerator // Lookup the response file reference flag. std::string responseFlagVar = "CMAKE_"; - responseFlagVar += this->Target->GetLinkerLanguage(this->ConfigName); + responseFlagVar += this->GeneratorTarget + ->GetLinkerLanguage(this->ConfigName); responseFlagVar += "_RESPONSE_FILE_LINK_FLAG"; const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar); diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index b885672..fd4527b 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -53,6 +53,7 @@ public: { return this->ProgressFileNameFull; } cmTarget* GetTarget() { return this->Target;} + cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget;} protected: diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 8ec6f5e..b855bea 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -40,16 +40,15 @@ cmNinjaNormalTargetGenerator(cmGeneratorTarget* target) , TargetNamePDB() , TargetLinkLanguage("") { - this->TargetLinkLanguage = target->Target - ->GetLinkerLanguage(this->GetConfigName()); + this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName()); if (target->GetType() == cmTarget::EXECUTABLE) - target->Target->GetExecutableNames(this->TargetNameOut, + this->GetGeneratorTarget()->GetExecutableNames(this->TargetNameOut, this->TargetNameReal, this->TargetNameImport, this->TargetNamePDB, GetLocalGenerator()->GetConfigName()); else - target->Target->GetLibraryNames(this->TargetNameOut, + this->GetGeneratorTarget()->GetLibraryNames(this->TargetNameOut, this->TargetNameSO, this->TargetNameReal, this->TargetNameImport, @@ -531,13 +530,14 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() vars["LANGUAGE_COMPILE_FLAGS"] = t; } - if (target.HasSOName(cfgName)) + if (this->GetGeneratorTarget()->HasSOName(cfgName)) { vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage); vars["SONAME"] = this->TargetNameSO; if (targetType == cmTarget::SHARED_LIBRARY) { - std::string install_dir = target.GetInstallNameDirForBuildTree(cfgName); + std::string install_dir = + this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName); if (!install_dir.empty()) { vars["INSTALLNAME_DIR"] = localGen.Convert(install_dir, @@ -547,6 +547,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() } } + cmNinjaDeps byproducts; + if (!this->TargetNameImport.empty()) { const std::string impLibPath = localGen.ConvertToOutputFormat( @@ -556,7 +558,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() EnsureParentDirectoryExists(impLibPath); if(target.HasImportLibrary()) { - outputs.push_back(targetOutputImplib); + byproducts.push_back(targetOutputImplib); } } @@ -567,7 +569,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string prefix; std::string base; std::string suffix; - target.GetFullNameComponents(prefix, base, suffix); + this->GetGeneratorTarget()->GetFullNameComponents(prefix, base, suffix); std::string dbg_suffix = ".dbg"; // TODO: Where to document? if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) @@ -602,7 +604,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() &postBuildCmdLines }; - cmNinjaDeps byproducts; for (unsigned i = 0; i != 3; ++i) { for (std::vector<cmCustomCommand>::const_iterator diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index addf292..81fdde2 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -58,7 +58,7 @@ cmNinjaTargetGenerator::New(cmGeneratorTarget* target) } cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target) - : cmCommonTargetGenerator(target), + : cmCommonTargetGenerator(cmOutputConverter::HOME_OUTPUT, target), MacOSXContentGenerator(0), OSXBundleGenerator(0), MacContentFolders(), @@ -195,7 +195,7 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const return cmNinjaDeps(); cmComputeLinkInformation* cli = - this->Target->GetLinkInformation(this->GetConfigName()); + this->GeneratorTarget->GetLinkInformation(this->GetConfigName()); if(!cli) return cmNinjaDeps(); @@ -209,6 +209,15 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const result.push_back(this->ConvertToNinjaPath(this->ModuleDefinitionFile)); } + // Add user-specified dependencies. + if (const char* linkDepends = this->Target->GetProperty("LINK_DEPENDS")) + { + std::vector<std::string> linkDeps; + cmSystemTools::ExpandListArgument(linkDepends, linkDeps); + std::transform(linkDeps.begin(), linkDeps.end(), + std::back_inserter(result), MapToNinjaPath()); + } + return result; } @@ -273,11 +282,12 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const { pdbPath = this->Target->GetPDBDirectory(this->GetConfigName()); pdbPath += "/"; - pdbPath += this->Target->GetPDBName(this->GetConfigName()); + pdbPath += this->GeneratorTarget->GetPDBName(this->GetConfigName()); } if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY) { - compilePdbPath = this->Target->GetCompilePDBPath(this->GetConfigName()); + compilePdbPath = + this->GeneratorTarget->GetCompilePDBPath(this->GetConfigName()); if(compilePdbPath.empty()) { compilePdbPath = this->Target->GetSupportDirectory() + "/"; @@ -741,7 +751,7 @@ cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()( cmSourceFile const& source, const char* pkgloc) { // Skip OS X content when not building a Framework or Bundle. - if(!this->Generator->GetTarget()->IsBundleOnApple()) + if(!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) { return; } diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx index 3bc0eb7..4fe99e3 100644 --- a/Source/cmOSXBundleGenerator.cxx +++ b/Source/cmOSXBundleGenerator.cxx @@ -47,7 +47,7 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, // Compute bundle directory names. std::string out = outpath; out += "/"; - out += this->GT->Target->GetAppBundleDirectory(this->ConfigName, false); + out += this->GT->GetAppBundleDirectory(this->ConfigName, false); cmSystemTools::MakeDirectory(out.c_str()); this->Makefile->AddCMakeOutputFile(out); @@ -57,7 +57,7 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, // to be set. std::string plist = outpath; plist += "/"; - plist += this->GT->Target->GetAppBundleDirectory(this->ConfigName, true); + plist += this->GT->GetAppBundleDirectory(this->ConfigName, true); plist += "/Info.plist"; this->LocalGenerator->GenerateAppleInfoPList(this->GT->Target, targetName, @@ -77,11 +77,11 @@ void cmOSXBundleGenerator::CreateFramework( // Compute the location of the top-level foo.framework directory. std::string contentdir = outpath + "/" + - this->GT->Target->GetFrameworkDirectory(this->ConfigName, true); + this->GT->GetFrameworkDirectory(this->ConfigName, true); contentdir += "/"; std::string newoutpath = outpath + "/" + - this->GT->Target->GetFrameworkDirectory(this->ConfigName, false); + this->GT->GetFrameworkDirectory(this->ConfigName, false); std::string frameworkVersion = this->GT->Target->GetFrameworkVersion(); @@ -172,14 +172,14 @@ void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName, // Compute bundle directory names. std::string out = root; out += "/"; - out += this->GT->Target->GetCFBundleDirectory(this->ConfigName, false); + out += this->GT->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 = root + "/" + - this->GT->Target->GetCFBundleDirectory(this->ConfigName, true); + this->GT->GetCFBundleDirectory(this->ConfigName, true); plist += "/Info.plist"; std::string name = cmSystemTools::GetFilenameName(targetName); this->LocalGenerator->GenerateAppleInfoPList(this->GT->Target, @@ -217,7 +217,7 @@ cmOSXBundleGenerator::InitMacOSXContentDirectory(const char* pkgloc) // Construct the full path to the content subdirectory. std::string macdir = - this->GT->Target->GetMacContentDirectory(this->ConfigName, + this->GT->GetMacContentDirectory(this->ConfigName, /*implib*/ false); macdir += "/"; macdir += pkgloc; diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx index a612437..35ee127 100644 --- a/Source/cmOrderDirectories.cxx +++ b/Source/cmOrderDirectories.cxx @@ -280,7 +280,7 @@ bool cmOrderDirectoriesConstraintLibrary::FindConflict(std::string const& dir) //---------------------------------------------------------------------------- cmOrderDirectories::cmOrderDirectories(cmGlobalGenerator* gg, - cmTarget const* target, + const cmGeneratorTarget* target, const char* purpose) { this->GlobalGenerator = gg; @@ -554,7 +554,8 @@ void cmOrderDirectories::FindImplicitConflicts() << text << "Some of these libraries may not be found correctly."; this->GlobalGenerator->GetCMakeInstance() - ->IssueMessage(cmake::WARNING, w.str(), this->Target->GetBacktrace()); + ->IssueMessage(cmake::WARNING, w.str(), + this->Target->Target->GetBacktrace()); } //---------------------------------------------------------------------------- @@ -635,5 +636,6 @@ void cmOrderDirectories::DiagnoseCycle() } e << "Some of these libraries may not be found correctly."; this->GlobalGenerator->GetCMakeInstance() - ->IssueMessage(cmake::WARNING, e.str(), this->Target->GetBacktrace()); + ->IssueMessage(cmake::WARNING, e.str(), + this->Target->Target->GetBacktrace()); } diff --git a/Source/cmOrderDirectories.h b/Source/cmOrderDirectories.h index cb5a51f..211c786 100644 --- a/Source/cmOrderDirectories.h +++ b/Source/cmOrderDirectories.h @@ -19,7 +19,7 @@ class cmGlobalGenerator; class cmOrderDirectoriesConstraint; class cmOrderDirectoriesConstraintLibrary; -class cmTarget; +class cmGeneratorTarget; /** \class cmOrderDirectories * \brief Compute a safe runtime path order for a set of shared libraries. @@ -27,7 +27,7 @@ class cmTarget; class cmOrderDirectories { public: - cmOrderDirectories(cmGlobalGenerator* gg, cmTarget const* target, + cmOrderDirectories(cmGlobalGenerator* gg, cmGeneratorTarget const* target, const char* purpose); ~cmOrderDirectories(); void AddRuntimeLibrary(std::string const& fullPath, const char* soname = 0); @@ -41,7 +41,7 @@ public: std::vector<std::string> const& GetOrderedDirectories(); private: cmGlobalGenerator* GlobalGenerator; - cmTarget const* Target; + cmGeneratorTarget const* Target; std::string Purpose; std::vector<std::string> OrderedDirectories; diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index b783701..a791b89 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -217,6 +217,9 @@ class cmPolicy; 3, 3, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0063, \ "Honor visibility properties for all target types.", \ + 3, 3, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0064, \ + "Support new TEST if() operator.", \ 3, 3, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 979db91..4eb9b13 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -369,7 +369,7 @@ bool cmQtAutoGenerators::InitializeAutogenTarget(cmLocalGenerator* lg, #if defined(_WIN32) && !defined(__CYGWIN__) bool usePRE_BUILD = false; - cmGlobalGenerator* gg = makefile->GetGlobalGenerator(); + cmGlobalGenerator* gg = lg->GetGlobalGenerator(); if(gg->GetName().find("Visual Studio") != std::string::npos) { cmGlobalVisualStudioGenerator* vsgg = @@ -396,7 +396,7 @@ bool cmQtAutoGenerators::InitializeAutogenTarget(cmLocalGenerator* lg, std::vector<std::string> rcc_output; bool const isNinja = - makefile->GetGlobalGenerator()->GetName() == "Ninja"; + lg->GetGlobalGenerator()->GetName() == "Ninja"; if(isNinja #if defined(_WIN32) && !defined(__CYGWIN__) || usePRE_BUILD @@ -475,8 +475,9 @@ bool cmQtAutoGenerators::InitializeAutogenTarget(cmLocalGenerator* lg, /*byproducts=*/rcc_output, depends, commandLines, false, autogenComment.c_str()); + autogenTarget->Compute(); + cmGeneratorTarget* gt = new cmGeneratorTarget(autogenTarget, lg); - lg->GetGlobalGenerator()->AddGeneratorTarget(autogenTarget, gt); makefile->AddGeneratorTarget(autogenTarget, gt); // Set target folder @@ -548,8 +549,11 @@ void cmQtAutoGenerators::SetupAutoGenerateTarget(cmTarget const* target) { qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR"); } + cmGeneratorTarget *gtgt = target->GetMakefile() + ->GetGlobalGenerator() + ->GetGeneratorTarget(target); if (const char *targetQtVersion = - target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", "")) + gtgt->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", "")) { qtVersion = targetQtVersion; } @@ -879,8 +883,11 @@ void cmQtAutoGenerators::MergeUicOptions(std::vector<std::string> &opts, static void GetUicOpts(cmTarget const* target, const std::string& config, std::string &optString) { + cmGeneratorTarget *gtgt = target->GetMakefile() + ->GetGlobalGenerator() + ->GetGeneratorTarget(target); std::vector<std::string> opts; - target->GetAutoUicOptions(opts, config); + gtgt->GetAutoUicOptions(opts, config); optString = cmJoin(opts, ";"); } @@ -1148,6 +1155,9 @@ void cmQtAutoGenerators::SetupAutoRccTarget(cmTarget const* target) std::string cmQtAutoGenerators::GetRccExecutable(cmTarget const* target) { + cmGeneratorTarget *gtgt = target->GetMakefile() + ->GetGlobalGenerator() + ->GetGeneratorTarget(target); cmMakefile *makefile = target->GetMakefile(); const char *qtVersion = makefile->GetDefinition("_target_qt_version"); if (!qtVersion) @@ -1158,8 +1168,7 @@ std::string cmQtAutoGenerators::GetRccExecutable(cmTarget const* target) qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR"); } if (const char *targetQtVersion = - target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", - "")) + gtgt->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", "")) { qtVersion = targetQtVersion; } diff --git a/Source/cmScriptGenerator.h b/Source/cmScriptGenerator.h index 9ab04f1..bc9372f 100644 --- a/Source/cmScriptGenerator.h +++ b/Source/cmScriptGenerator.h @@ -54,9 +54,6 @@ public: void Generate(std::ostream& os, const std::string& config, std::vector<std::string> const& configurationTypes); - const std::vector<std::string>& GetConfigurations() const - { return this->Configurations; } - protected: typedef cmScriptGeneratorIndent Indent; virtual void GenerateScript(std::ostream& os); diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx index 31e460f..17ad475 100644 --- a/Source/cmSetPropertyCommand.cxx +++ b/Source/cmSetPropertyCommand.cxx @@ -205,14 +205,8 @@ bool cmSetPropertyCommand::HandleDirectoryMode() // The local generators are associated with collapsed paths. dir = cmSystemTools::CollapseFullPath(dir); - // Lookup the generator. - if(cmLocalGenerator* lg = - this->Makefile->GetGlobalGenerator()->FindLocalGenerator(dir)) - { - // Use the makefile for the directory found. - mf = lg->GetMakefile(); - } - else + mf = this->Makefile->GetGlobalGenerator()->FindMakefile(dir); + if (!mf) { // Could not find the directory. this->SetError diff --git a/Source/cmState.cxx b/Source/cmState.cxx index d8f8306..f425861 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -20,8 +20,10 @@ struct cmState::SnapshotDataType { - cmState::PositionType CallStackParent; cmState::PositionType DirectoryParent; + cmLinkedTree<cmState::PolicyStackEntry>::iterator Policies; + cmLinkedTree<cmState::PolicyStackEntry>::iterator PolicyRoot; + cmLinkedTree<cmState::PolicyStackEntry>::iterator PolicyScope; cmState::SnapshotType SnapshotType; cmLinkedTree<std::string>::iterator ExecutionListFile; cmLinkedTree<cmState::BuildsystemDirectoryStateType>::iterator @@ -33,8 +35,19 @@ struct cmState::SnapshotDataType std::vector<std::string>::size_type CompileOptionsPosition; }; +struct cmState::PolicyStackEntry: public cmPolicies::PolicyMap +{ + typedef cmPolicies::PolicyMap derived; + PolicyStackEntry(bool w = false): derived(), Weak(w) {} + PolicyStackEntry(derived const& d, bool w): derived(d), Weak(w) {} + PolicyStackEntry(PolicyStackEntry const& r): derived(r), Weak(r.Weak) {} + bool Weak; +}; + struct cmState::BuildsystemDirectoryStateType { + cmState::PositionType DirectoryEnd; + std::string Location; std::string OutputLocation; @@ -240,6 +253,9 @@ cmState::Snapshot cmState::Reset() this->GlobalProperties.clear(); this->PropertyDefinitions.clear(); + PositionType pos = this->SnapshotData.Truncate(); + this->ExecutionListFiles.Truncate(); + { cmLinkedTree<BuildsystemDirectoryStateType>::iterator it = this->BuildsystemDirectory.Truncate(); @@ -249,9 +265,15 @@ cmState::Snapshot cmState::Reset() it->CompileDefinitionsBacktraces.clear(); it->CompileOptions.clear(); it->CompileOptionsBacktraces.clear(); + it->DirectoryEnd = pos; } - PositionType pos = this->SnapshotData.Truncate(); - this->ExecutionListFiles.Truncate(); + + this->PolicyStack.Clear(); + pos->Policies = this->PolicyStack.Root(); + pos->PolicyRoot = this->PolicyStack.Root(); + pos->PolicyScope = this->PolicyStack.Root(); + assert(pos->Policies.IsValid()); + assert(pos->PolicyRoot.IsValid()); this->DefineProperty ("RULE_LAUNCH_COMPILE", cmProperty::DIRECTORY, @@ -722,6 +744,12 @@ cmState::Snapshot cmState::CreateBaseSnapshot() pos->IncludeDirectoryPosition = 0; pos->CompileDefinitionsPosition = 0; pos->CompileOptionsPosition = 0; + pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->Policies = this->PolicyStack.Root(); + pos->PolicyRoot = this->PolicyStack.Root(); + pos->PolicyScope = this->PolicyStack.Root(); + assert(pos->Policies.IsValid()); + assert(pos->PolicyRoot.IsValid()); return cmState::Snapshot(this, pos); } @@ -732,7 +760,6 @@ cmState::CreateBuildsystemDirectorySnapshot(Snapshot originSnapshot, { assert(originSnapshot.IsValid()); PositionType pos = this->SnapshotData.Extend(originSnapshot.Position); - pos->CallStackParent = originSnapshot.Position; pos->EntryPointLine = entryPointLine; pos->EntryPointCommand = entryPointCommand; pos->DirectoryParent = originSnapshot.Position; @@ -743,6 +770,12 @@ cmState::CreateBuildsystemDirectorySnapshot(Snapshot originSnapshot, pos->ExecutionListFile = this->ExecutionListFiles.Extend( originSnapshot.Position->ExecutionListFile); + pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->Policies = originSnapshot.Position->Policies; + pos->PolicyRoot = originSnapshot.Position->Policies; + pos->PolicyScope = originSnapshot.Position->Policies; + assert(pos->Policies.IsValid()); + assert(pos->PolicyRoot.IsValid()); return cmState::Snapshot(this, pos); } @@ -754,12 +787,13 @@ cmState::CreateFunctionCallSnapshot(cmState::Snapshot originSnapshot, { PositionType pos = this->SnapshotData.Extend(originSnapshot.Position, *originSnapshot.Position); - pos->CallStackParent = originSnapshot.Position; pos->EntryPointLine = entryPointLine; pos->EntryPointCommand = entryPointCommand; pos->SnapshotType = FunctionCallType; pos->ExecutionListFile = this->ExecutionListFiles.Extend( originSnapshot.Position->ExecutionListFile, fileName); + pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->PolicyScope = originSnapshot.Position->Policies; return cmState::Snapshot(this, pos); } @@ -772,12 +806,13 @@ cmState::CreateMacroCallSnapshot(cmState::Snapshot originSnapshot, { PositionType pos = this->SnapshotData.Extend(originSnapshot.Position, *originSnapshot.Position); - pos->CallStackParent = originSnapshot.Position; pos->EntryPointLine = entryPointLine; pos->EntryPointCommand = entryPointCommand; pos->SnapshotType = MacroCallType; pos->ExecutionListFile = this->ExecutionListFiles.Extend( originSnapshot.Position->ExecutionListFile, fileName); + pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->PolicyScope = originSnapshot.Position->Policies; return cmState::Snapshot(this, pos); } @@ -789,12 +824,13 @@ cmState::CreateCallStackSnapshot(cmState::Snapshot originSnapshot, { PositionType pos = this->SnapshotData.Extend(originSnapshot.Position, *originSnapshot.Position); - pos->CallStackParent = originSnapshot.Position; pos->EntryPointLine = entryPointLine; pos->EntryPointCommand = entryPointCommand; pos->SnapshotType = CallStackType; pos->ExecutionListFile = this->ExecutionListFiles.Extend( originSnapshot.Position->ExecutionListFile, fileName); + pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->PolicyScope = originSnapshot.Position->Policies; return cmState::Snapshot(this, pos); } @@ -806,12 +842,24 @@ cmState::CreateInlineListFileSnapshot(cmState::Snapshot originSnapshot, { PositionType pos = this->SnapshotData.Extend(originSnapshot.Position, *originSnapshot.Position); - pos->CallStackParent = originSnapshot.Position; pos->EntryPointLine = entryPointLine; pos->EntryPointCommand = entryPointCommand; pos->SnapshotType = InlineListFileType; pos->ExecutionListFile = this->ExecutionListFiles.Extend( originSnapshot.Position->ExecutionListFile, fileName); + pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->PolicyScope = originSnapshot.Position->Policies; + return cmState::Snapshot(this, pos); +} + +cmState::Snapshot +cmState::CreatePolicyScopeSnapshot(cmState::Snapshot originSnapshot) +{ + PositionType pos = this->SnapshotData.Extend(originSnapshot.Position, + *originSnapshot.Position); + pos->SnapshotType = PolicyScopeType; + pos->BuildSystemDirectory->DirectoryEnd = pos; + pos->PolicyScope = originSnapshot.Position->Policies; return cmState::Snapshot(this, pos); } @@ -826,12 +874,9 @@ cmState::Snapshot cmState::Pop(cmState::Snapshot originSnapshot) prevPos->BuildSystemDirectory->CompileDefinitions.size(); prevPos->CompileOptionsPosition = prevPos->BuildSystemDirectory->CompileOptions.size(); + prevPos->BuildSystemDirectory->DirectoryEnd = prevPos; - if (prevPos == this->SnapshotData.Root()) - { - return Snapshot(this, prevPos); - } - return Snapshot(this, originSnapshot.Position->CallStackParent); + return Snapshot(this, prevPos); } cmState::Snapshot::Snapshot(cmState* state) @@ -847,6 +892,11 @@ cmState::Snapshot::Snapshot(cmState* state, PositionType position) } +cmState::SnapshotType cmState::Snapshot::GetType() const +{ + return this->Position->SnapshotType; +} + const char* cmState::Directory::GetCurrentSource() const { return this->DirectoryState->Location.c_str(); @@ -964,13 +1014,22 @@ cmState::Snapshot cmState::Snapshot::GetCallStackParent() const assert(this->Position != this->State->SnapshotData.Root()); Snapshot snapshot; - if (this->Position->SnapshotType == cmState::BuildsystemDirectoryType) + PositionType parentPos = this->Position; + while(parentPos->SnapshotType == cmState::PolicyScopeType) + { + ++parentPos; + } + if (parentPos->SnapshotType == cmState::BuildsystemDirectoryType) { return snapshot; } - PositionType parentPos = this->Position; ++parentPos; + while(parentPos->SnapshotType == cmState::PolicyScopeType) + { + ++parentPos; + } + if (parentPos == this->State->SnapshotData.Root()) { return snapshot; @@ -980,6 +1039,88 @@ cmState::Snapshot cmState::Snapshot::GetCallStackParent() const return snapshot; } +void cmState::Snapshot::PushPolicy(cmPolicies::PolicyMap entry, bool weak) +{ + PositionType pos = this->Position; + pos->Policies = + this->State->PolicyStack.Extend(pos->Policies, + PolicyStackEntry(entry, weak)); +} + +bool cmState::Snapshot::PopPolicy() +{ + PositionType pos = this->Position; + if (pos->Policies == pos->PolicyScope) + { + return false; + } + ++pos->Policies; + return true; +} + +bool cmState::Snapshot::CanPopPolicyScope() +{ + return this->Position->Policies == this->Position->PolicyScope; +} + +void cmState::Snapshot::SetPolicy(cmPolicies::PolicyID id, + cmPolicies::PolicyStatus status) +{ + // Update the policy stack from the top to the top-most strong entry. + bool previous_was_weak = true; + for(cmLinkedTree<PolicyStackEntry>::iterator psi = this->Position->Policies; + previous_was_weak && psi != this->Position->PolicyRoot; ++psi) + { + psi->Set(id, status); + previous_was_weak = psi->Weak; + } +} + +cmPolicies::PolicyStatus +cmState::Snapshot::GetPolicy(cmPolicies::PolicyID id) const +{ + cmPolicies::PolicyStatus status = cmPolicies::GetPolicyStatus(id); + + if(status == cmPolicies::REQUIRED_ALWAYS || + status == cmPolicies::REQUIRED_IF_USED) + { + return status; + } + + cmLinkedTree<BuildsystemDirectoryStateType>::iterator dir = + this->Position->BuildSystemDirectory; + + while (true) + { + assert(dir.IsValid()); + cmLinkedTree<PolicyStackEntry>::iterator leaf = + dir->DirectoryEnd->Policies; + cmLinkedTree<PolicyStackEntry>::iterator root = + dir->DirectoryEnd->PolicyRoot; + for( ; leaf != root; ++leaf) + { + if(leaf->IsDefined(id)) + { + status = leaf->Get(id); + return status; + } + } + cmState::PositionType e = dir->DirectoryEnd; + cmState::PositionType p = e->DirectoryParent; + if (p == this->State->SnapshotData.Root()) + { + break; + } + dir = p->BuildSystemDirectory; + } + return status; +} + +bool cmState::Snapshot::HasDefinedPolicyCMP0011() +{ + return !this->Position->Policies->IsEmpty(); +} + static const std::string cmPropertySentinal = std::string(); template<typename T, typename U, typename V> diff --git a/Source/cmState.h b/Source/cmState.h index 0d5300f..07aa2a5 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -17,6 +17,7 @@ #include "cmPropertyMap.h" #include "cmLinkedTree.h" #include "cmAlgorithms.h" +#include "cmPolicies.h" class cmake; class cmCommand; @@ -24,6 +25,7 @@ class cmCommand; class cmState { struct SnapshotDataType; + struct PolicyStackEntry; struct BuildsystemDirectoryStateType; typedef cmLinkedTree<SnapshotDataType>::iterator PositionType; friend class Snapshot; @@ -37,7 +39,8 @@ public: FunctionCallType, MacroCallType, CallStackType, - InlineListFileType + InlineListFileType, + PolicyScopeType }; class Directory; @@ -56,9 +59,17 @@ public: bool IsValid() const; Snapshot GetBuildsystemDirectoryParent() const; Snapshot GetCallStackParent() const; + SnapshotType GetType() const; void InitializeFromParent(); + void SetPolicy(cmPolicies::PolicyID id, cmPolicies::PolicyStatus status); + cmPolicies::PolicyStatus GetPolicy(cmPolicies::PolicyID id) const; + bool HasDefinedPolicyCMP0011(); + void PushPolicy(cmPolicies::PolicyMap entry, bool weak); + bool PopPolicy(); + bool CanPopPolicyScope(); + cmState* GetState() const; Directory GetDirectory() const; @@ -147,6 +158,7 @@ public: const std::string& entryPointCommand, long entryPointLine, std::string const& fileName); + Snapshot CreatePolicyScopeSnapshot(Snapshot originSnapshot); Snapshot Pop(Snapshot originSnapshot); enum CacheEntryType{ BOOL=0, PATH, FILEPATH, STRING, INTERNAL,STATIC, @@ -254,6 +266,7 @@ private: cmLinkedTree<std::string> ExecutionListFiles; + cmLinkedTree<PolicyStackEntry> PolicyStack; cmLinkedTree<SnapshotDataType> SnapshotData; std::vector<std::string> SourceDirectoryComponents; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 2543e68..a117238 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -950,8 +950,9 @@ bool cmSystemTools::RenameFile(const char* oldname, const char* newname) Try multiple times since we may be racing against another process creating/opening the destination file just before our MoveFileEx. */ WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry(); - while(!MoveFileExW(cmsys::Encoding::ToWide(oldname).c_str(), - cmsys::Encoding::ToWide(newname).c_str(), + while(!MoveFileExW( + SystemTools::ConvertToWindowsExtendedPath(oldname).c_str(), + SystemTools::ConvertToWindowsExtendedPath(newname).c_str(), MOVEFILE_REPLACE_EXISTING) && --retry.Count) { DWORD last_error = GetLastError(); @@ -962,12 +963,14 @@ bool cmSystemTools::RenameFile(const char* oldname, const char* newname) return false; } DWORD attrs = - GetFileAttributesW(cmsys::Encoding::ToWide(newname).c_str()); + GetFileAttributesW( + SystemTools::ConvertToWindowsExtendedPath(newname).c_str()); if((attrs != INVALID_FILE_ATTRIBUTES) && (attrs & FILE_ATTRIBUTE_READONLY)) { // Remove the read-only attribute from the destination file. - SetFileAttributesW(cmsys::Encoding::ToWide(newname).c_str(), + SetFileAttributesW( + SystemTools::ConvertToWindowsExtendedPath(newname).c_str(), attrs & ~FILE_ATTRIBUTE_READONLY); } else @@ -1956,11 +1959,11 @@ bool cmSystemTools::CopyFileTime(const char* fromFile, const char* toFile) { #if defined(_WIN32) && !defined(__CYGWIN__) cmSystemToolsWindowsHandle hFrom = - CreateFileW(cmsys::Encoding::ToWide(fromFile).c_str(), + CreateFileW(SystemTools::ConvertToWindowsExtendedPath(fromFile).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); cmSystemToolsWindowsHandle hTo = - CreateFileW(cmsys::Encoding::ToWide(toFile).c_str(), + CreateFileW(SystemTools::ConvertToWindowsExtendedPath(toFile).c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); if(!hFrom || !hTo) { @@ -2012,7 +2015,7 @@ bool cmSystemTools::FileTimeGet(const char* fname, cmSystemToolsFileTime* t) { #if defined(_WIN32) && !defined(__CYGWIN__) cmSystemToolsWindowsHandle h = - CreateFileW(cmsys::Encoding::ToWide(fname).c_str(), + CreateFileW(SystemTools::ConvertToWindowsExtendedPath(fname).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if(!h) { @@ -2039,7 +2042,7 @@ bool cmSystemTools::FileTimeSet(const char* fname, cmSystemToolsFileTime* t) { #if defined(_WIN32) && !defined(__CYGWIN__) cmSystemToolsWindowsHandle h = - CreateFileW(cmsys::Encoding::ToWide(fname).c_str(), + CreateFileW(SystemTools::ConvertToWindowsExtendedPath(fname).c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); if(!h) { diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index cf33791..49b3239 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -66,27 +66,8 @@ struct cmTarget::OutputInfo std::string OutDir; std::string ImpDir; std::string PdbDir; -}; - -//---------------------------------------------------------------------------- -struct cmTarget::ImportInfo -{ - ImportInfo(): NoSOName(false), Multiplicity(0) {} - bool NoSOName; - int Multiplicity; - std::string Location; - std::string SOName; - std::string ImportLibrary; - std::string Languages; - std::string Libraries; - std::string LibrariesProp; - std::string SharedDeps; -}; - -//---------------------------------------------------------------------------- -struct cmTarget::CompileInfo -{ - std::string CompilePdbDir; + bool empty() const + { return OutDir.empty() && ImpDir.empty() && PdbDir.empty(); } }; //---------------------------------------------------------------------------- @@ -147,9 +128,6 @@ public: typedef std::map<std::string, cmTarget::ImportInfo> ImportInfoMapType; ImportInfoMapType ImportInfoMap; - typedef std::map<std::string, cmTarget::CompileInfo> CompileInfoMapType; - CompileInfoMapType CompileInfoMap; - // Cache link implementation computation from each configuration. struct OptionalLinkImplementation: public cmTarget::LinkImplementation { @@ -175,23 +153,6 @@ public: HeadToLinkImplementationMap> LinkImplMapType; LinkImplMapType LinkImplMap; - typedef std::map<std::string, cmTarget::LinkClosure> LinkClosureMapType; - LinkClosureMapType LinkClosureMap; - - struct LinkImplClosure: public std::vector<cmTarget const*> - { - LinkImplClosure(): Done(false) {} - bool Done; - }; - std::map<std::string, LinkImplClosure> LinkImplClosureMap; - - struct CompatibleInterfaces: public cmTarget::CompatibleInterfaces - { - CompatibleInterfaces(): Done(false) {} - bool Done; - }; - std::map<std::string, CompatibleInterfaces> CompatibleInterfacesMap; - typedef std::map<std::string, std::vector<cmSourceFile*> > SourceFilesMapType; SourceFilesMapType SourceFilesMap; @@ -209,10 +170,18 @@ public: const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge; cmLinkImplItem const& LinkImplItem; }; - std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries; - std::vector<TargetPropertyEntry*> CompileOptionsEntries; - std::vector<TargetPropertyEntry*> CompileFeaturesEntries; - std::vector<TargetPropertyEntry*> CompileDefinitionsEntries; + std::vector<std::string> IncludeDirectoriesEntries; + std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces; + std::vector<TargetPropertyEntry*> IncludeDirectoriesItems; + std::vector<std::string> CompileOptionsEntries; + std::vector<cmListFileBacktrace> CompileOptionsBacktraces; + std::vector<TargetPropertyEntry*> CompileOptionsItems; + std::vector<std::string> CompileFeaturesEntries; + std::vector<cmListFileBacktrace> CompileFeaturesBacktraces; + std::vector<TargetPropertyEntry*> CompileFeaturesItems; + std::vector<std::string> CompileDefinitionsEntries; + std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces; + std::vector<TargetPropertyEntry*> CompileDefinitionsItems; std::vector<TargetPropertyEntry*> SourceEntries; std::vector<cmValueWithOrigin> LinkImplementationPropertyEntries; @@ -224,14 +193,6 @@ public: cmLinkImplItem cmTargetInternals::TargetPropertyEntry::NoLinkImplItem; //---------------------------------------------------------------------------- -static void deleteAndClear( - std::vector<cmTargetInternals::TargetPropertyEntry*> &entries) -{ - cmDeleteAll(entries); - entries.clear(); -} - -//---------------------------------------------------------------------------- cmTargetInternals::~cmTargetInternals() { } @@ -347,6 +308,8 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("CXX_STANDARD", 0); this->SetPropertyDefault("CXX_STANDARD_REQUIRED", 0); this->SetPropertyDefault("CXX_EXTENSIONS", 0); + this->SetPropertyDefault("LINK_SEARCH_START_STATIC", 0); + this->SetPropertyDefault("LINK_SEARCH_END_STATIC", 0); } // Collect the set of configuration types. @@ -407,13 +370,13 @@ void cmTarget::SetMakefile(cmMakefile* mf) const cmBacktraceRange parentIncludesBts = this->Makefile->GetIncludeDirectoriesBacktraces(); - cmBacktraceRange::const_iterator btIt = parentIncludesBts.begin(); - for (cmStringRange::const_iterator it - = parentIncludes.begin(); - it != parentIncludes.end(); ++it, ++btIt) - { - this->InsertInclude(*it, *btIt); - } + this->Internal->IncludeDirectoriesEntries.insert( + this->Internal->IncludeDirectoriesEntries.end(), + parentIncludes.begin(), parentIncludes.end()); + this->Internal->IncludeDirectoriesBacktraces.insert( + this->Internal->IncludeDirectoriesBacktraces.end(), + parentIncludesBts.begin(), parentIncludesBts.end()); + const std::set<std::string> parentSystemIncludes = this->Makefile->GetSystemIncludeDirectories(); @@ -425,13 +388,12 @@ void cmTarget::SetMakefile(cmMakefile* mf) const cmBacktraceRange parentOptionsBts = this->Makefile->GetCompileOptionsBacktraces(); - btIt = parentOptionsBts.begin(); - for (cmStringRange::const_iterator it - = parentOptions.begin(); - it != parentOptions.end(); ++it, ++btIt) - { - this->InsertCompileOption(*it, *btIt); - } + this->Internal->CompileOptionsEntries.insert( + this->Internal->CompileOptionsEntries.end(), + parentOptions.begin(), parentOptions.end()); + this->Internal->CompileOptionsBacktraces.insert( + this->Internal->CompileOptionsBacktraces.end(), + parentOptionsBts.begin(), parentOptionsBts.end()); } if (this->GetType() != INTERFACE_LIBRARY && this->GetType() != UTILITY) @@ -479,6 +441,44 @@ void cmTarget::SetMakefile(cmMakefile* mf) } } +void CreatePropertyGeneratorExpressions( + std::vector<std::string> const& entries, + std::vector<cmListFileBacktrace> const& backtraces, + std::vector<cmTargetInternals::TargetPropertyEntry*>& items) +{ + std::vector<cmListFileBacktrace>::const_iterator btIt = backtraces.begin(); + for (std::vector<std::string>::const_iterator it = entries.begin(); + it != entries.end(); ++it, ++btIt) + { + cmGeneratorExpression ge(*btIt); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*it); + items.push_back(new cmTargetInternals::TargetPropertyEntry(cge)); + } +} + +void cmTarget::Compute() +{ + CreatePropertyGeneratorExpressions( + this->Internal->IncludeDirectoriesEntries, + this->Internal->IncludeDirectoriesBacktraces, + this->Internal->IncludeDirectoriesItems); + + CreatePropertyGeneratorExpressions( + this->Internal->CompileOptionsEntries, + this->Internal->CompileOptionsBacktraces, + this->Internal->CompileOptionsItems); + + CreatePropertyGeneratorExpressions( + this->Internal->CompileFeaturesEntries, + this->Internal->CompileFeaturesBacktraces, + this->Internal->CompileFeaturesItems); + + CreatePropertyGeneratorExpressions( + this->Internal->CompileDefinitionsEntries, + this->Internal->CompileDefinitionsBacktraces, + this->Internal->CompileDefinitionsItems); +} + //---------------------------------------------------------------------------- void cmTarget::AddUtility(const std::string& u, cmMakefile *makefile) { @@ -540,10 +540,7 @@ void cmTarget::ClearLinkMaps() this->Internal->LinkImplMap.clear(); this->Internal->LinkInterfaceMap.clear(); this->Internal->LinkInterfaceUsageRequirementsOnlyMap.clear(); - this->Internal->LinkClosureMap.clear(); this->Internal->SourceFilesMap.clear(); - cmDeleteAll(this->LinkInformation); - this->LinkInformation.clear(); } //---------------------------------------------------------------------------- @@ -625,13 +622,6 @@ bool cmTarget::IsXCTestOnApple() const } //---------------------------------------------------------------------------- -bool cmTarget::IsBundleOnApple() const -{ - return this->IsFrameworkOnApple() || this->IsAppBundleOnApple() || - this->IsCFBundleOnApple(); -} - -//---------------------------------------------------------------------------- static bool processSources(cmTarget const* tgt, const std::vector<cmTargetInternals::TargetPropertyEntry*> &entries, std::vector<std::string> &srcs, @@ -816,7 +806,7 @@ void cmTarget::GetSourceFiles(std::vector<std::string> &files, this->LinkImplementationLanguageIsContextDependent = false; } - deleteAndClear(linkInterfaceSourcesEntries); + cmDeleteAll(linkInterfaceSourcesEntries); } //---------------------------------------------------------------------------- @@ -1364,13 +1354,6 @@ cmTarget::AddSystemIncludeDirectories(const std::set<std::string> &incs) this->SystemIncludeDirectories.insert(incs.begin(), incs.end()); } -//---------------------------------------------------------------------------- -void -cmTarget::AddSystemIncludeDirectories(const std::vector<std::string> &incs) -{ - this->SystemIncludeDirectories.insert(incs.begin(), incs.end()); -} - #if defined(_WIN32) && !defined(__CYGWIN__) //---------------------------------------------------------------------------- void @@ -1717,39 +1700,35 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) } else if(prop == "INCLUDE_DIRECTORIES") { + this->Internal->IncludeDirectoriesEntries.clear(); + this->Internal->IncludeDirectoriesBacktraces.clear(); + this->Internal->IncludeDirectoriesEntries.push_back(value); cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - cmGeneratorExpression ge(lfbt); - deleteAndClear(this->Internal->IncludeDirectoriesEntries); - cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); - this->Internal->IncludeDirectoriesEntries.push_back( - new cmTargetInternals::TargetPropertyEntry(cge)); + this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt); } else if(prop == "COMPILE_OPTIONS") { + this->Internal->CompileOptionsEntries.clear(); + this->Internal->CompileOptionsBacktraces.clear(); + this->Internal->CompileOptionsEntries.push_back(value); cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - cmGeneratorExpression ge(lfbt); - deleteAndClear(this->Internal->CompileOptionsEntries); - cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); - this->Internal->CompileOptionsEntries.push_back( - new cmTargetInternals::TargetPropertyEntry(cge)); + this->Internal->CompileOptionsBacktraces.push_back(lfbt); } else if(prop == "COMPILE_FEATURES") { + this->Internal->CompileFeaturesEntries.clear(); + this->Internal->CompileFeaturesBacktraces.clear(); + this->Internal->CompileFeaturesEntries.push_back(value); cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - cmGeneratorExpression ge(lfbt); - deleteAndClear(this->Internal->CompileFeaturesEntries); - cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); - this->Internal->CompileFeaturesEntries.push_back( - new cmTargetInternals::TargetPropertyEntry(cge)); + this->Internal->CompileFeaturesBacktraces.push_back(lfbt); } else if(prop == "COMPILE_DEFINITIONS") { + this->Internal->CompileDefinitionsEntries.clear(); + this->Internal->CompileDefinitionsBacktraces.clear(); + this->Internal->CompileDefinitionsEntries.push_back(value); cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - cmGeneratorExpression ge(lfbt); - deleteAndClear(this->Internal->CompileDefinitionsEntries); - cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); - this->Internal->CompileDefinitionsEntries.push_back( - new cmTargetInternals::TargetPropertyEntry(cge)); + this->Internal->CompileDefinitionsBacktraces.push_back(lfbt); } else if(prop == "EXPORT_NAME" && this->IsImported()) { @@ -1815,31 +1794,27 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value, } else if(prop == "INCLUDE_DIRECTORIES") { + this->Internal->IncludeDirectoriesEntries.push_back(value); cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - cmGeneratorExpression ge(lfbt); - this->Internal->IncludeDirectoriesEntries.push_back( - new cmTargetInternals::TargetPropertyEntry(ge.Parse(value))); + this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt); } else if(prop == "COMPILE_OPTIONS") { + this->Internal->CompileOptionsEntries.push_back(value); cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - cmGeneratorExpression ge(lfbt); - this->Internal->CompileOptionsEntries.push_back( - new cmTargetInternals::TargetPropertyEntry(ge.Parse(value))); + this->Internal->CompileOptionsBacktraces.push_back(lfbt); } else if(prop == "COMPILE_FEATURES") { + this->Internal->CompileFeaturesEntries.push_back(value); cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - cmGeneratorExpression ge(lfbt); - this->Internal->CompileFeaturesEntries.push_back( - new cmTargetInternals::TargetPropertyEntry(ge.Parse(value))); + this->Internal->CompileFeaturesBacktraces.push_back(lfbt); } else if(prop == "COMPILE_DEFINITIONS") { + this->Internal->CompileDefinitionsEntries.push_back(value); cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - cmGeneratorExpression ge(lfbt); - this->Internal->CompileDefinitionsEntries.push_back( - new cmTargetInternals::TargetPropertyEntry(ge.Parse(value))); + this->Internal->CompileDefinitionsBacktraces.push_back(lfbt); } else if(prop == "EXPORT_NAME" && this->IsImported()) { @@ -1938,14 +1913,16 @@ void cmTarget::InsertInclude(std::string const& entry, cmListFileBacktrace const& bt, bool before) { - cmGeneratorExpression ge(bt); + std::vector<std::string>::iterator position = + before ? this->Internal->IncludeDirectoriesEntries.begin() + : this->Internal->IncludeDirectoriesEntries.end(); - std::vector<cmTargetInternals::TargetPropertyEntry*>::iterator position - = before ? this->Internal->IncludeDirectoriesEntries.begin() - : this->Internal->IncludeDirectoriesEntries.end(); + std::vector<cmListFileBacktrace>::iterator btPosition = + before ? this->Internal->IncludeDirectoriesBacktraces.begin() + : this->Internal->IncludeDirectoriesBacktraces.end(); - this->Internal->IncludeDirectoriesEntries.insert(position, - new cmTargetInternals::TargetPropertyEntry(ge.Parse(entry))); + this->Internal->IncludeDirectoriesEntries.insert(position, entry); + this->Internal->IncludeDirectoriesBacktraces.insert(btPosition, bt); } //---------------------------------------------------------------------------- @@ -1953,24 +1930,24 @@ void cmTarget::InsertCompileOption(std::string const& entry, cmListFileBacktrace const& bt, bool before) { - cmGeneratorExpression ge(bt); + std::vector<std::string>::iterator position = + before ? this->Internal->CompileOptionsEntries.begin() + : this->Internal->CompileOptionsEntries.end(); - std::vector<cmTargetInternals::TargetPropertyEntry*>::iterator position - = before ? this->Internal->CompileOptionsEntries.begin() - : this->Internal->CompileOptionsEntries.end(); + std::vector<cmListFileBacktrace>::iterator btPosition = + before ? this->Internal->CompileOptionsBacktraces.begin() + : this->Internal->CompileOptionsBacktraces.end(); - this->Internal->CompileOptionsEntries.insert(position, - new cmTargetInternals::TargetPropertyEntry(ge.Parse(entry))); + this->Internal->CompileOptionsEntries.insert(position, entry); + this->Internal->CompileOptionsBacktraces.insert(btPosition, bt); } //---------------------------------------------------------------------------- void cmTarget::InsertCompileDefinition(std::string const& entry, cmListFileBacktrace const& bt) { - cmGeneratorExpression ge(bt); - - this->Internal->CompileDefinitionsEntries.push_back( - new cmTargetInternals::TargetPropertyEntry(ge.Parse(entry))); + this->Internal->CompileDefinitionsEntries.push_back(entry); + this->Internal->CompileDefinitionsBacktraces.push_back(bt); } //---------------------------------------------------------------------------- @@ -2134,7 +2111,7 @@ cmTarget::GetIncludeDirectories(const std::string& config, } processIncludeDirectories(this, - this->Internal->IncludeDirectoriesEntries, + this->Internal->IncludeDirectoriesItems, includes, uniqueIncludes, &dagChecker, @@ -2150,7 +2127,8 @@ cmTarget::GetIncludeDirectories(const std::string& config, if(this->Makefile->IsOn("APPLE")) { - LinkImplementation const* impl = this->GetLinkImplementation(config); + cmLinkImplementationLibraries const* impl = + this->GetLinkImplementationLibraries(config); for(std::vector<cmLinkImplItem>::const_iterator it = impl->Libraries.begin(); it != impl->Libraries.end(); ++it) @@ -2183,7 +2161,7 @@ cmTarget::GetIncludeDirectories(const std::string& config, debugIncludes, language); - deleteAndClear(linkInterfaceIncludeDirectoriesEntries); + cmDeleteAll(linkInterfaceIncludeDirectoriesEntries); return includes; } @@ -2251,31 +2229,6 @@ static void processCompileOptions(cmTarget const* tgt, } //---------------------------------------------------------------------------- -void cmTarget::GetAutoUicOptions(std::vector<std::string> &result, - const std::string& config) const -{ - const char *prop - = this->GetLinkInterfaceDependentStringProperty("AUTOUIC_OPTIONS", - config); - if (!prop) - { - return; - } - cmGeneratorExpression ge; - - cmGeneratorExpressionDAGChecker dagChecker( - this->GetName(), - "AUTOUIC_OPTIONS", 0, 0); - cmSystemTools::ExpandListArgument(ge.Parse(prop) - ->Evaluate(this->Makefile, - config, - false, - this, - &dagChecker), - result); -} - -//---------------------------------------------------------------------------- void cmTarget::GetCompileOptions(std::vector<std::string> &result, const std::string& config, const std::string& language) const @@ -2305,7 +2258,7 @@ void cmTarget::GetCompileOptions(std::vector<std::string> &result, } processCompileOptions(this, - this->Internal->CompileOptionsEntries, + this->Internal->CompileOptionsItems, result, uniqueOptions, &dagChecker, @@ -2329,7 +2282,7 @@ void cmTarget::GetCompileOptions(std::vector<std::string> &result, debugOptions, language); - deleteAndClear(linkInterfaceCompileOptionsEntries); + cmDeleteAll(linkInterfaceCompileOptionsEntries); } //---------------------------------------------------------------------------- @@ -2376,7 +2329,7 @@ void cmTarget::GetCompileDefinitions(std::vector<std::string> &list, } processCompileDefinitions(this, - this->Internal->CompileDefinitionsEntries, + this->Internal->CompileDefinitionsItems, list, uniqueOptions, &dagChecker, @@ -2431,7 +2384,7 @@ void cmTarget::GetCompileDefinitions(std::vector<std::string> &list, debugDefines, language); - deleteAndClear(linkInterfaceCompileDefinitionsEntries); + cmDeleteAll(linkInterfaceCompileDefinitionsEntries); } //---------------------------------------------------------------------------- @@ -2477,7 +2430,7 @@ void cmTarget::GetCompileFeatures(std::vector<std::string> &result, } processCompileFeatures(this, - this->Internal->CompileFeaturesEntries, + this->Internal->CompileFeaturesItems, result, uniqueFeatures, &dagChecker, @@ -2498,7 +2451,7 @@ void cmTarget::GetCompileFeatures(std::vector<std::string> &result, config, debugFeatures); - deleteAndClear(linkInterfaceCompileFeaturesEntries); + cmDeleteAll(linkInterfaceCompileFeaturesEntries); } //---------------------------------------------------------------------------- @@ -2653,59 +2606,36 @@ cmTarget::OutputInfo const* cmTarget::GetOutputInfo( config_upper = cmSystemTools::UpperCase(config); } typedef cmTargetInternals::OutputInfoMapType OutputInfoMapType; - OutputInfoMapType::const_iterator i = + OutputInfoMapType::iterator i = this->Internal->OutputInfoMap.find(config_upper); if(i == this->Internal->OutputInfoMap.end()) { + // Add empty info in map to detect potential recursion. OutputInfo info; + OutputInfoMapType::value_type entry(config_upper, info); + i = this->Internal->OutputInfoMap.insert(entry).first; + + // Compute output directories. this->ComputeOutputDir(config, false, info.OutDir); this->ComputeOutputDir(config, true, info.ImpDir); if(!this->ComputePDBOutputDir("PDB", config, info.PdbDir)) { info.PdbDir = info.OutDir; } - OutputInfoMapType::value_type entry(config_upper, info); - i = this->Internal->OutputInfoMap.insert(entry).first; - } - return &i->second; -} -//---------------------------------------------------------------------------- -cmTarget::CompileInfo const* cmTarget::GetCompileInfo( - const std::string& config) const -{ - // There is no compile information for imported targets. - if(this->IsImported()) - { - return 0; + // Now update the previously-prepared map entry. + i->second = info; } - - if(this->GetType() > cmTarget::OBJECT_LIBRARY) + else if(i->second.empty()) { - std::string msg = "cmTarget::GetCompileInfo called for "; - msg += this->GetName(); - msg += " which has type "; - msg += cmTarget::GetTargetTypeName(this->GetType()); - this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR, msg); + // An empty map entry indicates we have been called recursively + // from the above block. + this->Makefile->GetCMakeInstance()->IssueMessage( + cmake::FATAL_ERROR, + "Target '" + this->GetName() + "' OUTPUT_DIRECTORY depends on itself.", + this->GetBacktrace()); return 0; } - - // Lookup/compute/cache the compile information for this configuration. - std::string config_upper; - if(!config.empty()) - { - config_upper = cmSystemTools::UpperCase(config); - } - typedef cmTargetInternals::CompileInfoMapType CompileInfoMapType; - CompileInfoMapType::const_iterator i = - this->Internal->CompileInfoMap.find(config_upper); - if(i == this->Internal->CompileInfoMap.end()) - { - CompileInfo info; - this->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir); - CompileInfoMapType::value_type entry(config_upper, info); - i = this->Internal->CompileInfoMap.insert(entry).first; - } return &i->second; } @@ -2740,16 +2670,6 @@ std::string cmTarget::GetPDBDirectory(const std::string& config) const } //---------------------------------------------------------------------------- -std::string cmTarget::GetCompilePDBDirectory(const std::string& config) const -{ - if(CompileInfo const* info = this->GetCompileInfo(config)) - { - return info->CompilePdbDir; - } - return ""; -} - -//---------------------------------------------------------------------------- const char* cmTarget::ImportedGetLocation(const std::string& config) const { static std::string location; @@ -2833,22 +2753,6 @@ bool cmTarget::HandleLocationPropertyPolicy(cmMakefile* context) const } //---------------------------------------------------------------------------- -static void MakePropertyList(std::string& output, - std::vector<cmTargetInternals::TargetPropertyEntry*> const& values) -{ - output = ""; - std::string sep; - for (std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator - it = values.begin(), end = values.end(); - it != end; ++it) - { - output += sep; - output += (*it)->ge->GetInput(); - sep = ";"; - } -} - -//---------------------------------------------------------------------------- const char *cmTarget::GetProperty(const std::string& prop) const { return this->GetProperty(prop, this->Makefile); @@ -3023,7 +2927,7 @@ const char *cmTarget::GetProperty(const std::string& prop, } static std::string output; - MakePropertyList(output, this->Internal->IncludeDirectoriesEntries); + output = cmJoin(this->Internal->IncludeDirectoriesEntries, ";"); return output.c_str(); } else if(prop == propCOMPILE_FEATURES) @@ -3034,7 +2938,7 @@ const char *cmTarget::GetProperty(const std::string& prop, } static std::string output; - MakePropertyList(output, this->Internal->CompileFeaturesEntries); + output = cmJoin(this->Internal->CompileFeaturesEntries, ";"); return output.c_str(); } else if(prop == propCOMPILE_OPTIONS) @@ -3045,7 +2949,7 @@ const char *cmTarget::GetProperty(const std::string& prop, } static std::string output; - MakePropertyList(output, this->Internal->CompileOptionsEntries); + output = cmJoin(this->Internal->CompileOptionsEntries, ";"); return output.c_str(); } else if(prop == propCOMPILE_DEFINITIONS) @@ -3056,7 +2960,7 @@ const char *cmTarget::GetProperty(const std::string& prop, } static std::string output; - MakePropertyList(output, this->Internal->CompileDefinitionsEntries); + output = cmJoin(this->Internal->CompileDefinitionsEntries, ";"); return output.c_str(); } else if (prop == propIMPORTED) @@ -3192,229 +3096,6 @@ bool cmTarget::GetPropertyAsBool(const std::string& prop) const } //---------------------------------------------------------------------------- -class cmTargetCollectLinkLanguages -{ -public: - cmTargetCollectLinkLanguages(cmTarget const* target, - const std::string& config, - UNORDERED_SET<std::string>& languages, - cmTarget const* head): - Config(config), Languages(languages), HeadTarget(head), - Makefile(target->GetMakefile()), Target(target) - { this->Visited.insert(target); } - - void Visit(cmLinkItem const& item) - { - if(!item.Target) - { - if(item.find("::") != std::string::npos) - { - bool noMessage = false; - cmake::MessageType messageType = cmake::FATAL_ERROR; - std::ostringstream e; - switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0028)) - { - case cmPolicies::WARN: - { - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\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; - } - - if(!noMessage) - { - e << "Target \"" << this->Target->GetName() - << "\" links to target \"" << item - << "\" but the target was not found. Perhaps a find_package() " - "call is missing for an IMPORTED target, or an ALIAS target is " - "missing?"; - this->Makefile->GetCMakeInstance()->IssueMessage(messageType, - e.str(), - this->Target->GetBacktrace()); - } - } - return; - } - if(!this->Visited.insert(item.Target).second) - { - return; - } - - cmTarget::LinkInterface const* iface = - item.Target->GetLinkInterface(this->Config, this->HeadTarget); - if(!iface) { return; } - - for(std::vector<std::string>::const_iterator - li = iface->Languages.begin(); li != iface->Languages.end(); ++li) - { - this->Languages.insert(*li); - } - - for(std::vector<cmLinkItem>::const_iterator - li = iface->Libraries.begin(); li != iface->Libraries.end(); ++li) - { - this->Visit(*li); - } - } -private: - std::string Config; - UNORDERED_SET<std::string>& Languages; - cmTarget const* HeadTarget; - cmMakefile* Makefile; - const cmTarget* Target; - std::set<cmTarget const*> Visited; -}; - -//---------------------------------------------------------------------------- -std::string cmTarget::GetLinkerLanguage(const std::string& config) const -{ - return this->GetLinkClosure(config)->LinkerLanguage; -} - -//---------------------------------------------------------------------------- -cmTarget::LinkClosure const* -cmTarget::GetLinkClosure(const std::string& config) const -{ - std::string key(cmSystemTools::UpperCase(config)); - cmTargetInternals::LinkClosureMapType::iterator - i = this->Internal->LinkClosureMap.find(key); - if(i == this->Internal->LinkClosureMap.end()) - { - LinkClosure lc; - this->ComputeLinkClosure(config, lc); - cmTargetInternals::LinkClosureMapType::value_type entry(key, lc); - i = this->Internal->LinkClosureMap.insert(entry).first; - } - return &i->second; -} - -//---------------------------------------------------------------------------- -class cmTargetSelectLinker -{ - int Preference; - cmTarget const* Target; - cmMakefile* Makefile; - cmGlobalGenerator* GG; - UNORDERED_SET<std::string> Preferred; -public: - cmTargetSelectLinker(cmTarget const* target): Preference(0), Target(target) - { - this->Makefile = this->Target->GetMakefile(); - this->GG = this->Makefile->GetGlobalGenerator(); - } - void Consider(const std::string& lang) - { - int preference = this->GG->GetLinkerPreference(lang); - if(preference > this->Preference) - { - this->Preference = preference; - this->Preferred.clear(); - } - if(preference == this->Preference) - { - this->Preferred.insert(lang); - } - } - std::string Choose() - { - if(this->Preferred.empty()) - { - return ""; - } - else if(this->Preferred.size() > 1) - { - std::ostringstream e; - e << "Target " << this->Target->GetName() - << " contains multiple languages with the highest linker preference" - << " (" << this->Preference << "):\n"; - for(UNORDERED_SET<std::string>::const_iterator - li = this->Preferred.begin(); li != this->Preferred.end(); ++li) - { - e << " " << *li << "\n"; - } - e << "Set the LINKER_LANGUAGE property for this target."; - cmake* cm = this->Makefile->GetCMakeInstance(); - cm->IssueMessage(cmake::FATAL_ERROR, e.str(), - this->Target->GetBacktrace()); - } - return *this->Preferred.begin(); - } -}; - -//---------------------------------------------------------------------------- -void cmTarget::ComputeLinkClosure(const std::string& config, - LinkClosure& lc) const -{ - // Get languages built in this target. - UNORDERED_SET<std::string> languages; - LinkImplementation const* impl = this->GetLinkImplementation(config); - for(std::vector<std::string>::const_iterator li = impl->Languages.begin(); - li != impl->Languages.end(); ++li) - { - languages.insert(*li); - } - - // Add interface languages from linked targets. - cmTargetCollectLinkLanguages cll(this, config, languages, this); - for(std::vector<cmLinkImplItem>::const_iterator - li = impl->Libraries.begin(); - li != impl->Libraries.end(); ++li) - { - cll.Visit(*li); - } - - // Store the transitive closure of languages. - for(UNORDERED_SET<std::string>::const_iterator li = languages.begin(); - li != languages.end(); ++li) - { - lc.Languages.push_back(*li); - } - - // Choose the language whose linker should be used. - if(this->GetProperty("HAS_CXX")) - { - lc.LinkerLanguage = "CXX"; - } - else if(const char* linkerLang = this->GetProperty("LINKER_LANGUAGE")) - { - lc.LinkerLanguage = linkerLang; - } - else - { - // Find the language with the highest preference value. - cmTargetSelectLinker tsl(this); - - // First select from the languages compiled directly in this target. - for(std::vector<std::string>::const_iterator li = impl->Languages.begin(); - li != impl->Languages.end(); ++li) - { - tsl.Consider(*li); - } - - // Now consider languages that propagate from linked targets. - for(UNORDERED_SET<std::string>::const_iterator sit = languages.begin(); - sit != languages.end(); ++sit) - { - std::string propagates = "CMAKE_"+*sit+"_LINKER_PREFERENCE_PROPAGATES"; - if(this->Makefile->IsOn(propagates)) - { - tsl.Consider(*sit); - } - } - - lc.LinkerLanguage = tsl.Choose(); - } -} - -//---------------------------------------------------------------------------- void cmTarget::ExpandLinkItems(std::string const& prop, std::string const& value, std::string const& config, @@ -3517,133 +3198,6 @@ const char* cmTarget::GetPrefixVariableInternal(bool implib) const } //---------------------------------------------------------------------------- -std::string cmTarget::GetPDBName(const std::string& config) const -{ - std::string prefix; - std::string base; - std::string suffix; - this->GetFullNameInternal(config, false, prefix, base, suffix); - - std::vector<std::string> props; - std::string configUpper = cmSystemTools::UpperCase(config); - if(!configUpper.empty()) - { - // PDB_NAME_<CONFIG> - props.push_back("PDB_NAME_" + configUpper); - } - - // PDB_NAME - props.push_back("PDB_NAME"); - - for(std::vector<std::string>::const_iterator i = props.begin(); - i != props.end(); ++i) - { - if(const char* outName = this->GetProperty(*i)) - { - base = outName; - break; - } - } - return prefix+base+".pdb"; -} - -//---------------------------------------------------------------------------- -std::string cmTarget::GetCompilePDBName(const std::string& config) const -{ - std::string prefix; - std::string base; - std::string suffix; - this->GetFullNameInternal(config, false, prefix, base, suffix); - - // Check for a per-configuration output directory target property. - std::string configUpper = cmSystemTools::UpperCase(config); - std::string configProp = "COMPILE_PDB_NAME_"; - configProp += configUpper; - const char* config_name = this->GetProperty(configProp); - if(config_name && *config_name) - { - return prefix + config_name + ".pdb"; - } - - const char* name = this->GetProperty("COMPILE_PDB_NAME"); - if(name && *name) - { - return prefix + name + ".pdb"; - } - - return ""; -} - -//---------------------------------------------------------------------------- -std::string cmTarget::GetCompilePDBPath(const std::string& config) const -{ - std::string dir = this->GetCompilePDBDirectory(config); - std::string name = this->GetCompilePDBName(config); - if(dir.empty() && !name.empty()) - { - dir = this->GetPDBDirectory(config); - } - if(!dir.empty()) - { - dir += "/"; - } - return dir + name; -} - -//---------------------------------------------------------------------------- -bool cmTarget::HasSOName(const std::string& config) const -{ - // soname is supported only for shared libraries and modules, - // and then only when the platform supports an soname flag. - return ((this->GetType() == cmTarget::SHARED_LIBRARY || - this->GetType() == cmTarget::MODULE_LIBRARY) && - !this->GetPropertyAsBool("NO_SONAME") && - this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config))); -} - -//---------------------------------------------------------------------------- -std::string cmTarget::GetSOName(const std::string& config) const -{ - if(this->IsImported()) - { - // Lookup the imported soname. - if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) - { - if(info->NoSOName) - { - // The imported library has no builtin soname so the name - // searched at runtime will be just the filename. - return cmSystemTools::GetFilenameName(info->Location); - } - else - { - // Use the soname given if any. - if(info->SOName.find("@rpath/") == 0) - { - return info->SOName.substr(6); - } - return info->SOName; - } - } - else - { - return ""; - } - } - else - { - // Compute the soname that will be built. - std::string name; - std::string soName; - std::string realName; - std::string impName; - std::string pdbName; - this->GetLibraryNames(name, soName, realName, impName, pdbName, config); - return soName; - } -} - -//---------------------------------------------------------------------------- bool cmTarget::HasMacOSXRpathInstallNameDir(const std::string& config) const { bool install_name_is_rpath = false; @@ -3770,20 +3324,6 @@ bool cmTarget::IsImportedSharedLibWithoutSOName( } //---------------------------------------------------------------------------- -std::string cmTarget::GetFullName(const std::string& config, - bool implib) const -{ - if(this->IsImported()) - { - return this->GetFullNameImported(config, implib); - } - else - { - return this->GetFullNameInternal(config, implib); - } -} - -//---------------------------------------------------------------------------- std::string cmTarget::GetFullNameImported(const std::string& config, bool implib) const { @@ -3792,15 +3332,6 @@ cmTarget::GetFullNameImported(const std::string& config, bool implib) const } //---------------------------------------------------------------------------- -void cmTarget::GetFullNameComponents(std::string& prefix, std::string& base, - std::string& suffix, - const std::string& config, - bool implib) const -{ - this->GetFullNameInternal(config, implib, prefix, base, suffix); -} - -//---------------------------------------------------------------------------- std::string cmTarget::ImportedGetFullPath(const std::string& config, bool implib) const { @@ -3818,237 +3349,6 @@ cmTarget::ImportedGetFullPath(const std::string& config, bool implib) const } //---------------------------------------------------------------------------- -std::string -cmTarget::GetFullNameInternal(const std::string& config, bool implib) const -{ - std::string prefix; - std::string base; - std::string suffix; - this->GetFullNameInternal(config, implib, prefix, base, suffix); - return prefix+base+suffix; -} - -//---------------------------------------------------------------------------- -void cmTarget::GetFullNameInternal(const std::string& config, - bool implib, - std::string& outPrefix, - std::string& outBase, - std::string& outSuffix) const -{ - // Use just the target name for non-main target types. - if(this->GetType() != cmTarget::STATIC_LIBRARY && - this->GetType() != cmTarget::SHARED_LIBRARY && - this->GetType() != cmTarget::MODULE_LIBRARY && - this->GetType() != cmTarget::EXECUTABLE) - { - outPrefix = ""; - outBase = this->GetName(); - outSuffix = ""; - return; - } - - // Return an empty name for the import library if this platform - // does not support import libraries. - if(implib && - !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) - { - outPrefix = ""; - outBase = ""; - outSuffix = ""; - return; - } - - // The implib option is only allowed for shared libraries, module - // libraries, and executables. - if(this->GetType() != cmTarget::SHARED_LIBRARY && - this->GetType() != cmTarget::MODULE_LIBRARY && - this->GetType() != cmTarget::EXECUTABLE) - { - implib = false; - } - - // Compute the full name for main target types. - const char* targetPrefix = (implib - ? this->GetProperty("IMPORT_PREFIX") - : this->GetProperty("PREFIX")); - const char* targetSuffix = (implib - ? this->GetProperty("IMPORT_SUFFIX") - : this->GetProperty("SUFFIX")); - const char* configPostfix = 0; - if(!config.empty()) - { - std::string configProp = cmSystemTools::UpperCase(config); - configProp += "_POSTFIX"; - configPostfix = this->GetProperty(configProp); - // Mac application bundles and frameworks have no postfix. - if(configPostfix && - (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) - { - configPostfix = 0; - } - } - const char* prefixVar = this->GetPrefixVariableInternal(implib); - const char* suffixVar = this->GetSuffixVariableInternal(implib); - - // Check for language-specific default prefix and suffix. - std::string ll = this->GetLinkerLanguage(config); - if(!ll.empty()) - { - if(!targetSuffix && suffixVar && *suffixVar) - { - std::string langSuff = suffixVar + std::string("_") + ll; - targetSuffix = this->Makefile->GetDefinition(langSuff); - } - if(!targetPrefix && prefixVar && *prefixVar) - { - std::string langPrefix = prefixVar + std::string("_") + ll; - targetPrefix = this->Makefile->GetDefinition(langPrefix); - } - } - - // if there is no prefix on the target use the cmake definition - if(!targetPrefix && prefixVar) - { - targetPrefix = this->Makefile->GetSafeDefinition(prefixVar); - } - // if there is no suffix on the target use the cmake definition - if(!targetSuffix && suffixVar) - { - targetSuffix = this->Makefile->GetSafeDefinition(suffixVar); - } - - // frameworks have directory prefix but no suffix - std::string fw_prefix; - if(this->IsFrameworkOnApple()) - { - fw_prefix = this->GetOutputName(config, false); - fw_prefix += ".framework/"; - targetPrefix = fw_prefix.c_str(); - targetSuffix = 0; - } - - if(this->IsCFBundleOnApple()) - { - fw_prefix = this->GetCFBundleDirectory(config, false); - fw_prefix += "/"; - targetPrefix = fw_prefix.c_str(); - targetSuffix = 0; - } - - // Begin the final name with the prefix. - outPrefix = targetPrefix?targetPrefix:""; - - // Append the target name or property-specified name. - outBase += this->GetOutputName(config, implib); - - // Append the per-configuration postfix. - outBase += configPostfix?configPostfix:""; - - // Name shared libraries with their version number on some platforms. - if(const char* soversion = this->GetProperty("SOVERSION")) - { - if(this->GetType() == cmTarget::SHARED_LIBRARY && !implib && - this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")) - { - outBase += "-"; - outBase += soversion; - } - } - - // Append the suffix. - outSuffix = targetSuffix?targetSuffix:""; -} - -//---------------------------------------------------------------------------- -void cmTarget::GetLibraryNames(std::string& name, - std::string& soName, - std::string& realName, - std::string& impName, - std::string& pdbName, - const std::string& config) const -{ - // This should not be called for imported targets. - // TODO: Split cmTarget into a class hierarchy to get compile-time - // enforcement of the limited imported target API. - if(this->IsImported()) - { - std::string msg = "GetLibraryNames called on imported target: "; - msg += this->GetName(); - this->Makefile->IssueMessage(cmake::INTERNAL_ERROR, - msg); - return; - } - - assert(this->GetType() != INTERFACE_LIBRARY); - - // Check for library version properties. - const char* version = this->GetProperty("VERSION"); - const char* soversion = this->GetProperty("SOVERSION"); - if(!this->HasSOName(config) || - this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") || - this->IsFrameworkOnApple()) - { - // Versioning is supported only for shared libraries and modules, - // and then only when the platform supports an soname flag. - version = 0; - soversion = 0; - } - if(version && !soversion) - { - // The soversion must be set if the library version is set. Use - // the library version as the soversion. - soversion = version; - } - if(!version && soversion) - { - // Use the soversion as the library version. - version = soversion; - } - - // Get the components of the library name. - std::string prefix; - std::string base; - std::string suffix; - this->GetFullNameInternal(config, false, prefix, base, suffix); - - // The library name. - name = prefix+base+suffix; - - 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 || - this->GetType() == cmTarget::MODULE_LIBRARY) - { - impName = this->GetFullNameInternal(config, true); - } - else - { - impName = ""; - } - - // The program database file name. - pdbName = this->GetPDBName(config); -} - -//---------------------------------------------------------------------------- void cmTarget::ComputeVersionedName(std::string& vName, std::string const& prefix, std::string const& base, @@ -4066,68 +3366,6 @@ void cmTarget::ComputeVersionedName(std::string& vName, } //---------------------------------------------------------------------------- -void cmTarget::GetExecutableNames(std::string& name, - std::string& realName, - std::string& impName, - std::string& pdbName, - const std::string& config) const -{ - // This should not be called for imported targets. - // TODO: Split cmTarget into a class hierarchy to get compile-time - // enforcement of the limited imported target API. - if(this->IsImported()) - { - std::string msg = - "GetExecutableNames called on imported target: "; - msg += this->GetName(); - this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR, msg); - } - - // This versioning is supported only for executables and then only - // when the platform supports symbolic links. -#if defined(_WIN32) && !defined(__CYGWIN__) - const char* version = 0; -#else - // Check for executable version properties. - const char* version = this->GetProperty("VERSION"); - if(this->GetType() != cmTarget::EXECUTABLE || this->Makefile->IsOn("XCODE")) - { - version = 0; - } -#endif - - // Get the components of the executable name. - std::string prefix; - std::string base; - std::string suffix; - this->GetFullNameInternal(config, false, prefix, base, suffix); - - // The executable name. - name = prefix+base+suffix; - - // The executable's real name on disk. -#if defined(__CYGWIN__) - realName = prefix+base; -#else - realName = name; -#endif - if(version) - { - realName += "-"; - realName += version; - } -#if defined(__CYGWIN__) - realName += suffix; -#endif - - // The import library name. - impName = this->GetFullNameInternal(config, true); - - // The program database file name. - pdbName = this->GetPDBName(config); -} - -//---------------------------------------------------------------------------- bool cmTarget::HasImplibGNUtoMS() const { return this->HasImportLibrary() && this->GetPropertyAsBool("GNUtoMS"); @@ -4172,7 +3410,7 @@ bool cmTarget::HaveBuildTreeRPATH(const std::string& config) const { return false; } - if(LinkImplementationLibraries const* impl = + if(cmLinkImplementationLibraries const* impl = this->GetLinkImplementationLibraries(config)) { return !impl->Libraries.empty(); @@ -4189,137 +3427,6 @@ bool cmTarget::HaveInstallTreeRPATH() const } //---------------------------------------------------------------------------- -bool cmTarget::NeedRelinkBeforeInstall(const std::string& config) const -{ - // Only executables and shared libraries can have an rpath and may - // need relinking. - if(this->TargetTypeValue != cmTarget::EXECUTABLE && - this->TargetTypeValue != cmTarget::SHARED_LIBRARY && - this->TargetTypeValue != cmTarget::MODULE_LIBRARY) - { - return false; - } - - // If there is no install location this target will not be installed - // and therefore does not need relinking. - if(!this->GetHaveInstallRule()) - { - return false; - } - - // If skipping all rpaths completely then no relinking is needed. - if(this->Makefile->IsOn("CMAKE_SKIP_RPATH")) - { - return false; - } - - // If building with the install-tree rpath no relinking is needed. - if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) - { - return false; - } - - // If chrpath is going to be used no relinking is needed. - if(this->IsChrpathUsed(config)) - { - return false; - } - - // Check for rpath support on this platform. - std::string ll = this->GetLinkerLanguage(config); - if(!ll.empty()) - { - std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; - flagVar += ll; - flagVar += "_FLAG"; - if(!this->Makefile->IsSet(flagVar)) - { - // There is no rpath support on this platform so nothing needs - // relinking. - return false; - } - } - else - { - // No linker language is known. This error will be reported by - // other code. - return false; - } - - // If either a build or install tree rpath is set then the rpath - // will likely change between the build tree and install tree and - // this target must be relinked. - return this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH(); -} - -//---------------------------------------------------------------------------- -std::string cmTarget::GetInstallNameDirForBuildTree( - const std::string& config) const -{ - // 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(); - } - - // Use the build tree directory for the target. - if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME") && - !this->Makefile->IsOn("CMAKE_SKIP_RPATH") && - !this->GetPropertyAsBool("SKIP_BUILD_RPATH")) - { - std::string dir; - bool macosx_rpath = this->MacOSXRpathInstallNameDirDefault(); - if(macosx_rpath) - { - dir = "@rpath"; - } - else - { - dir = this->GetDirectory(config); - } - dir += "/"; - return dir; - } - else - { - return ""; - } -} - -//---------------------------------------------------------------------------- -std::string cmTarget::GetInstallNameDirForInstallTree() const -{ - 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")) - { - if(install_name_dir && *install_name_dir) - { - dir = install_name_dir; - dir += "/"; - } - } - if(!install_name_dir) - { - if(this->MacOSXRpathInstallNameDirDefault()) - { - dir = "@rpath/"; - } - } - return dir; - } - else - { - return ""; - } -} - -//---------------------------------------------------------------------------- const char* cmTarget::GetOutputTargetType(bool implib) const { switch(this->GetType()) @@ -4408,7 +3515,10 @@ bool cmTarget::ComputeOutputDir(const std::string& config, if(const char* config_outdir = this->GetProperty(configProp)) { // Use the user-specified per-configuration output directory. - out = config_outdir; + cmGeneratorExpression ge; + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = + ge.Parse(config_outdir); + out = cge->Evaluate(this->Makefile, config); // Skip per-configuration subdirectory. conf = ""; @@ -4416,7 +3526,17 @@ bool cmTarget::ComputeOutputDir(const std::string& config, else if(const char* outdir = this->GetProperty(propertyName)) { // Use the user-specified output directory. - out = outdir; + cmGeneratorExpression ge; + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = + ge.Parse(outdir); + out = cge->Evaluate(this->Makefile, config); + + // Skip per-configuration subdirectory if the value contained a + // generator expression. + if (out != outdir) + { + conf = ""; + } } else if(this->GetType() == cmTarget::EXECUTABLE) { @@ -4527,54 +3647,6 @@ bool cmTarget::UsesDefaultOutputDir(const std::string& config, } //---------------------------------------------------------------------------- -std::string cmTarget::GetOutputName(const std::string& config, - bool implib) const -{ - std::vector<std::string> props; - std::string type = this->GetOutputTargetType(implib); - std::string configUpper = cmSystemTools::UpperCase(config); - if(!type.empty() && !configUpper.empty()) - { - // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG> - props.push_back(type + "_OUTPUT_NAME_" + configUpper); - } - if(!type.empty()) - { - // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME - props.push_back(type + "_OUTPUT_NAME"); - } - if(!configUpper.empty()) - { - // OUTPUT_NAME_<CONFIG> - props.push_back("OUTPUT_NAME_" + configUpper); - // <CONFIG>_OUTPUT_NAME - props.push_back(configUpper + "_OUTPUT_NAME"); - } - // OUTPUT_NAME - props.push_back("OUTPUT_NAME"); - - std::string outName; - for(std::vector<std::string>::const_iterator i = props.begin(); - i != props.end(); ++i) - { - if (const char* outNameProp = this->GetProperty(*i)) - { - outName = outNameProp; - break; - } - } - - if (outName.empty()) - { - outName = this->GetName(); - } - - cmGeneratorExpression ge; - cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName); - return cge->Evaluate(this->Makefile, config); -} - -//---------------------------------------------------------------------------- std::string cmTarget::GetFrameworkVersion() const { assert(this->GetType() != INTERFACE_LIBRARY); @@ -4627,500 +3699,6 @@ bool cmTarget::IsNullImpliedByLinkLibraries(const std::string &p) const } //---------------------------------------------------------------------------- -template<typename PropertyType> -PropertyType getTypedProperty(cmTarget const* tgt, const std::string& prop); - -//---------------------------------------------------------------------------- -template<> -bool getTypedProperty<bool>(cmTarget const* tgt, const std::string& prop) -{ - return tgt->GetPropertyAsBool(prop); -} - -//---------------------------------------------------------------------------- -template<> -const char *getTypedProperty<const char *>(cmTarget const* tgt, - const std::string& prop) -{ - return tgt->GetProperty(prop); -} - -enum CompatibleType -{ - BoolType, - StringType, - NumberMinType, - NumberMaxType -}; - -//---------------------------------------------------------------------------- -template<typename PropertyType> -std::pair<bool, PropertyType> consistentProperty(PropertyType lhs, - PropertyType rhs, - CompatibleType t); - -//---------------------------------------------------------------------------- -template<> -std::pair<bool, bool> consistentProperty(bool lhs, bool rhs, CompatibleType) -{ - return std::make_pair(lhs == rhs, lhs); -} - -//---------------------------------------------------------------------------- -std::pair<bool, const char*> consistentStringProperty(const char *lhs, - const char *rhs) -{ - const bool b = strcmp(lhs, rhs) == 0; - return std::make_pair(b, b ? lhs : 0); -} - -//---------------------------------------------------------------------------- -std::pair<bool, const char*> consistentNumberProperty(const char *lhs, - const char *rhs, - CompatibleType t) -{ - char *pEnd; - - const char* const null_ptr = 0; - - long lnum = strtol(lhs, &pEnd, 0); - if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) - { - return std::pair<bool, const char*>(false, null_ptr); - } - - long rnum = strtol(rhs, &pEnd, 0); - if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) - { - return std::pair<bool, const char*>(false, null_ptr); - } - - if (t == NumberMaxType) - { - return std::make_pair(true, std::max(lnum, rnum) == lnum ? lhs : rhs); - } - else - { - return std::make_pair(true, std::min(lnum, rnum) == lnum ? lhs : rhs); - } -} - -//---------------------------------------------------------------------------- -template<> -std::pair<bool, const char*> consistentProperty(const char *lhs, - const char *rhs, - CompatibleType t) -{ - if (!lhs && !rhs) - { - return std::make_pair(true, lhs); - } - if (!lhs) - { - return std::make_pair(true, rhs); - } - if (!rhs) - { - return std::make_pair(true, lhs); - } - - const char* const null_ptr = 0; - - switch(t) - { - case BoolType: - assert(0 && "consistentProperty for strings called with BoolType"); - return std::pair<bool, const char*>(false, null_ptr); - case StringType: - return consistentStringProperty(lhs, rhs); - case NumberMinType: - case NumberMaxType: - return consistentNumberProperty(lhs, rhs, t); - } - assert(0 && "Unreachable!"); - return std::pair<bool, const char*>(false, null_ptr); -} - -template<typename PropertyType> -PropertyType impliedValue(PropertyType); -template<> -bool impliedValue<bool>(bool) -{ - return false; -} -template<> -const char* impliedValue<const char*>(const char*) -{ - return ""; -} - - -template<typename PropertyType> -std::string valueAsString(PropertyType); -template<> -std::string valueAsString<bool>(bool value) -{ - return value ? "TRUE" : "FALSE"; -} -template<> -std::string valueAsString<const char*>(const char* value) -{ - return value ? value : "(unset)"; -} - -//---------------------------------------------------------------------------- -void -cmTarget::ReportPropertyOrigin(const std::string &p, - const std::string &result, - const std::string &report, - const std::string &compatibilityType) const -{ - std::vector<std::string> debugProperties; - const char *debugProp = - this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); - if (debugProp) - { - cmSystemTools::ExpandListArgument(debugProp, debugProperties); - } - - bool debugOrigin = !this->DebugCompatiblePropertiesDone[p] - && std::find(debugProperties.begin(), - debugProperties.end(), - p) - != debugProperties.end(); - - if (this->Makefile->IsConfigured()) - { - this->DebugCompatiblePropertiesDone[p] = true; - } - if (!debugOrigin) - { - return; - } - - std::string areport = compatibilityType; - areport += std::string(" of property \"") + p + "\" for target \""; - areport += std::string(this->GetName()); - areport += "\" (result: \""; - areport += result; - areport += "\"):\n" + report; - - this->Makefile->GetCMakeInstance()->IssueMessage(cmake::LOG, areport); -} - -//---------------------------------------------------------------------------- -std::string compatibilityType(CompatibleType t) -{ - switch(t) - { - case BoolType: - return "Boolean compatibility"; - case StringType: - return "String compatibility"; - case NumberMaxType: - return "Numeric maximum compatibility"; - case NumberMinType: - return "Numeric minimum compatibility"; - } - assert(0 && "Unreachable!"); - return ""; -} - -//---------------------------------------------------------------------------- -std::string compatibilityAgree(CompatibleType t, bool dominant) -{ - switch(t) - { - case BoolType: - case StringType: - return dominant ? "(Disagree)\n" : "(Agree)\n"; - case NumberMaxType: - case NumberMinType: - return dominant ? "(Dominant)\n" : "(Ignored)\n"; - } - assert(0 && "Unreachable!"); - return ""; -} - -//---------------------------------------------------------------------------- -template<typename PropertyType> -PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, - const std::string &p, - const std::string& config, - const char *defaultValue, - CompatibleType t, - PropertyType *) -{ - PropertyType propContent = getTypedProperty<PropertyType>(tgt, p); - const bool explicitlySet = tgt->GetProperties() - .find(p) - != tgt->GetProperties().end(); - const bool impliedByUse = - tgt->IsNullImpliedByLinkLibraries(p); - assert((impliedByUse ^ explicitlySet) - || (!impliedByUse && !explicitlySet)); - - std::vector<cmTarget const*> const& deps = - tgt->GetLinkImplementationClosure(config); - - if(deps.empty()) - { - return propContent; - } - bool propInitialized = explicitlySet; - - std::string report = " * Target \""; - report += tgt->GetName(); - if (explicitlySet) - { - report += "\" has property content \""; - report += valueAsString<PropertyType>(propContent); - report += "\"\n"; - } - else if (impliedByUse) - { - report += "\" property is implied by use.\n"; - } - else - { - report += "\" property not set.\n"; - } - - std::string interfaceProperty = "INTERFACE_" + p; - for(std::vector<cmTarget const*>::const_iterator li = - deps.begin(); - li != deps.end(); ++li) - { - // An error should be reported if one dependency - // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other - // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the - // target itself has a POSITION_INDEPENDENT_CODE which disagrees - // with a dependency. - - cmTarget const* theTarget = *li; - - const bool ifaceIsSet = theTarget->GetProperties() - .find(interfaceProperty) - != theTarget->GetProperties().end(); - PropertyType ifacePropContent = - getTypedProperty<PropertyType>(theTarget, - interfaceProperty); - - std::string reportEntry; - if (ifaceIsSet) - { - reportEntry += " * Target \""; - reportEntry += theTarget->GetName(); - reportEntry += "\" property value \""; - reportEntry += valueAsString<PropertyType>(ifacePropContent); - reportEntry += "\" "; - } - - if (explicitlySet) - { - if (ifaceIsSet) - { - std::pair<bool, PropertyType> consistent = - consistentProperty(propContent, - ifacePropContent, t); - report += reportEntry; - report += compatibilityAgree(t, propContent != consistent.second); - if (!consistent.first) - { - std::ostringstream e; - e << "Property " << p << " on target \"" - << tgt->GetName() << "\" does\nnot match the " - "INTERFACE_" << p << " property requirement\nof " - "dependency \"" << theTarget->GetName() << "\".\n"; - cmSystemTools::Error(e.str().c_str()); - break; - } - else - { - propContent = consistent.second; - continue; - } - } - else - { - // Explicitly set on target and not set in iface. Can't disagree. - continue; - } - } - else if (impliedByUse) - { - propContent = impliedValue<PropertyType>(propContent); - - if (ifaceIsSet) - { - std::pair<bool, PropertyType> consistent = - consistentProperty(propContent, - ifacePropContent, t); - report += reportEntry; - report += compatibilityAgree(t, propContent != consistent.second); - if (!consistent.first) - { - std::ostringstream e; - e << "Property " << p << " on target \"" - << tgt->GetName() << "\" is\nimplied to be " << defaultValue - << " because it was used to determine the link libraries\n" - "already. The INTERFACE_" << p << " property on\ndependency \"" - << theTarget->GetName() << "\" is in conflict.\n"; - cmSystemTools::Error(e.str().c_str()); - break; - } - else - { - propContent = consistent.second; - continue; - } - } - else - { - // Implicitly set on target and not set in iface. Can't disagree. - continue; - } - } - else - { - if (ifaceIsSet) - { - if (propInitialized) - { - std::pair<bool, PropertyType> consistent = - consistentProperty(propContent, - ifacePropContent, t); - report += reportEntry; - report += compatibilityAgree(t, propContent != consistent.second); - if (!consistent.first) - { - std::ostringstream e; - e << "The INTERFACE_" << p << " property of \"" - << theTarget->GetName() << "\" does\nnot agree with the value " - "of " << p << " already determined\nfor \"" - << tgt->GetName() << "\".\n"; - cmSystemTools::Error(e.str().c_str()); - break; - } - else - { - propContent = consistent.second; - continue; - } - } - else - { - report += reportEntry + "(Interface set)\n"; - propContent = ifacePropContent; - propInitialized = true; - } - } - else - { - // Not set. Nothing to agree on. - continue; - } - } - } - - tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent), - report, compatibilityType(t)); - return propContent; -} - -//---------------------------------------------------------------------------- -bool cmTarget::GetLinkInterfaceDependentBoolProperty(const std::string &p, - const std::string& config) const -{ - return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE", - BoolType, 0); -} - -//---------------------------------------------------------------------------- -const char * cmTarget::GetLinkInterfaceDependentStringProperty( - const std::string &p, - const std::string& config) const -{ - return checkInterfacePropertyCompatibility<const char *>(this, - p, - config, - "empty", - StringType, 0); -} - -//---------------------------------------------------------------------------- -const char * cmTarget::GetLinkInterfaceDependentNumberMinProperty( - const std::string &p, - const std::string& config) const -{ - return checkInterfacePropertyCompatibility<const char *>(this, - p, - config, - "empty", - NumberMinType, 0); -} - -//---------------------------------------------------------------------------- -const char * cmTarget::GetLinkInterfaceDependentNumberMaxProperty( - const std::string &p, - const std::string& config) const -{ - return checkInterfacePropertyCompatibility<const char *>(this, - p, - config, - "empty", - NumberMaxType, 0); -} - -//---------------------------------------------------------------------------- -bool cmTarget::IsLinkInterfaceDependentBoolProperty(const std::string &p, - const std::string& config) const -{ - if (this->TargetTypeValue == OBJECT_LIBRARY - || this->TargetTypeValue == INTERFACE_LIBRARY) - { - return false; - } - return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0; -} - -//---------------------------------------------------------------------------- -bool cmTarget::IsLinkInterfaceDependentStringProperty(const std::string &p, - const std::string& config) const -{ - if (this->TargetTypeValue == OBJECT_LIBRARY - || this->TargetTypeValue == INTERFACE_LIBRARY) - { - return false; - } - return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0; -} - -//---------------------------------------------------------------------------- -bool cmTarget::IsLinkInterfaceDependentNumberMinProperty(const std::string &p, - const std::string& config) const -{ - if (this->TargetTypeValue == OBJECT_LIBRARY - || this->TargetTypeValue == INTERFACE_LIBRARY) - { - return false; - } - return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0; -} - -//---------------------------------------------------------------------------- -bool cmTarget::IsLinkInterfaceDependentNumberMaxProperty(const std::string &p, - const std::string& config) const -{ - if (this->TargetTypeValue == OBJECT_LIBRARY - || this->TargetTypeValue == INTERFACE_LIBRARY) - { - return false; - } - return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0; -} - -//---------------------------------------------------------------------------- void cmTarget::GetObjectLibrariesCMP0026(std::vector<cmTarget*>& objlibs) const { @@ -5206,73 +3784,6 @@ void cmTarget::GetLanguages(std::set<std::string>& languages, } //---------------------------------------------------------------------------- -bool cmTarget::IsChrpathUsed(const std::string& config) const -{ - // Only certain target types have an rpath. - if(!(this->GetType() == cmTarget::SHARED_LIBRARY || - this->GetType() == cmTarget::MODULE_LIBRARY || - this->GetType() == cmTarget::EXECUTABLE)) - { - return false; - } - - // If the target will not be installed we do not need to change its - // rpath. - if(!this->GetHaveInstallRule()) - { - return false; - } - - // Skip chrpath if skipping rpath altogether. - if(this->Makefile->IsOn("CMAKE_SKIP_RPATH")) - { - return false; - } - - // Skip chrpath if it does not need to be changed at install time. - if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH")) - { - return false; - } - - // Allow the user to disable builtin chrpath explicitly. - if(this->Makefile->IsOn("CMAKE_NO_BUILTIN_CHRPATH")) - { - 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. - std::string ll = this->GetLinkerLanguage(config); - if(!ll.empty()) - { - std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; - sepVar += ll; - sepVar += "_FLAG_SEP"; - const char* sep = this->Makefile->GetDefinition(sepVar); - if(sep && *sep) - { - // TODO: Add ELF check to ABI detection and get rid of - // CMAKE_EXECUTABLE_FORMAT. - if(const char* fmt = - this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) - { - return strcmp(fmt, "ELF") == 0; - } - } - } -#endif - static_cast<void>(config); - return false; -} - -//---------------------------------------------------------------------------- cmTarget::ImportInfo const* cmTarget::GetImportInfo(const std::string& config) const { @@ -5760,86 +4271,6 @@ cmTarget::GetImportLinkInterface(const std::string& config, } //---------------------------------------------------------------------------- -void processILibs(const std::string& config, - cmTarget const* headTarget, - cmLinkItem const& item, - std::vector<cmTarget const*>& tgts, - std::set<cmTarget const*>& emitted) -{ - if (item.Target && emitted.insert(item.Target).second) - { - tgts.push_back(item.Target); - if(cmTarget::LinkInterfaceLibraries const* iface = - item.Target->GetLinkInterfaceLibraries(config, headTarget, true)) - { - for(std::vector<cmLinkItem>::const_iterator - it = iface->Libraries.begin(); - it != iface->Libraries.end(); ++it) - { - processILibs(config, headTarget, *it, tgts, emitted); - } - } - } -} - -//---------------------------------------------------------------------------- -std::vector<cmTarget const*> const& -cmTarget::GetLinkImplementationClosure(const std::string& config) const -{ - cmTargetInternals::LinkImplClosure& tgts = - this->Internal->LinkImplClosureMap[config]; - if(!tgts.Done) - { - tgts.Done = true; - std::set<cmTarget const*> emitted; - - cmTarget::LinkImplementationLibraries const* impl - = this->GetLinkImplementationLibraries(config); - - for(std::vector<cmLinkImplItem>::const_iterator - it = impl->Libraries.begin(); - it != impl->Libraries.end(); ++it) - { - processILibs(config, this, *it, tgts , emitted); - } - } - return tgts; -} - -//---------------------------------------------------------------------------- -cmTarget::CompatibleInterfaces const& -cmTarget::GetCompatibleInterfaces(std::string const& config) const -{ - cmTargetInternals::CompatibleInterfaces& compat = - this->Internal->CompatibleInterfacesMap[config]; - if(!compat.Done) - { - compat.Done = true; - compat.PropsBool.insert("POSITION_INDEPENDENT_CODE"); - compat.PropsString.insert("AUTOUIC_OPTIONS"); - std::vector<cmTarget const*> const& deps = - this->GetLinkImplementationClosure(config); - for(std::vector<cmTarget const*>::const_iterator li = deps.begin(); - li != deps.end(); ++li) - { -#define CM_READ_COMPATIBLE_INTERFACE(X, x) \ - if(const char* prop = (*li)->GetProperty("COMPATIBLE_INTERFACE_" #X)) \ - { \ - std::vector<std::string> props; \ - cmSystemTools::ExpandListArgument(prop, props); \ - compat.Props##x.insert(props.begin(), props.end()); \ - } - CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool) - CM_READ_COMPATIBLE_INTERFACE(STRING, String) - CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin) - CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax) -#undef CM_READ_COMPATIBLE_INTERFACE - } - } - return compat; -} - -//---------------------------------------------------------------------------- void cmTargetInternals::ComputeLinkInterfaceLibraries( cmTarget const* thisTarget, @@ -5942,7 +4373,7 @@ cmTargetInternals::ComputeLinkInterfaceLibraries( // to the link implementation. { // The link implementation is the default link interface. - cmTarget::LinkImplementationLibraries const* impl = + cmLinkImplementationLibraries const* impl = thisTarget->GetLinkImplementationLibrariesInternal(config, headTarget); iface.Libraries.insert(iface.Libraries.end(), impl->Libraries.begin(), impl->Libraries.end()); @@ -6042,7 +4473,7 @@ void cmTargetInternals::ComputeLinkInterface(cmTarget const* thisTarget, || thisTarget->GetPolicyStatusCMP0022() == cmPolicies::OLD) { // The link implementation is the default link interface. - cmTarget::LinkImplementationLibraries const* + cmLinkImplementationLibraries const* impl = thisTarget->GetLinkImplementationLibrariesInternal(config, headTarget); iface.ImplementationIsInterface = true; @@ -6093,7 +4524,7 @@ void cmTargetInternals::AddInterfaceEntries( cmTarget const* thisTarget, std::string const& config, std::string const& prop, std::vector<TargetPropertyEntry*>& entries) { - if(cmTarget::LinkImplementationLibraries const* impl = + if(cmLinkImplementationLibraries const* impl = thisTarget->GetLinkImplementationLibraries(config)) { for (std::vector<cmLinkImplItem>::const_iterator @@ -6143,14 +4574,14 @@ cmTarget::GetLinkImplementation(const std::string& config) const } //---------------------------------------------------------------------------- -cmTarget::LinkImplementationLibraries const* +cmLinkImplementationLibraries const* cmTarget::GetLinkImplementationLibraries(const std::string& config) const { return this->GetLinkImplementationLibrariesInternal(config, this); } //---------------------------------------------------------------------------- -cmTarget::LinkImplementationLibraries const* +cmLinkImplementationLibraries const* cmTarget::GetLinkImplementationLibrariesInternal(const std::string& config, cmTarget const* head) const { @@ -6396,382 +4827,6 @@ std::string cmTarget::CheckCMP0004(std::string const& item) const return lib; } -template<typename PropertyType> -PropertyType getLinkInterfaceDependentProperty(cmTarget const* tgt, - const std::string& prop, - const std::string& config, - CompatibleType, - PropertyType *); - -template<> -bool getLinkInterfaceDependentProperty(cmTarget const* tgt, - const std::string& prop, - const std::string& config, - CompatibleType, bool *) -{ - return tgt->GetLinkInterfaceDependentBoolProperty(prop, config); -} - -template<> -const char * getLinkInterfaceDependentProperty(cmTarget const* tgt, - const std::string& prop, - const std::string& config, - CompatibleType t, - const char **) -{ - switch(t) - { - case BoolType: - assert(0 && "String compatibility check function called for boolean"); - return 0; - case StringType: - return tgt->GetLinkInterfaceDependentStringProperty(prop, config); - case NumberMinType: - return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config); - case NumberMaxType: - return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config); - } - assert(0 && "Unreachable!"); - return 0; -} - -//---------------------------------------------------------------------------- -template<typename PropertyType> -void checkPropertyConsistency(cmTarget const* depender, - cmTarget const* dependee, - const std::string& propName, - std::set<std::string> &emitted, - const std::string& config, - CompatibleType t, - PropertyType *) -{ - const char *prop = dependee->GetProperty(propName); - if (!prop) - { - return; - } - - std::vector<std::string> props; - cmSystemTools::ExpandListArgument(prop, props); - std::string pdir = - dependee->GetMakefile()->GetRequiredDefinition("CMAKE_ROOT"); - pdir += "/Help/prop_tgt/"; - - for(std::vector<std::string>::iterator pi = props.begin(); - pi != props.end(); ++pi) - { - std::string pname = cmSystemTools::HelpFileName(*pi); - std::string pfile = pdir + pname + ".rst"; - if(cmSystemTools::FileExists(pfile.c_str(), true)) - { - std::ostringstream e; - e << "Target \"" << dependee->GetName() << "\" has property \"" - << *pi << "\" listed in its " << propName << " property. " - "This is not allowed. Only user-defined properties may appear " - "listed in the " << propName << " property."; - depender->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str()); - return; - } - if(emitted.insert(*pi).second) - { - getLinkInterfaceDependentProperty<PropertyType>(depender, *pi, config, - t, 0); - if (cmSystemTools::GetErrorOccuredFlag()) - { - return; - } - } - } -} - -static std::string intersect(const std::set<std::string> &s1, - const std::set<std::string> &s2) -{ - std::set<std::string> intersect; - std::set_intersection(s1.begin(),s1.end(), - s2.begin(),s2.end(), - std::inserter(intersect,intersect.begin())); - if (!intersect.empty()) - { - return *intersect.begin(); - } - return ""; -} -static std::string intersect(const std::set<std::string> &s1, - const std::set<std::string> &s2, - const std::set<std::string> &s3) -{ - std::string result; - result = intersect(s1, s2); - if (!result.empty()) - return result; - result = intersect(s1, s3); - if (!result.empty()) - return result; - return intersect(s2, s3); -} -static std::string intersect(const std::set<std::string> &s1, - const std::set<std::string> &s2, - const std::set<std::string> &s3, - const std::set<std::string> &s4) -{ - std::string result; - result = intersect(s1, s2); - if (!result.empty()) - return result; - result = intersect(s1, s3); - if (!result.empty()) - return result; - result = intersect(s1, s4); - if (!result.empty()) - return result; - return intersect(s2, s3, s4); -} - -//---------------------------------------------------------------------------- -void cmTarget::CheckPropertyCompatibility(cmComputeLinkInformation *info, - const std::string& config) const -{ - const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); - - std::set<std::string> emittedBools; - static std::string strBool = "COMPATIBLE_INTERFACE_BOOL"; - std::set<std::string> emittedStrings; - static std::string strString = "COMPATIBLE_INTERFACE_STRING"; - std::set<std::string> emittedMinNumbers; - static std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN"; - std::set<std::string> emittedMaxNumbers; - static std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX"; - - for(cmComputeLinkInformation::ItemVector::const_iterator li = - deps.begin(); - li != deps.end(); ++li) - { - if (!li->Target) - { - continue; - } - - checkPropertyConsistency<bool>(this, li->Target, - strBool, - emittedBools, config, BoolType, 0); - if (cmSystemTools::GetErrorOccuredFlag()) - { - return; - } - checkPropertyConsistency<const char *>(this, li->Target, - strString, - emittedStrings, config, - StringType, 0); - if (cmSystemTools::GetErrorOccuredFlag()) - { - return; - } - checkPropertyConsistency<const char *>(this, li->Target, - strNumMin, - emittedMinNumbers, config, - NumberMinType, 0); - if (cmSystemTools::GetErrorOccuredFlag()) - { - return; - } - checkPropertyConsistency<const char *>(this, li->Target, - strNumMax, - emittedMaxNumbers, config, - NumberMaxType, 0); - if (cmSystemTools::GetErrorOccuredFlag()) - { - return; - } - } - - std::string prop = intersect(emittedBools, - emittedStrings, - emittedMinNumbers, - emittedMaxNumbers); - - if (!prop.empty()) - { - // Use a sorted std::vector to keep the error message sorted. - std::vector<std::string> props; - std::set<std::string>::const_iterator i = emittedBools.find(prop); - if (i != emittedBools.end()) - { - props.push_back(strBool); - } - i = emittedStrings.find(prop); - if (i != emittedStrings.end()) - { - props.push_back(strString); - } - i = emittedMinNumbers.find(prop); - if (i != emittedMinNumbers.end()) - { - props.push_back(strNumMin); - } - i = emittedMaxNumbers.find(prop); - if (i != emittedMaxNumbers.end()) - { - props.push_back(strNumMax); - } - std::sort(props.begin(), props.end()); - - std::string propsString = cmJoin(cmMakeRange(props).retreat(1), ", "); - propsString += " and the " + props.back(); - - std::ostringstream e; - e << "Property \"" << prop << "\" appears in both the " - << propsString << - " property in the dependencies of target \"" << this->GetName() << - "\". This is not allowed. A property may only require compatibility " - "in a boolean interpretation, a numeric minimum, a numeric maximum or a " - "string interpretation, but not a mixture."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - } -} - -//---------------------------------------------------------------------------- -cmComputeLinkInformation* -cmTarget::GetLinkInformation(const std::string& config) const -{ - // Lookup any existing information for this configuration. - std::string key(cmSystemTools::UpperCase(config)); - cmTargetLinkInformationMap::iterator - i = this->LinkInformation.find(key); - if(i == this->LinkInformation.end()) - { - // Compute information for this configuration. - cmComputeLinkInformation* info = - new cmComputeLinkInformation(this, config); - if(!info || !info->Compute()) - { - delete info; - info = 0; - } - - // Store the information for this configuration. - cmTargetLinkInformationMap::value_type entry(key, info); - i = this->LinkInformation.insert(entry).first; - - if (info) - { - this->CheckPropertyCompatibility(info, config); - } - } - return i->second; -} - -//---------------------------------------------------------------------------- -std::string cmTarget::GetFrameworkDirectory(const std::string& config, - bool rootDir) const -{ - std::string fpath; - fpath += this->GetOutputName(config, false); - fpath += ".framework"; - if(!rootDir) - { - fpath += "/Versions/"; - fpath += this->GetFrameworkVersion(); - } - return fpath; -} - -//---------------------------------------------------------------------------- -std::string cmTarget::GetCFBundleDirectory(const std::string& config, - bool contentOnly) const -{ - std::string fpath; - fpath += this->GetOutputName(config, false); - fpath += "."; - const char *ext = this->GetProperty("BUNDLE_EXTENSION"); - if (!ext) - { - if (this->IsXCTestOnApple()) - { - ext = "xctest"; - } - else - { - ext = "bundle"; - } - } - fpath += ext; - fpath += "/Contents"; - if(!contentOnly) - fpath += "/MacOS"; - return fpath; -} - -//---------------------------------------------------------------------------- -std::string cmTarget::GetAppBundleDirectory(const std::string& config, - bool contentOnly) const -{ - 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 std::string& config, - bool contentOnly) const -{ - std::string fpath = base; - if(this->IsAppBundleOnApple()) - { - fpath += this->GetAppBundleDirectory(config, contentOnly); - } - if(this->IsFrameworkOnApple()) - { - fpath += this->GetFrameworkDirectory(config, contentOnly); - } - if(this->IsCFBundleOnApple()) - { - fpath += this->GetCFBundleDirectory(config, contentOnly); - } - return fpath; -} - -//---------------------------------------------------------------------------- -std::string cmTarget::GetMacContentDirectory(const std::string& config, - bool implib) const -{ - // Start with the output directory for the target. - std::string fpath = this->GetDirectory(config, implib); - fpath += "/"; - 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; -} - -//---------------------------------------------------------------------------- -cmTargetLinkInformationMap -::cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r): derived() -{ - // Ideally cmTarget instances should never be copied. However until - // we can make a sweep to remove that, this copy constructor avoids - // allowing the resources (LinkInformation) from getting copied. In - // the worst case this will lead to extra cmComputeLinkInformation - // instances. We also enforce in debug mode that the map be emptied - // when copied. - static_cast<void>(r); - assert(r.empty()); -} - -//---------------------------------------------------------------------------- -cmTargetLinkInformationMap::~cmTargetLinkInformationMap() -{ - cmDeleteAll(*this); -} - //---------------------------------------------------------------------------- cmTargetInternalPointer::cmTargetInternalPointer() { @@ -6791,10 +4846,10 @@ cmTargetInternalPointer //---------------------------------------------------------------------------- cmTargetInternalPointer::~cmTargetInternalPointer() { - cmDeleteAll(this->Pointer->IncludeDirectoriesEntries); - cmDeleteAll(this->Pointer->CompileOptionsEntries); - cmDeleteAll(this->Pointer->CompileFeaturesEntries); - cmDeleteAll(this->Pointer->CompileDefinitionsEntries); + cmDeleteAll(this->Pointer->IncludeDirectoriesItems); + cmDeleteAll(this->Pointer->CompileOptionsItems); + cmDeleteAll(this->Pointer->CompileFeaturesItems); + cmDeleteAll(this->Pointer->CompileDefinitionsItems); cmDeleteAll(this->Pointer->SourceEntries); delete this->Pointer; } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index f567d50..2007b40 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -16,6 +16,7 @@ #include "cmPropertyMap.h" #include "cmPolicies.h" #include "cmListFileCache.h" +#include "cmLinkItem.h" #include <cmsys/auto_ptr.hxx> #if defined(CMAKE_BUILD_WITH_CMAKE) @@ -52,41 +53,6 @@ class cmTarget; class cmGeneratorTarget; class cmTargetTraceDependencies; -// Basic information about each link item. -class cmLinkItem: public std::string -{ - typedef std::string std_string; -public: - cmLinkItem(): std_string(), Target(0) {} - cmLinkItem(const std_string& n, - cmTarget const* t): std_string(n), Target(t) {} - cmLinkItem(cmLinkItem const& r): std_string(r), Target(r.Target) {} - cmTarget const* Target; -}; -class cmLinkImplItem: public cmLinkItem -{ -public: - cmLinkImplItem(): cmLinkItem(), Backtrace(), FromGenex(false) {} - cmLinkImplItem(std::string const& n, - cmTarget const* t, - cmListFileBacktrace const& bt, - bool fromGenex): - cmLinkItem(n, t), Backtrace(bt), FromGenex(fromGenex) {} - cmLinkImplItem(cmLinkImplItem const& r): - cmLinkItem(r), Backtrace(r.Backtrace), FromGenex(r.FromGenex) {} - cmListFileBacktrace Backtrace; - bool FromGenex; -}; - -struct cmTargetLinkInformationMap: - public std::map<std::string, cmComputeLinkInformation*> -{ - typedef std::map<std::string, cmComputeLinkInformation*> derived; - cmTargetLinkInformationMap() {} - cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r); - ~cmTargetLinkInformationMap(); -}; - class cmTargetInternals; class cmTargetInternalPointer { @@ -166,6 +132,8 @@ public: void AddPostBuildCommand(cmCustomCommand const &cmd) {this->PostBuildCommands.push_back(cmd);} + void Compute(); + /** * Get the list of the source files used by this target */ @@ -302,31 +270,7 @@ public: cmTarget const* headTarget, bool usage_requirements_only) const; - std::vector<cmTarget const*> const& - GetLinkImplementationClosure(const std::string& config) const; - - struct CompatibleInterfaces - { - std::set<std::string> PropsBool; - std::set<std::string> PropsString; - std::set<std::string> PropsNumberMax; - std::set<std::string> PropsNumberMin; - }; - CompatibleInterfaces const& - GetCompatibleInterfaces(std::string const& config) const; - - /** The link implementation specifies the direct library - dependencies needed by the object files of the target. */ - struct LinkImplementationLibraries - { - // Libraries linked directly in this configuration. - std::vector<cmLinkImplItem> Libraries; - - // Libraries linked directly in other configurations. - // Needed only for OLD behavior of CMP0003. - std::vector<cmLinkItem> WrongConfigLibraries; - }; - struct LinkImplementation: public LinkImplementationLibraries + struct LinkImplementation: public cmLinkImplementationLibraries { // Languages whose runtime libraries must be linked. std::vector<std::string> Languages; @@ -334,21 +278,9 @@ public: LinkImplementation const* GetLinkImplementation(const std::string& config) const; - LinkImplementationLibraries const* + cmLinkImplementationLibraries const* GetLinkImplementationLibraries(const std::string& config) const; - /** Link information from the transitive closure of the link - implementation and the interfaces of its dependencies. */ - struct LinkClosure - { - // The preferred linker language. - std::string LinkerLanguage; - - // Languages whose runtime libraries must be linked. - std::vector<std::string> Languages; - }; - LinkClosure const* GetLinkClosure(const std::string& config) const; - cmTarget const* FindTargetToLink(std::string const& name) const; /** Strip off leading and trailing whitespace from an item named in @@ -368,12 +300,6 @@ public: pdb output directory is given. */ std::string GetPDBDirectory(const std::string& config) const; - /** Get the directory in which to place the target compiler .pdb file. - If the configuration name is given then the generator will add its - subdirectory for that configuration. Otherwise just the canonical - compiler pdb output directory is given. */ - std::string GetCompilePDBDirectory(const std::string& config = "") const; - const char* ImportedGetLocation(const std::string& config) const; /** Get the target major and minor version numbers interpreted from @@ -387,33 +313,6 @@ public: void GetTargetVersion(bool soversion, int& major, int& minor, int& patch) const; - ///! Return the preferred linker language for this target - std::string GetLinkerLanguage(const std::string& config = "") const; - - /** Get the full name of the target according to the settings in its - makefile. */ - std::string GetFullName(const std::string& config="", - bool implib = false) const; - void GetFullNameComponents(std::string& prefix, - std::string& base, std::string& suffix, - const std::string& config="", - bool implib = false) const; - - /** Get the name of the pdb file for the target. */ - std::string GetPDBName(const std::string& config) const; - - /** Get the name of the compiler pdb file for the target. */ - std::string GetCompilePDBName(const std::string& config="") const; - - /** Get the path for the MSVC /Fd option for this target. */ - std::string GetCompilePDBPath(const std::string& config="") const; - - /** Whether this library has soname enabled and platform supports it. */ - bool HasSOName(const std::string& config) const; - - /** Get the soname of the target. Allowed only for a shared library. */ - std::string GetSOName(const std::string& config) const; - /** Whether this library has \@rpath and platform supports it. */ bool HasMacOSXRpathInstallNameDir(const std::string& config) const; @@ -424,21 +323,6 @@ public: no soname at all. */ bool IsImportedSharedLibWithoutSOName(const std::string& config) const; - /** Get the names of the library needed to generate a build rule - that takes into account shared library version numbers. This - should be called only on a library target. */ - void GetLibraryNames(std::string& name, std::string& soName, - std::string& realName, std::string& impName, - std::string& pdbName, const std::string& config) const; - - /** Get the names of the executable needed to generate a build rule - that takes into account executable version numbers. This should - be called only on an executable target. */ - void GetExecutableNames(std::string& name, std::string& realName, - std::string& impName, - std::string& pdbName, - const std::string& config) const; - /** Does this target have a GNU implib to convert to MS format? */ bool HasImplibGNUtoMS() const; @@ -447,29 +331,9 @@ public: bool GetImplibGNUtoMS(std::string const& gnuName, std::string& out, const char* newExt = 0) const; - /** - * Compute whether this target must be relinked before installing. - */ - bool NeedRelinkBeforeInstall(const std::string& config) const; - bool HaveBuildTreeRPATH(const std::string& config) const; bool HaveInstallTreeRPATH() const; - /** Return true if builtin chrpath will work for this target */ - bool IsChrpathUsed(const std::string& config) const; - - /** 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 std::string& config) const; - - /** Return the install name directory for the target in the - * install tree. For example: "\@rpath/" or "\@loader_path/". */ - std::string GetInstallNameDirForInstallTree() const; - - cmComputeLinkInformation* - GetLinkInformation(const std::string& config) const; - // Get the properties cmPropertyMap &GetProperties() const { return this->Properties; } @@ -520,10 +384,6 @@ public: /** Return whether this target is an executable Bundle on Apple. */ bool IsAppBundleOnApple() const; - /** Return whether this target is an executable Bundle, a framework - or CFBundle on Apple. */ - bool IsBundleOnApple() const; - /** Return the framework version string. Undefined if IsFrameworkOnApple returns false. */ std::string GetFrameworkVersion() const; @@ -538,25 +398,9 @@ public: directory. */ bool UsesDefaultOutputDir(const std::string& config, bool implib) const; - /** @return the mac content directory for this target. */ - std::string GetMacContentDirectory(const std::string& config, - bool implib) const; - /** @return whether this target have a well defined output file name. */ bool HaveWellDefinedOutputFiles() const; - /** @return the Mac framework directory without the base. */ - std::string GetFrameworkDirectory(const std::string& config, - bool rootDir) const; - - /** @return the Mac CFBundle directory without the base */ - std::string GetCFBundleDirectory(const std::string& config, - bool contentOnly) const; - - /** @return the Mac App directory without the base */ - std::string GetAppBundleDirectory(const std::string& config, - bool contentOnly) const; - std::vector<std::string> GetIncludeDirectories( const std::string& config, const std::string& language) const; @@ -574,47 +418,21 @@ public: void GetCompileOptions(std::vector<std::string> &result, const std::string& config, const std::string& language) const; - void GetAutoUicOptions(std::vector<std::string> &result, - const std::string& config) const; void GetCompileFeatures(std::vector<std::string> &features, const std::string& config) const; bool IsNullImpliedByLinkLibraries(const std::string &p) const; - bool IsLinkInterfaceDependentBoolProperty(const std::string &p, - const std::string& config) const; - bool IsLinkInterfaceDependentStringProperty(const std::string &p, - const std::string& config) const; - bool IsLinkInterfaceDependentNumberMinProperty(const std::string &p, - const std::string& config) const; - bool IsLinkInterfaceDependentNumberMaxProperty(const std::string &p, - const std::string& config) const; - - bool GetLinkInterfaceDependentBoolProperty(const std::string &p, - const std::string& config) const; - - const char *GetLinkInterfaceDependentStringProperty(const std::string &p, - const std::string& config) const; - const char *GetLinkInterfaceDependentNumberMinProperty(const std::string &p, - const std::string& config) const; - const char *GetLinkInterfaceDependentNumberMaxProperty(const std::string &p, - const std::string& config) const; std::string GetDebugGeneratorExpressions(const std::string &value, cmTarget::LinkLibraryType llt) const; void AddSystemIncludeDirectories(const std::set<std::string> &incs); - void AddSystemIncludeDirectories(const std::vector<std::string> &incs); std::set<std::string> const & GetSystemIncludeDirectories() const { return this->SystemIncludeDirectories; } bool LinkLanguagePropagatesToDependents() const { return this->TargetTypeValue == STATIC_LIBRARY; } - void ReportPropertyOrigin(const std::string &p, - const std::string &result, - const std::string &report, - const std::string &compatibilityType) const; - std::map<std::string, std::string> const& GetMaxLanguageStandards() const { @@ -684,11 +502,6 @@ private: const char* GetSuffixVariableInternal(bool implib) const; const char* GetPrefixVariableInternal(bool implib) const; - std::string GetFullNameInternal(const std::string& config, - bool implib) const; - void GetFullNameInternal(const std::string& config, bool implib, - std::string& outPrefix, std::string& outBase, - std::string& outSuffix) const; // Use a makefile variable to set a default for the given property. // If the variable is not defined use the given default instead. @@ -698,19 +511,12 @@ private: // Returns ARCHIVE, LIBRARY, or RUNTIME based on platform and type. const char* GetOutputTargetType(bool implib) const; - // Get the target base name. - std::string GetOutputName(const std::string& config, bool implib) const; - std::string GetFullNameImported(const std::string& config, bool implib) const; std::string ImportedGetFullPath(const std::string& config, bool implib) const; - /** Append to @a base the mac content directory and return it. */ - std::string BuildMacContentDirectory(const std::string& base, - const std::string& config, - bool contentOnly) const; void GetSourceFiles(std::vector<std::string> &files, const std::string& config) const; @@ -721,7 +527,6 @@ private: std::set<std::string> Utilities; mutable std::set<std::string> LinkImplicitNullProperties; std::map<std::string, cmListFileBacktrace> UtilityBacktraces; - mutable std::map<std::string, bool> DebugCompatiblePropertiesDone; mutable std::map<std::string, std::string> MaxLanguageStandards; cmPolicies::PolicyMap PolicyMap; std::string Name; @@ -768,27 +573,32 @@ private: std::string& out) const; // Cache import information from properties for each configuration. - struct ImportInfo; + struct ImportInfo + { + ImportInfo(): NoSOName(false), Multiplicity(0) {} + bool NoSOName; + int Multiplicity; + std::string Location; + std::string SOName; + std::string ImportLibrary; + std::string Languages; + std::string Libraries; + std::string LibrariesProp; + std::string SharedDeps; + }; + ImportInfo const* GetImportInfo(const std::string& config) const; void ComputeImportInfo(std::string const& desired_config, ImportInfo& info) const; - // Cache target compile paths for each configuration. - struct CompileInfo; - CompileInfo const* GetCompileInfo(const std::string& config) const; - - mutable cmTargetLinkInformationMap LinkInformation; - void CheckPropertyCompatibility(cmComputeLinkInformation *info, - const std::string& config) const; LinkInterface const* GetImportLinkInterface(const std::string& config, cmTarget const* head, bool usage_requirements_only) const; - LinkImplementationLibraries const* + cmLinkImplementationLibraries const* GetLinkImplementationLibrariesInternal(const std::string& config, cmTarget const* head) const; - void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const; void ExpandLinkItems(std::string const& prop, std::string const& value, std::string const& config, cmTarget const* headTarget, diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx index 7824c89..7dfe9ca 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.cxx +++ b/Source/cmTargetIncludeDirectoriesCommand.cxx @@ -75,7 +75,23 @@ bool cmTargetIncludeDirectoriesCommand tgt->InsertInclude(this->Join(content), lfbt, prepend); if (system) { - tgt->AddSystemIncludeDirectories(content); + std::string prefix = + this->Makefile->GetCurrentSourceDirectory() + std::string("/"); + std::set<std::string> sdirs; + for (std::vector<std::string>::const_iterator it = content.begin(); + it != content.end(); ++it) + { + if (cmSystemTools::FileIsFullPath(it->c_str()) + || cmGeneratorExpression::Find(*it) == 0) + { + sdirs.insert(*it); + } + else + { + sdirs.insert(prefix + *it); + } + } + tgt->AddSystemIncludeDirectories(sdirs); } return true; } @@ -91,7 +107,7 @@ void cmTargetIncludeDirectoriesCommand if (system) { - std::string joined = cmJoin(content, ";"); + std::string joined = this->Join(content); tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", joined.c_str()); } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 71785e9..80b8591 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1627,7 +1627,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( this->GlobalGenerator->GetLanguageFromExtension (sf.GetExtension().c_str()); std::string sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf); - const std::string& linkLanguage = this->Target->GetLinkerLanguage(); + const std::string& linkLanguage = this->GeneratorTarget->GetLinkerLanguage(); bool needForceLang = false; // source file does not match its extension language if(lang != sourceLang) @@ -1774,7 +1774,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() else { outDir = this->Target->GetDirectory(config->c_str()) + "/"; - targetNameFull = this->Target->GetFullName(config->c_str()); + targetNameFull = this->GeneratorTarget->GetFullName(config->c_str()); } this->ConvertToWindowsSlash(intermediateDir); this->ConvertToWindowsSlash(outDir); @@ -1888,7 +1888,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( std::string flags; const std::string& linkLanguage = - this->Target->GetLinkerLanguage(configName.c_str()); + this->GeneratorTarget->GetLinkerLanguage(configName.c_str()); if(linkLanguage.empty()) { cmSystemTools::Error @@ -2026,7 +2026,8 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( } // Specify the compiler program database file if configured. - std::string pdb = this->Target->GetCompilePDBPath(configName.c_str()); + std::string pdb = + this->GeneratorTarget->GetCompilePDBPath(configName.c_str()); if(!pdb.empty()) { this->ConvertToWindowsSlash(pdb); @@ -2370,7 +2371,7 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) Options& linkOptions = *pOptions; const std::string& linkLanguage = - this->Target->GetLinkerLanguage(config.c_str()); + this->GeneratorTarget->GetLinkerLanguage(config.c_str()); if(linkLanguage.empty()) { cmSystemTools::Error @@ -2438,7 +2439,7 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) cmSystemTools::ExpandListArgument(libs, libVec); cmComputeLinkInformation* pcli = - this->Target->GetLinkInformation(config.c_str()); + this->GeneratorTarget->GetLinkInformation(config.c_str()); if(!pcli) { cmSystemTools::Error @@ -2471,13 +2472,14 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) std::string targetNamePDB; if(this->Target->GetType() == cmTarget::EXECUTABLE) { - this->Target->GetExecutableNames(targetName, targetNameFull, + this->GeneratorTarget->GetExecutableNames(targetName, targetNameFull, targetNameImport, targetNamePDB, config.c_str()); } else { - this->Target->GetLibraryNames(targetName, targetNameSO, targetNameFull, + this->GeneratorTarget->GetLibraryNames(targetName, targetNameSO, + targetNameFull, targetNameImport, targetNamePDB, config.c_str()); } diff --git a/Source/cmXCodeObject.cxx b/Source/cmXCodeObject.cxx index e72d315..c59c360 100644 --- a/Source/cmXCodeObject.cxx +++ b/Source/cmXCodeObject.cxx @@ -243,7 +243,11 @@ void cmXCodeObject::PrintString(std::ostream& os,std::string String) bool needQuote = (String.empty() || String.find("//") != String.npos || - String.find_first_of(" <>+-*=@[](){},") != String.npos); + String.find_first_not_of( + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "$_./") != String.npos); const char* quote = needQuote? "\"" : ""; // Print the string, quoted and escaped as necessary. diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 9d2c19e..dbbe07d 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -75,7 +75,9 @@ # include "cmGlobalWatcomWMakeGenerator.h" #endif #include "cmGlobalUnixMakefileGenerator3.h" -#include "cmGlobalNinjaGenerator.h" +#if defined(CMAKE_BUILD_WITH_CMAKE) +# include "cmGlobalNinjaGenerator.h" +#endif #include "cmExtraCodeLiteGenerator.h" #if !defined(CMAKE_BOOT_MINGW) @@ -1447,7 +1449,7 @@ int cmake::ActualConfigure() } } - cmMakefile* mf=this->GlobalGenerator->GetLocalGenerators()[0]->GetMakefile(); + cmMakefile* mf=this->GlobalGenerator->GetMakefiles()[0]; if (mf->IsOn("CTEST_USE_LAUNCHERS") && !this->State->GetGlobalProperty("RULE_LAUNCH_COMPILE")) { @@ -1607,7 +1609,11 @@ int cmake::Generate() { return -1; } - this->GlobalGenerator->DoGenerate(); + if (!this->GlobalGenerator->Compute()) + { + return -1; + } + this->GlobalGenerator->Generate(); if ( !this->GraphVizFile.empty() ) { std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl; @@ -1696,8 +1702,10 @@ void cmake::AddDefaultGenerators() #endif this->Generators.push_back( cmGlobalUnixMakefileGenerator3::NewFactory()); +#if defined(CMAKE_BUILD_WITH_CMAKE) this->Generators.push_back( cmGlobalNinjaGenerator::NewFactory()); +#endif #if defined(CMAKE_USE_WMAKE) this->Generators.push_back( cmGlobalWatcomWMakeGenerator::NewFactory()); @@ -2576,6 +2584,25 @@ int cmake::Build(const std::string& dir, } std::string cachePath = dir; cmSystemTools::ConvertToUnixSlashes(cachePath); + std::string cacheFile = cachePath; + cacheFile += "/CMakeCache.txt"; + if(!cmSystemTools::FileExists(cacheFile.c_str())) + { + // search in parent directories for cache + std::string cmakeFiles = cachePath; + cmakeFiles += "/CMakeFiles"; + if(cmSystemTools::FileExists(cmakeFiles.c_str())) + { + std::string cachePathFound = + cmSystemTools::FileExistsInParentDirectories( + "CMakeCache.txt", cachePath.c_str(), "/"); + if(!cachePathFound.empty()) + { + cachePath = cmSystemTools::GetFilenamePath(cachePathFound); + } + } + } + if(!this->LoadCache(cachePath)) { std::cerr << "Error: could not load cache\n"; diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 71f47f3..7bee0ea 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -1468,18 +1468,24 @@ bool cmcmd::RunCommand(const char* comment, std::string output; int retCode =0; // use rc command to create .res file - cmSystemTools::RunSingleCommand(command, - &output, &output, - &retCode, 0, cmSystemTools::OUTPUT_NONE); + bool res = cmSystemTools::RunSingleCommand(command, + &output, &output, + &retCode, 0, + cmSystemTools::OUTPUT_NONE); // always print the output of the command, unless // it is the dumb rc command banner, but if the command // returned an error code then print the output anyway as // the banner may be mixed with some other important information. if(output.find("Resource Compiler Version") == output.npos - || retCode !=0) + || !res || retCode) { std::cout << output; } + if (!res) + { + std::cout << comment << " failed to run." << std::endl; + return false; + } // if retCodeOut is requested then always return true // and set the retCodeOut to retCode if(retCodeOut) @@ -1593,7 +1599,10 @@ int cmcmd::VisualStudioLinkIncremental(std::vector<std::string>& args, mtCommand.push_back(tempManifest); // now run mt.exe to create the final manifest file int mtRet =0; - cmcmd::RunCommand("MT", mtCommand, verbose, &mtRet); + if(!cmcmd::RunCommand("MT", mtCommand, verbose, &mtRet)) + { + return -1; + } // if mt returns 0, then the manifest was not changed and // we do not need to do another link step if(mtRet == 0) diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 7eb678b..017d619 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -1237,7 +1237,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) IF(NOT CYGWIN) SET(KWSYS_TEST_PROCESS_7 7) ENDIF() - FOREACH(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7}) + FOREACH(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10) ADD_TEST(kwsys.testProcess-${n} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n}) SET_PROPERTY(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST}) SET_TESTS_PROPERTIES(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120) @@ -1270,6 +1270,10 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) MESSAGE(STATUS "GET_TEST_PROPERTY returned: ${wfv}") ENDIF() + # Set up ctest custom configuration file. + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/CTestCustom.cmake.in + ${PROJECT_BINARY_DIR}/CTestCustom.cmake @ONLY) + # Suppress known consistent failures on buggy systems. IF(KWSYS_TEST_BOGUS_FAILURES) SET_TESTS_PROPERTIES(${KWSYS_TEST_BOGUS_FAILURES} PROPERTIES WILL_FAIL ON) diff --git a/Source/kwsys/CTestCustom.cmake.in b/Source/kwsys/CTestCustom.cmake.in new file mode 100644 index 0000000..d6f802e --- /dev/null +++ b/Source/kwsys/CTestCustom.cmake.in @@ -0,0 +1,15 @@ +# kwsys.testProcess-10 involves sending SIGINT to a child process, which then +# exits abnormally via a call to _exit(). (On Windows, a call to ExitProcess). +# Naturally, this results in plenty of memory being "leaked" by this child +# process - the memory check results are not meaningful in this case. +# +# kwsys.testProcess-9 also tests sending SIGINT to a child process. However, +# normal operation of that test involves the child process timing out, and the +# host process kills (SIGKILL) it as a result. Since it was SIGKILL'ed, the +# resulting memory leaks are not logged by valgrind anyway. Therefore, we +# don't have to exclude it. + +set(CTEST_CUSTOM_MEMCHECK_IGNORE + ${CTEST_CUSTOM_MEMCHECK_IGNORE} + kwsys.testProcess-10 + ) diff --git a/Source/kwsys/EncodingC.c b/Source/kwsys/EncodingC.c index ba2cec2..32b9bff 100644 --- a/Source/kwsys/EncodingC.c +++ b/Source/kwsys/EncodingC.c @@ -45,8 +45,11 @@ wchar_t* kwsysEncoding_DupToWide(const char* str) if(length > 0) { ret = (wchar_t*)malloc((length)*sizeof(wchar_t)); - ret[0] = 0; - kwsysEncoding_mbstowcs(ret, str, length); + if(ret) + { + ret[0] = 0; + kwsysEncoding_mbstowcs(ret, str, length); + } } return ret; } @@ -72,8 +75,11 @@ char* kwsysEncoding_DupToNarrow(const wchar_t* str) if(length > 0) { ret = (char*)malloc(length); - ret[0] = 0; - kwsysEncoding_wcstombs(ret, str, length); + if(ret) + { + ret[0] = 0; + kwsysEncoding_wcstombs(ret, str, length); + } } return ret; } diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in index e35939f..c5ebc97 100644 --- a/Source/kwsys/Process.h.in +++ b/Source/kwsys/Process.h.in @@ -23,58 +23,60 @@ # define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT #endif #if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define kwsysProcess kwsys_ns(Process) -# define kwsysProcess_s kwsys_ns(Process_s) -# define kwsysProcess_New kwsys_ns(Process_New) -# define kwsysProcess_Delete kwsys_ns(Process_Delete) -# define kwsysProcess_SetCommand kwsys_ns(Process_SetCommand) -# define kwsysProcess_AddCommand kwsys_ns(Process_AddCommand) -# define kwsysProcess_SetTimeout kwsys_ns(Process_SetTimeout) -# define kwsysProcess_SetWorkingDirectory kwsys_ns(Process_SetWorkingDirectory) -# define kwsysProcess_SetPipeFile kwsys_ns(Process_SetPipeFile) -# define kwsysProcess_SetPipeNative kwsys_ns(Process_SetPipeNative) -# define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared) -# define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach) -# define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow) -# define kwsysProcess_Option_MergeOutput kwsys_ns(Process_Option_MergeOutput) -# define kwsysProcess_Option_Verbatim kwsys_ns(Process_Option_Verbatim) -# define kwsysProcess_GetOption kwsys_ns(Process_GetOption) -# define kwsysProcess_SetOption kwsys_ns(Process_SetOption) -# define kwsysProcess_Option_e kwsys_ns(Process_Option_e) -# define kwsysProcess_State_Starting kwsys_ns(Process_State_Starting) -# define kwsysProcess_State_Error kwsys_ns(Process_State_Error) -# define kwsysProcess_State_Exception kwsys_ns(Process_State_Exception) -# define kwsysProcess_State_Executing kwsys_ns(Process_State_Executing) -# define kwsysProcess_State_Exited kwsys_ns(Process_State_Exited) -# define kwsysProcess_State_Expired kwsys_ns(Process_State_Expired) -# define kwsysProcess_State_Killed kwsys_ns(Process_State_Killed) -# define kwsysProcess_State_Disowned kwsys_ns(Process_State_Disowned) -# define kwsysProcess_GetState kwsys_ns(Process_GetState) -# define kwsysProcess_State_e kwsys_ns(Process_State_e) -# define kwsysProcess_Exception_None kwsys_ns(Process_Exception_None) -# define kwsysProcess_Exception_Fault kwsys_ns(Process_Exception_Fault) -# define kwsysProcess_Exception_Illegal kwsys_ns(Process_Exception_Illegal) -# define kwsysProcess_Exception_Interrupt kwsys_ns(Process_Exception_Interrupt) -# define kwsysProcess_Exception_Numerical kwsys_ns(Process_Exception_Numerical) -# define kwsysProcess_Exception_Other kwsys_ns(Process_Exception_Other) -# define kwsysProcess_GetExitException kwsys_ns(Process_GetExitException) -# define kwsysProcess_Exception_e kwsys_ns(Process_Exception_e) -# define kwsysProcess_GetExitCode kwsys_ns(Process_GetExitCode) -# define kwsysProcess_GetExitValue kwsys_ns(Process_GetExitValue) -# define kwsysProcess_GetErrorString kwsys_ns(Process_GetErrorString) -# define kwsysProcess_GetExceptionString kwsys_ns(Process_GetExceptionString) -# define kwsysProcess_Execute kwsys_ns(Process_Execute) -# define kwsysProcess_Disown kwsys_ns(Process_Disown) -# define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData) -# define kwsysProcess_Pipes_e kwsys_ns(Process_Pipes_e) -# define kwsysProcess_Pipe_None kwsys_ns(Process_Pipe_None) -# define kwsysProcess_Pipe_STDIN kwsys_ns(Process_Pipe_STDIN) -# define kwsysProcess_Pipe_STDOUT kwsys_ns(Process_Pipe_STDOUT) -# define kwsysProcess_Pipe_STDERR kwsys_ns(Process_Pipe_STDERR) -# define kwsysProcess_Pipe_Timeout kwsys_ns(Process_Pipe_Timeout) -# define kwsysProcess_Pipe_Handle kwsys_ns(Process_Pipe_Handle) -# define kwsysProcess_WaitForExit kwsys_ns(Process_WaitForExit) -# define kwsysProcess_Kill kwsys_ns(Process_Kill) +# define kwsysProcess kwsys_ns(Process) +# define kwsysProcess_s kwsys_ns(Process_s) +# define kwsysProcess_New kwsys_ns(Process_New) +# define kwsysProcess_Delete kwsys_ns(Process_Delete) +# define kwsysProcess_SetCommand kwsys_ns(Process_SetCommand) +# define kwsysProcess_AddCommand kwsys_ns(Process_AddCommand) +# define kwsysProcess_SetTimeout kwsys_ns(Process_SetTimeout) +# define kwsysProcess_SetWorkingDirectory kwsys_ns(Process_SetWorkingDirectory) +# define kwsysProcess_SetPipeFile kwsys_ns(Process_SetPipeFile) +# define kwsysProcess_SetPipeNative kwsys_ns(Process_SetPipeNative) +# define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared) +# define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach) +# define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow) +# define kwsysProcess_Option_MergeOutput kwsys_ns(Process_Option_MergeOutput) +# define kwsysProcess_Option_Verbatim kwsys_ns(Process_Option_Verbatim) +# define kwsysProcess_Option_CreateProcessGroup kwsys_ns(Process_Option_CreateProcessGroup) +# define kwsysProcess_GetOption kwsys_ns(Process_GetOption) +# define kwsysProcess_SetOption kwsys_ns(Process_SetOption) +# define kwsysProcess_Option_e kwsys_ns(Process_Option_e) +# define kwsysProcess_State_Starting kwsys_ns(Process_State_Starting) +# define kwsysProcess_State_Error kwsys_ns(Process_State_Error) +# define kwsysProcess_State_Exception kwsys_ns(Process_State_Exception) +# define kwsysProcess_State_Executing kwsys_ns(Process_State_Executing) +# define kwsysProcess_State_Exited kwsys_ns(Process_State_Exited) +# define kwsysProcess_State_Expired kwsys_ns(Process_State_Expired) +# define kwsysProcess_State_Killed kwsys_ns(Process_State_Killed) +# define kwsysProcess_State_Disowned kwsys_ns(Process_State_Disowned) +# define kwsysProcess_GetState kwsys_ns(Process_GetState) +# define kwsysProcess_State_e kwsys_ns(Process_State_e) +# define kwsysProcess_Exception_None kwsys_ns(Process_Exception_None) +# define kwsysProcess_Exception_Fault kwsys_ns(Process_Exception_Fault) +# define kwsysProcess_Exception_Illegal kwsys_ns(Process_Exception_Illegal) +# define kwsysProcess_Exception_Interrupt kwsys_ns(Process_Exception_Interrupt) +# define kwsysProcess_Exception_Numerical kwsys_ns(Process_Exception_Numerical) +# define kwsysProcess_Exception_Other kwsys_ns(Process_Exception_Other) +# define kwsysProcess_GetExitException kwsys_ns(Process_GetExitException) +# define kwsysProcess_Exception_e kwsys_ns(Process_Exception_e) +# define kwsysProcess_GetExitCode kwsys_ns(Process_GetExitCode) +# define kwsysProcess_GetExitValue kwsys_ns(Process_GetExitValue) +# define kwsysProcess_GetErrorString kwsys_ns(Process_GetErrorString) +# define kwsysProcess_GetExceptionString kwsys_ns(Process_GetExceptionString) +# define kwsysProcess_Execute kwsys_ns(Process_Execute) +# define kwsysProcess_Disown kwsys_ns(Process_Disown) +# define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData) +# define kwsysProcess_Pipes_e kwsys_ns(Process_Pipes_e) +# define kwsysProcess_Pipe_None kwsys_ns(Process_Pipe_None) +# define kwsysProcess_Pipe_STDIN kwsys_ns(Process_Pipe_STDIN) +# define kwsysProcess_Pipe_STDOUT kwsys_ns(Process_Pipe_STDOUT) +# define kwsysProcess_Pipe_STDERR kwsys_ns(Process_Pipe_STDERR) +# define kwsysProcess_Pipe_Timeout kwsys_ns(Process_Pipe_Timeout) +# define kwsysProcess_Pipe_Handle kwsys_ns(Process_Pipe_Handle) +# define kwsysProcess_WaitForExit kwsys_ns(Process_WaitForExit) +# define kwsysProcess_Interrupt kwsys_ns(Process_Interrupt) +# define kwsysProcess_Kill kwsys_ns(Process_Kill) #endif #if defined(__cplusplus) @@ -199,6 +201,15 @@ kwsysEXPORT void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, * and ignore the rest of the arguments. * 0 = No (default) * 1 = Yes + * + * kwsysProcess_Option_CreateProcessGroup = Whether to place the process in a + * new process group. This is + * useful if you want to send Ctrl+C + * to the process. On UNIX, also + * places the process in a new + * session. + * 0 = No (default) + * 1 = Yes */ kwsysEXPORT int kwsysProcess_GetOption(kwsysProcess* cp, int optionId); kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, @@ -208,7 +219,8 @@ enum kwsysProcess_Option_e kwsysProcess_Option_HideWindow, kwsysProcess_Option_Detach, kwsysProcess_Option_MergeOutput, - kwsysProcess_Option_Verbatim + kwsysProcess_Option_Verbatim, + kwsysProcess_Option_CreateProcessGroup }; /** @@ -363,6 +375,17 @@ enum kwsysProcess_Pipes_e kwsysEXPORT int kwsysProcess_WaitForExit(kwsysProcess* cp, double* timeout); /** + * Interrupt the process group for the child process that is currently + * running by sending it the appropriate operating-system specific signal. + * The caller should call WaitForExit after this returns to wait for the + * child to terminate. + * + * WARNING: If you didn't specify kwsysProcess_Option_CreateProcessGroup, + * you will interrupt your own process group. + */ +kwsysEXPORT void kwsysProcess_Interrupt(kwsysProcess* cp); + +/** * Forcefully terminate the child process that is currently running. * The caller should call WaitForExit after this returns to wait for * the child to terminate. @@ -394,6 +417,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp); # undef kwsysProcess_Option_HideWindow # undef kwsysProcess_Option_MergeOutput # undef kwsysProcess_Option_Verbatim +# undef kwsysProcess_Option_CreateProcessGroup # undef kwsysProcess_GetOption # undef kwsysProcess_SetOption # undef kwsysProcess_Option_e @@ -430,6 +454,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp); # undef kwsysProcess_Pipe_Timeout # undef kwsysProcess_Pipe_Handle # undef kwsysProcess_WaitForExit +# undef kwsysProcess_Interrupt # undef kwsysProcess_Kill # endif #endif diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index 0393a6d..6d9b109 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -88,7 +88,7 @@ typedef ssize_t kwsysProcess_ssize_t; typedef int kwsysProcess_ssize_t; #endif -#if defined(__BEOS__) && !defined(__ZETA__) +#if defined(__BEOS__) && !defined(__ZETA__) /* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */ # include <be/kernel/OS.h> static inline void kwsysProcess_usleep(unsigned int msec) @@ -151,6 +151,7 @@ typedef struct kwsysProcessCreateInformation_s } kwsysProcessCreateInformation; /*--------------------------------------------------------------------------*/ +static void kwsysProcessVolatileFree(volatile void* p); static int kwsysProcessInitialize(kwsysProcess* cp); static void kwsysProcessCleanup(kwsysProcess* cp, int error); static void kwsysProcessCleanupDescriptor(int* pfd); @@ -197,7 +198,7 @@ struct kwsysProcess_s { /* The command lines to execute. */ char*** Commands; - int NumberOfCommands; + volatile int NumberOfCommands; /* Descriptors for the read ends of the child's output pipes and the signal pipe. */ @@ -213,8 +214,10 @@ struct kwsysProcess_s /* Buffer for pipe data. */ char PipeBuffer[KWSYSPE_PIPE_BUFFER_SIZE]; - /* Process IDs returned by the calls to fork. */ - pid_t* ForkPIDs; + /* Process IDs returned by the calls to fork. Everything is volatile + because the signal handler accesses them. You must be very careful + when reaping PIDs or modifying this array to avoid race conditions. */ + volatile pid_t* volatile ForkPIDs; /* Flag for whether the children were terminated by a faild select. */ int SelectError; @@ -237,6 +240,9 @@ struct kwsysProcess_s /* Whether to merge stdout/stderr of the child. */ int MergeOutput; + /* Whether to create the process in a new process group. */ + volatile sig_atomic_t CreateProcessGroup; + /* Time at which the child started. Negative for no timeout. */ kwsysProcessTime StartTime; @@ -257,8 +263,9 @@ struct kwsysProcess_s /* The number of children still executing. */ int CommandsLeft; - /* The current status of the child process. */ - int State; + /* The current status of the child process. Must be atomic because + the signal handler checks this to avoid a race. */ + volatile sig_atomic_t State; /* The exceptional behavior that terminated the child process, if * any. */ @@ -271,7 +278,7 @@ struct kwsysProcess_s int ExitValue; /* Whether the process was killed. */ - int Killed; + volatile sig_atomic_t Killed; /* Buffer for error message in case of failure. */ char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1]; @@ -649,6 +656,8 @@ int kwsysProcess_GetOption(kwsysProcess* cp, int optionId) case kwsysProcess_Option_Detach: return cp->OptionDetach; case kwsysProcess_Option_MergeOutput: return cp->MergeOutput; case kwsysProcess_Option_Verbatim: return cp->Verbatim; + case kwsysProcess_Option_CreateProcessGroup: + return cp->CreateProcessGroup; default: return 0; } } @@ -666,6 +675,8 @@ void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value) case kwsysProcess_Option_Detach: cp->OptionDetach = value; break; case kwsysProcess_Option_MergeOutput: cp->MergeOutput = value; break; case kwsysProcess_Option_Verbatim: cp->Verbatim = value; break; + case kwsysProcess_Option_CreateProcessGroup: + cp->CreateProcessGroup = value; break; default: break; } } @@ -1490,6 +1501,45 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) } /*--------------------------------------------------------------------------*/ +void kwsysProcess_Interrupt(kwsysProcess* cp) +{ + int i; + /* Make sure we are executing a process. */ + if(!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired || + cp->Killed) + { + return; + } + + /* Interrupt the children. */ + if (cp->CreateProcessGroup) + { + if(cp->ForkPIDs) + { + for(i=0; i < cp->NumberOfCommands; ++i) + { + /* Make sure the PID is still valid. */ + if(cp->ForkPIDs[i]) + { + /* The user created a process group for this process. The group ID + is the process ID for the original process in the group. */ + kill(-cp->ForkPIDs[i], SIGINT); + } + } + } + } + else + { + /* No process group was created. Kill our own process group. + NOTE: While one could argue that we could call kill(cp->ForkPIDs[i], + SIGINT) as a way to still interrupt the process even though it's not in + a special group, this is not an option on Windows. Therefore, we kill + the current process group for consistency with Windows. */ + kill(0, SIGINT); + } +} + +/*--------------------------------------------------------------------------*/ void kwsysProcess_Kill(kwsysProcess* cp) { int i; @@ -1539,10 +1589,28 @@ void kwsysProcess_Kill(kwsysProcess* cp) } /*--------------------------------------------------------------------------*/ +/* Call the free() function with a pointer to volatile without causing + compiler warnings. */ +static void kwsysProcessVolatileFree(volatile void* p) +{ + /* clang has made it impossible to free memory that points to volatile + without first using special pragmas to disable a warning... */ +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wcast-qual" +#endif + free((void*)p); /* The cast will silence most compilers, but not clang. */ +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +} + +/*--------------------------------------------------------------------------*/ /* Initialize a process control structure for kwsysProcess_Execute. */ static int kwsysProcessInitialize(kwsysProcess* cp) { int i; + volatile pid_t* oldForkPIDs; for(i=0; i < KWSYSPE_PIPE_COUNT; ++i) { cp->PipeReadEnds[i] = -1; @@ -1571,16 +1639,21 @@ static int kwsysProcessInitialize(kwsysProcess* cp) cp->ErrorMessage[0] = 0; strcpy(cp->ExitExceptionString, "No exception"); - if(cp->ForkPIDs) + oldForkPIDs = cp->ForkPIDs; + cp->ForkPIDs = (volatile pid_t*)malloc( + sizeof(volatile pid_t)*(size_t)(cp->NumberOfCommands)); + if(oldForkPIDs) { - free(cp->ForkPIDs); + kwsysProcessVolatileFree(oldForkPIDs); } - cp->ForkPIDs = (pid_t*)malloc(sizeof(pid_t)*(size_t)(cp->NumberOfCommands)); if(!cp->ForkPIDs) { return 0; } - memset(cp->ForkPIDs, 0, sizeof(pid_t)*(size_t)(cp->NumberOfCommands)); + for(i=0; i < cp->NumberOfCommands; ++i) + { + cp->ForkPIDs[i] = 0; /* can't use memset due to volatile */ + } if(cp->CommandExitCodes) { @@ -1671,7 +1744,7 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error) /* Free memory. */ if(cp->ForkPIDs) { - free(cp->ForkPIDs); + kwsysProcessVolatileFree(cp->ForkPIDs); cp->ForkPIDs = 0; } if(cp->RealWorkingDirectory) @@ -1758,15 +1831,49 @@ int decc$set_child_standard_streams(int fd1, int fd2, int fd3); static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, kwsysProcessCreateInformation* si) { + sigset_t mask, old_mask; + int pgidPipe[2]; + char tmp; + ssize_t readRes; + /* Create the error reporting pipe. */ if(pipe(si->ErrorPipe) < 0) { return 0; } - /* Set close-on-exec flag on the error pipe's write end. */ - if(fcntl(si->ErrorPipe[1], F_SETFD, FD_CLOEXEC) < 0) + /* Create a pipe for detecting that the child process has created a process + group and session. */ + if(pipe(pgidPipe) < 0) { + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); + return 0; + } + + /* Set close-on-exec flag on the pipe's write end. */ + if(fcntl(si->ErrorPipe[1], F_SETFD, FD_CLOEXEC) < 0 || + fcntl(pgidPipe[1], F_SETFD, FD_CLOEXEC) < 0) + { + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); + kwsysProcessCleanupDescriptor(&pgidPipe[0]); + kwsysProcessCleanupDescriptor(&pgidPipe[1]); + return 0; + } + + /* Block SIGINT / SIGTERM while we start. The purpose is so that our signal + handler doesn't get called from the child process after the fork and + before the exec, and subsequently start kill()'ing PIDs from ForkPIDs. */ + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + if(sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) + { + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); + kwsysProcessCleanupDescriptor(&pgidPipe[0]); + kwsysProcessCleanupDescriptor(&pgidPipe[1]); return 0; } @@ -1774,13 +1881,19 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, #if defined(__VMS) /* VMS needs vfork and execvp to be in the same function because they use setjmp/longjmp to run the child startup code in the - parent! TODO: OptionDetach. */ + parent! TODO: OptionDetach. Also + TODO: CreateProcessGroup. */ cp->ForkPIDs[prIndex] = vfork(); #else cp->ForkPIDs[prIndex] = kwsysProcessFork(cp, si); #endif if(cp->ForkPIDs[prIndex] < 0) { + sigprocmask(SIG_SETMASK, &old_mask, 0); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); + kwsysProcessCleanupDescriptor(&pgidPipe[0]); + kwsysProcessCleanupDescriptor(&pgidPipe[1]); return 0; } @@ -1790,8 +1903,10 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, /* Specify standard pipes for child process. */ decc$set_child_standard_streams(si->StdIn, si->StdOut, si->StdErr); #else - /* Close the read end of the error reporting pipe. */ + /* Close the read end of the error reporting / process group + setup pipe. */ close(si->ErrorPipe[0]); + close(pgidPipe[0]); /* Setup the stdin, stdout, and stderr pipes. */ if(si->StdIn > 0) @@ -1819,11 +1934,25 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, /* Restore all default signal handlers. */ kwsysProcessRestoreDefaultSignalHandlers(); + + /* Now that we have restored default signal handling and created the + process group, restore mask. */ + sigprocmask(SIG_SETMASK, &old_mask, 0); + + /* Create new process group. We use setsid instead of setpgid to avoid + the child getting hung up on signals like SIGTTOU. (In the real world, + this has been observed where "git svn" ends up calling the "resize" + program which opens /dev/tty. */ + if(cp->CreateProcessGroup && setsid() < 0) + { + kwsysProcessChildErrorExit(si->ErrorPipe[1]); + } #endif /* Execute the real process. If successful, this does not return. */ execvp(cp->Commands[prIndex][0], cp->Commands[prIndex]); /* TODO: What does VMS do if the child fails to start? */ + /* TODO: On VMS, how do we put the process in a new group? */ /* Failure. Report error to parent and terminate. */ kwsysProcessChildErrorExit(si->ErrorPipe[1]); @@ -1834,12 +1963,34 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, decc$set_child_standard_streams(0, 1, 2); #endif + /* We are done with the error reporting pipe and process group setup pipe + write end. */ + kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); + kwsysProcessCleanupDescriptor(&pgidPipe[1]); + + /* Make sure the child is in the process group before we proceed. This + avoids race conditions with calls to the kill function that we make for + signalling process groups. */ + while((readRes = read(pgidPipe[0], &tmp, 1)) > 0); + if(readRes < 0) + { + sigprocmask(SIG_SETMASK, &old_mask, 0); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&pgidPipe[0]); + return 0; + } + kwsysProcessCleanupDescriptor(&pgidPipe[0]); + + /* Unmask signals. */ + if(sigprocmask(SIG_SETMASK, &old_mask, 0) < 0) + { + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + return 0; + } + /* A child has been created. */ ++cp->CommandsLeft; - /* We are done with the error reporting pipe write end. */ - kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); - /* Block until the child's exec call succeeds and closes the error pipe or writes data to the pipe to report an error. */ { @@ -1877,6 +2028,17 @@ static void kwsysProcessDestroy(kwsysProcess* cp) /* A child process has terminated. Reap it if it is one handled by this object. */ int i; + /* Temporarily disable signals that access ForkPIDs. We don't want them to + read a reaped PID, and writes to ForkPIDs are not atomic. */ + sigset_t mask, old_mask; + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + if(sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) + { + return; + } + for(i=0; i < cp->NumberOfCommands; ++i) { if(cp->ForkPIDs[i]) @@ -1910,6 +2072,9 @@ static void kwsysProcessDestroy(kwsysProcess* cp) } } } + + /* Re-enable signals. */ + sigprocmask(SIG_SETMASK, &old_mask, 0); } /*--------------------------------------------------------------------------*/ @@ -1938,7 +2103,7 @@ static int kwsysProcessSetupOutputPipeFile(int* p, const char* name) /* Assign the replacement descriptor. */ *p = fout; - return 1; + return 1; } /*--------------------------------------------------------------------------*/ @@ -2582,19 +2747,23 @@ typedef struct kwsysProcessInstances_s } kwsysProcessInstances; static kwsysProcessInstances kwsysProcesses; -/* The old SIGCHLD handler. */ +/* The old SIGCHLD / SIGINT / SIGTERM handlers. */ static struct sigaction kwsysProcessesOldSigChldAction; +static struct sigaction kwsysProcessesOldSigIntAction; +static struct sigaction kwsysProcessesOldSigTermAction; /*--------------------------------------------------------------------------*/ static void kwsysProcessesUpdate(kwsysProcessInstances* newProcesses) { - /* Block SIGCHLD while we update the set of pipes to check. + /* Block signals while we update the set of pipes to check. TODO: sigprocmask is undefined for threaded apps. See pthread_sigmask. */ sigset_t newset; sigset_t oldset; sigemptyset(&newset); sigaddset(&newset, SIGCHLD); + sigaddset(&newset, SIGINT); + sigaddset(&newset, SIGTERM); sigprocmask(SIG_BLOCK, &newset, &oldset); /* Store the new set in that seen by the signal handler. */ @@ -2686,21 +2855,36 @@ static int kwsysProcessesAdd(kwsysProcess* cp) { /* Install our handler for SIGCHLD. Repeat call until it is not interrupted. */ - struct sigaction newSigChldAction; - memset(&newSigChldAction, 0, sizeof(struct sigaction)); + struct sigaction newSigAction; + memset(&newSigAction, 0, sizeof(struct sigaction)); #if KWSYSPE_USE_SIGINFO - newSigChldAction.sa_sigaction = kwsysProcessesSignalHandler; - newSigChldAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; + newSigAction.sa_sigaction = kwsysProcessesSignalHandler; + newSigAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; # ifdef SA_RESTART - newSigChldAction.sa_flags |= SA_RESTART; + newSigAction.sa_flags |= SA_RESTART; # endif #else - newSigChldAction.sa_handler = kwsysProcessesSignalHandler; - newSigChldAction.sa_flags = SA_NOCLDSTOP; + newSigAction.sa_handler = kwsysProcessesSignalHandler; + newSigAction.sa_flags = SA_NOCLDSTOP; #endif - while((sigaction(SIGCHLD, &newSigChldAction, + sigemptyset(&newSigAction.sa_mask); + while((sigaction(SIGCHLD, &newSigAction, &kwsysProcessesOldSigChldAction) < 0) && (errno == EINTR)); + + /* Install our handler for SIGINT / SIGTERM. Repeat call until + it is not interrupted. */ + sigemptyset(&newSigAction.sa_mask); + sigaddset(&newSigAction.sa_mask, SIGTERM); + while((sigaction(SIGINT, &newSigAction, + &kwsysProcessesOldSigIntAction) < 0) && + (errno == EINTR)); + + sigemptyset(&newSigAction.sa_mask); + sigaddset(&newSigAction.sa_mask, SIGINT); + while((sigaction(SIGTERM, &newSigAction, + &kwsysProcessesOldSigIntAction) < 0) && + (errno == EINTR)); } } @@ -2734,10 +2918,14 @@ static void kwsysProcessesRemove(kwsysProcess* cp) /* If this was the last process, disable the signal handler. */ if(newProcesses.Count == 0) { - /* Restore the SIGCHLD handler. Repeat call until it is not + /* Restore the signal handlers. Repeat call until it is not interrupted. */ while((sigaction(SIGCHLD, &kwsysProcessesOldSigChldAction, 0) < 0) && (errno == EINTR)); + while((sigaction(SIGINT, &kwsysProcessesOldSigIntAction, 0) < 0) && + (errno == EINTR)); + while((sigaction(SIGTERM, &kwsysProcessesOldSigTermAction, 0) < 0) && + (errno == EINTR)); /* Free the table of process pointers since it is now empty. This is safe because the signal handler has been removed. */ @@ -2763,39 +2951,108 @@ static void kwsysProcessesSignalHandler(int signum #endif ) { - (void)signum; + int i, j, procStatus, old_errno = errno; #if KWSYSPE_USE_SIGINFO (void)info; (void)ucontext; #endif /* Signal all process objects that a child has terminated. */ - { - int i; - for(i=0; i < kwsysProcesses.Count; ++i) + switch(signum) { - /* Set the pipe in a signalled state. */ - char buf = 1; - kwsysProcess* cp = kwsysProcesses.Processes[i]; - kwsysProcess_ssize_t status= - read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1); - (void)status; - status=write(cp->SignalPipe, &buf, 1); - (void)status; + case SIGCHLD: + for(i=0; i < kwsysProcesses.Count; ++i) + { + /* Set the pipe in a signalled state. */ + char buf = 1; + kwsysProcess* cp = kwsysProcesses.Processes[i]; + kwsysProcess_ssize_t pipeStatus= + read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1); + (void)pipeStatus; + pipeStatus=write(cp->SignalPipe, &buf, 1); + (void)pipeStatus; + } + break; + case SIGINT: + case SIGTERM: + /* Signal child processes that are running in new process groups. */ + for(i=0; i < kwsysProcesses.Count; ++i) + { + kwsysProcess* cp = kwsysProcesses.Processes[i]; + /* Check Killed to avoid data race condition when killing. + Check State to avoid data race condition in kwsysProcessCleanup + when there is an error (it leaves a reaped PID). */ + if(cp->CreateProcessGroup && !cp->Killed && + cp->State != kwsysProcess_State_Error && cp->ForkPIDs) + { + for(j=0; j < cp->NumberOfCommands; ++j) + { + /* Make sure the PID is still valid. */ + if(cp->ForkPIDs[j]) + { + /* The user created a process group for this process. The group ID + is the process ID for the original process in the group. */ + kill(-cp->ForkPIDs[j], SIGINT); + } + } + } + } + + /* Wait for all processes to terminate. */ + while(wait(&procStatus) >= 0 || errno != ECHILD) + { + } + + /* Terminate the process, which is now in an inconsistent state + because we reaped all the PIDs that it may have been reaping + or may have reaped in the future. Reraise the signal so that + the proper exit code is returned. */ + { + /* Install default signal handler. */ + struct sigaction defSigAction; + sigset_t unblockSet; + memset(&defSigAction, 0, sizeof(defSigAction)); + defSigAction.sa_handler = SIG_DFL; + sigemptyset(&defSigAction.sa_mask); + while((sigaction(signum, &defSigAction, 0) < 0) && + (errno == EINTR)); + /* Unmask the signal. */ + sigemptyset(&unblockSet); + sigaddset(&unblockSet, signum); + sigprocmask(SIG_UNBLOCK, &unblockSet, 0); + /* Raise the signal again. */ + raise(signum); + /* We shouldn't get here... but if we do... */ + _exit(1); + } + /* break omitted to silence unreachable code clang compiler warning. */ } - } #if !KWSYSPE_USE_SIGINFO - /* Re-Install our handler for SIGCHLD. Repeat call until it is not - interrupted. */ + /* Re-Install our handler. Repeat call until it is not interrupted. */ { - struct sigaction newSigChldAction; - memset(&newSigChldAction, 0, sizeof(struct sigaction)); + struct sigaction newSigAction; + struct sigaction &oldSigAction; + memset(&newSigAction, 0, sizeof(struct sigaction)); newSigChldAction.sa_handler = kwsysProcessesSignalHandler; newSigChldAction.sa_flags = SA_NOCLDSTOP; - while((sigaction(SIGCHLD, &newSigChldAction, - &kwsysProcessesOldSigChldAction) < 0) && + sigemptyset(&newSigAction.sa_mask); + switch(signum) + { + case SIGCHLD: oldSigAction = &kwsysProcessesOldSigChldAction; break; + case SIGINT: + sigaddset(&newSigAction.sa_mask, SIGTERM); + oldSigAction = &kwsysProcessesOldSigIntAction; break; + case SIGTERM: + sigaddset(&newSigAction.sa_mask, SIGINT); + oldSigAction = &kwsysProcessesOldSigTermAction; break; + default: return 0; + } + while((sigaction(signum, &newSigAction, + oldSigAction) < 0) && (errno == EINTR)); } #endif + + errno = old_errno; } diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index a7dd2ca..1f8749f 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -109,14 +109,15 @@ static DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd); static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, kwsysProcessPipeData* td); static int kwsysProcessInitialize(kwsysProcess* cp); -static int kwsysProcessCreate(kwsysProcess* cp, int index, - kwsysProcessCreateInformation* si); +static DWORD kwsysProcessCreate(kwsysProcess* cp, int index, + kwsysProcessCreateInformation* si); static void kwsysProcessDestroy(kwsysProcess* cp, int event); -static int kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name); +static DWORD kwsysProcessSetupOutputPipeFile(PHANDLE handle, + const char* name); static void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle); static void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle); static void kwsysProcessCleanupHandle(PHANDLE h); -static void kwsysProcessCleanup(kwsysProcess* cp, int error); +static void kwsysProcessCleanup(kwsysProcess* cp, DWORD error); static void kwsysProcessCleanErrorMessage(kwsysProcess* cp); static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, kwsysProcessTime* timeoutTime); @@ -133,6 +134,13 @@ static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProc static void kwsysProcessSetExitException(kwsysProcess* cp, int code); static void kwsysProcessKillTree(int pid); static void kwsysProcessDisablePipeThreads(kwsysProcess* cp); +static int kwsysProcessesInitialize(void); +static int kwsysTryEnterCreateProcessSection(void); +static void kwsysLeaveCreateProcessSection(void); +static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessId, + int newProcessGroup); +static void kwsysProcessesRemove(HANDLE hProcess); +static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType); /*--------------------------------------------------------------------------*/ /* A structure containing synchronization data for each thread. */ @@ -222,6 +230,9 @@ struct kwsysProcess_s /* Whether to merge stdout/stderr of the child. */ int MergeOutput; + /* Whether to create the process in a new process group. */ + int CreateProcessGroup; + /* Mutex to protect the shared index used by threads to report data. */ HANDLE SharedIndexMutex; @@ -321,6 +332,16 @@ kwsysProcess* kwsysProcess_New(void) /* Windows version number data. */ OSVERSIONINFO osv; + /* Initialize list of processes before we get any farther. It's especially + important that the console Ctrl handler be added BEFORE starting the + first process. This prevents the risk of an orphaned process being + started by the main thread while the default Ctrl handler is in + progress. */ + if(!kwsysProcessesInitialize()) + { + return 0; + } + /* Allocate a process control structure. */ cp = (kwsysProcess*)malloc(sizeof(kwsysProcess)); if(!cp) @@ -836,6 +857,8 @@ int kwsysProcess_GetOption(kwsysProcess* cp, int optionId) case kwsysProcess_Option_HideWindow: return cp->HideWindow; case kwsysProcess_Option_MergeOutput: return cp->MergeOutput; case kwsysProcess_Option_Verbatim: return cp->Verbatim; + case kwsysProcess_Option_CreateProcessGroup: + return cp->CreateProcessGroup; default: return 0; } } @@ -854,6 +877,8 @@ void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value) case kwsysProcess_Option_HideWindow: cp->HideWindow = value; break; case kwsysProcess_Option_MergeOutput: cp->MergeOutput = value; break; case kwsysProcess_Option_Verbatim: cp->Verbatim = value; break; + case kwsysProcess_Option_CreateProcessGroup: + cp->CreateProcessGroup = value; break; default: break; } } @@ -945,7 +970,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) if(!GetCurrentDirectoryW(cp->RealWorkingDirectoryLength, cp->RealWorkingDirectory)) { - kwsysProcessCleanup(cp, 1); + kwsysProcessCleanup(cp, GetLastError()); return; } SetCurrentDirectoryW(cp->WorkingDirectory); @@ -957,14 +982,16 @@ void kwsysProcess_Execute(kwsysProcess* cp) { /* Create a handle to read a file for stdin. */ wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN); + DWORD error; cp->PipeChildStd[0] = CreateFileW(wstdin, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); + error = GetLastError(); /* Check now in case free changes this. */ free(wstdin); if(cp->PipeChildStd[0] == INVALID_HANDLE_VALUE) { - kwsysProcessCleanup(cp, 1); + kwsysProcessCleanup(cp, error); return; } } @@ -990,17 +1017,18 @@ void kwsysProcess_Execute(kwsysProcess* cp) if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDOUT].Read, &cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, 0, 0)) { - kwsysProcessCleanup(cp, 1); + kwsysProcessCleanup(cp, GetLastError()); return; } if(cp->PipeFileSTDOUT) { /* Use a file for stdout. */ - if(!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1], - cp->PipeFileSTDOUT)) + DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1], + cp->PipeFileSTDOUT); + if(error) { - kwsysProcessCleanup(cp, 1); + kwsysProcessCleanup(cp, error); return; } } @@ -1023,7 +1051,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) GetCurrentProcess(), &cp->PipeChildStd[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) { - kwsysProcessCleanup(cp, 1); + kwsysProcessCleanup(cp, GetLastError()); return; } } @@ -1034,17 +1062,18 @@ void kwsysProcess_Execute(kwsysProcess* cp) if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read, &cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0)) { - kwsysProcessCleanup(cp, 1); + kwsysProcessCleanup(cp, GetLastError()); return; } if(cp->PipeFileSTDERR) { /* Use a file for stderr. */ - if(!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2], - cp->PipeFileSTDERR)) + DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2], + cp->PipeFileSTDERR); + if(error) { - kwsysProcessCleanup(cp, 1); + kwsysProcessCleanup(cp, error); return; } } @@ -1067,7 +1096,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) GetCurrentProcess(), &cp->PipeChildStd[2], 0, FALSE, DUPLICATE_SAME_ACCESS)) { - kwsysProcessCleanup(cp, 1); + kwsysProcessCleanup(cp, GetLastError()); return; } } @@ -1106,11 +1135,12 @@ void kwsysProcess_Execute(kwsysProcess* cp) HANDLE p[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; if (!CreatePipe(&p[0], &p[1], 0, 0)) { + DWORD error = GetLastError(); if (nextStdInput != cp->PipeChildStd[0]) { kwsysProcessCleanupHandle(&nextStdInput); } - kwsysProcessCleanup(cp, 1); + kwsysProcessCleanup(cp, error); return; } nextStdInput = p[0]; @@ -1119,7 +1149,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) si.hStdError = cp->MergeOutput? cp->PipeChildStd[1] : cp->PipeChildStd[2]; { - int res = kwsysProcessCreate(cp, i, &si); + DWORD error = kwsysProcessCreate(cp, i, &si); /* Close our copies of pipes used between children. */ if (si.hStdInput != cp->PipeChildStd[0]) @@ -1134,7 +1164,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) { kwsysProcessCleanupHandle(&si.hStdError); } - if (res) + if (!error) { cp->ProcessEvents[i+1] = cp->ProcessInformation[i].hProcess; } @@ -1144,7 +1174,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) { kwsysProcessCleanupHandle(&nextStdInput); } - kwsysProcessCleanup(cp, 1); + kwsysProcessCleanup(cp, error); return; } } @@ -1460,6 +1490,52 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) } /*--------------------------------------------------------------------------*/ +void kwsysProcess_Interrupt(kwsysProcess* cp) +{ + int i; + /* Make sure we are executing a process. */ + if(!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired || + cp->Killed) + { + KWSYSPE_DEBUG((stderr, "interrupt: child not executing\n")); + return; + } + + /* Skip actually interrupting the child if it has already terminated. */ + if(cp->Terminated) + { + KWSYSPE_DEBUG((stderr, "interrupt: child already terminated\n")); + return; + } + + /* Interrupt the children. */ + if (cp->CreateProcessGroup) + { + if(cp->ProcessInformation) + { + for(i=0; i < cp->NumberOfCommands; ++i) + { + /* Make sure the process handle isn't closed (e.g. from disowning). */ + if(cp->ProcessInformation[i].hProcess) + { + /* The user created a process group for this process. The group ID + is the process ID for the original process in the group. Note + that we have to use Ctrl+Break: Ctrl+C is not allowed for process + groups. */ + GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, + cp->ProcessInformation[i].dwProcessId); + } + } + } + } + else + { + /* No process group was created. Kill our own process group... */ + GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0); + } +} + +/*--------------------------------------------------------------------------*/ void kwsysProcess_Kill(kwsysProcess* cp) { int i; @@ -1487,7 +1563,8 @@ void kwsysProcess_Kill(kwsysProcess* cp) for(i=0; i < cp->NumberOfCommands; ++i) { kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId); - // close the handle if we kill it + /* Remove from global list of processes and close handles. */ + kwsysProcessesRemove(cp->ProcessInformation[i].hProcess); kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); } @@ -1686,7 +1763,7 @@ int kwsysProcessInitialize(kwsysProcess* cp) } /*--------------------------------------------------------------------------*/ -static int kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn) +static DWORD kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn) { DWORD flags; @@ -1697,13 +1774,19 @@ static int kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn) if (flags & HANDLE_FLAG_INHERIT) { *out = in; - return 1; + return ERROR_SUCCESS; } /* Create an inherited copy of this handle. */ - return DuplicateHandle(GetCurrentProcess(), in, - GetCurrentProcess(), out, - 0, TRUE, DUPLICATE_SAME_ACCESS); + if (DuplicateHandle(GetCurrentProcess(), in, GetCurrentProcess(), out, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + return ERROR_SUCCESS; + } + else + { + return GetLastError(); + } } else { @@ -1719,29 +1802,46 @@ static int kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn) (GENERIC_WRITE | FILE_READ_ATTRIBUTES)), FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0); - return *out != INVALID_HANDLE_VALUE; + return (*out != INVALID_HANDLE_VALUE) ? ERROR_SUCCESS : GetLastError(); } - } /*--------------------------------------------------------------------------*/ -int kwsysProcessCreate(kwsysProcess* cp, int index, - kwsysProcessCreateInformation* si) +DWORD kwsysProcessCreate(kwsysProcess* cp, int index, + kwsysProcessCreateInformation* si) { - int res = + DWORD creationFlags; + DWORD error = ERROR_SUCCESS; + + /* Check if we are currently exiting. */ + if (!kwsysTryEnterCreateProcessSection()) + { + /* The Ctrl handler is currently working on exiting our process. Rather + than return an error code, which could cause incorrect conclusions to be + reached by the caller, we simply hang. (For example, a CMake try_run + configure step might cause the project to configure wrong.) */ + Sleep(INFINITE); + } - /* Create inherited copies the handles. */ - kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput, - si->hStdInput, 1) && - kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput, - si->hStdOutput, 0) && - kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError, - si->hStdError, 0) && + /* Create the child in a suspended state so we can wait until all + children have been created before running any one. */ + creationFlags = CREATE_SUSPENDED; + if (cp->CreateProcessGroup) + { + creationFlags |= CREATE_NEW_PROCESS_GROUP; + } - /* Create the child in a suspended state so we can wait until all - children have been created before running any one. */ - CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, CREATE_SUSPENDED, 0, - 0, &si->StartupInfo, &cp->ProcessInformation[index]); + /* Create inherited copies of the handles. */ + (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput, + si->hStdInput, 1)) || + (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput, + si->hStdOutput, 0)) || + (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError, + si->hStdError, 0)) || + /* Create the process. */ + (!CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, creationFlags, 0, + 0, &si->StartupInfo, &cp->ProcessInformation[index]) && + (error = GetLastError())); /* Close the inherited copies of the handles. */ if (si->StartupInfo.hStdInput != si->hStdInput) @@ -1757,7 +1857,23 @@ int kwsysProcessCreate(kwsysProcess* cp, int index, kwsysProcessCleanupHandle(&si->StartupInfo.hStdError); } - return res; + /* Add the process to the global list of processes. */ + if (!error && + !kwsysProcessesAdd(cp->ProcessInformation[index].hProcess, + cp->ProcessInformation[index].dwProcessId, cp->CreateProcessGroup)) + { + /* This failed for some reason. Kill the suspended process. */ + TerminateProcess(cp->ProcessInformation[index].hProcess, 1); + /* And clean up... */ + kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess); + kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread); + strcpy(cp->ErrorMessage, "kwsysProcessesAdd function failed"); + error = ERROR_NOT_ENOUGH_MEMORY; /* Most likely reason. */ + } + + /* If the console Ctrl handler is waiting for us, this will release it... */ + kwsysLeaveCreateProcessSection(); + return error; } /*--------------------------------------------------------------------------*/ @@ -1779,6 +1895,9 @@ void kwsysProcessDestroy(kwsysProcess* cp, int event) GetExitCodeProcess(cp->ProcessInformation[index].hProcess, &cp->CommandExitCodes[index]); + /* Remove from global list of processes. */ + kwsysProcessesRemove(cp->ProcessInformation[index].hProcess); + /* Close the process handle for the terminated process. */ kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess); @@ -1813,13 +1932,14 @@ void kwsysProcessDestroy(kwsysProcess* cp, int event) } /*--------------------------------------------------------------------------*/ -int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name) +DWORD kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name) { HANDLE fout; wchar_t* wname; + DWORD error; if(!name) { - return 1; + return ERROR_INVALID_PARAMETER; } /* Close the existing handle. */ @@ -1829,15 +1949,16 @@ int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name) wname = kwsysEncoding_DupToWide(name); fout = CreateFileW(wname, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); + error = GetLastError(); free(wname); if(fout == INVALID_HANDLE_VALUE) { - return 0; + return error; } /* Assign the replacement handle. */ *phandle = fout; - return 1; + return ERROR_SUCCESS; } /*--------------------------------------------------------------------------*/ @@ -1876,7 +1997,7 @@ void kwsysProcessCleanupHandle(PHANDLE h) /*--------------------------------------------------------------------------*/ /* Close all handles created by kwsysProcess_Execute. */ -void kwsysProcessCleanup(kwsysProcess* cp, int error) +void kwsysProcessCleanup(kwsysProcess* cp, DWORD error) { int i; /* If this is an error case, report the error. */ @@ -1886,21 +2007,27 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error) if(cp->ErrorMessage[0] == 0) { /* Format the error message. */ - DWORD original = GetLastError(); wchar_t err_msg[KWSYSPE_PIPE_BUFFER_SIZE]; DWORD length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, 0, original, + FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_msg, KWSYSPE_PIPE_BUFFER_SIZE, 0); - WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage, - KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL); if(length < 1) { /* FormatMessage failed. Use a default message. */ _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, "Process execution failed with error 0x%X. " "FormatMessage failed with error 0x%X", - original, GetLastError()); + error, GetLastError()); + } + if(!WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage, + KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL)) + { + /* WideCharToMultiByte failed. Use a default message. */ + _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, + "Process execution failed with error 0x%X. " + "WideCharToMultiByte failed with error 0x%X", + error, GetLastError()); } } @@ -1923,6 +2050,8 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error) } for(i=0; i < cp->NumberOfCommands; ++i) { + /* Remove from global list of processes and close handles. */ + kwsysProcessesRemove(cp->ProcessInformation[i].hProcess); kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); } @@ -2659,3 +2788,230 @@ static void kwsysProcessDisablePipeThreads(kwsysProcess* cp) ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); } } + +/*--------------------------------------------------------------------------*/ +/* Global set of executing processes for use by the Ctrl handler. + This global instance will be zero-initialized by the compiler. + + Note that the console Ctrl handler runs on a background thread and so + everything it does must be thread safe. Here, we track the hProcess + HANDLEs directly instead of kwsysProcess instances, so that we don't have + to make kwsysProcess thread safe. */ +typedef struct kwsysProcessInstance_s +{ + HANDLE hProcess; + DWORD dwProcessId; + int NewProcessGroup; /* Whether the process was created in a new group. */ +} kwsysProcessInstance; + +typedef struct kwsysProcessInstances_s +{ + /* Whether we have initialized key fields below, like critical sections. */ + int Initialized; + + /* Ctrl handler runs on a different thread, so we must sync access. */ + CRITICAL_SECTION Lock; + + int Exiting; + size_t Count; + size_t Size; + kwsysProcessInstance* Processes; +} kwsysProcessInstances; +static kwsysProcessInstances kwsysProcesses; + +/*--------------------------------------------------------------------------*/ +/* Initialize critial section and set up console Ctrl handler. You MUST call + this before using any other kwsysProcesses* functions below. */ +static int kwsysProcessesInitialize(void) +{ + /* Initialize everything if not done already. */ + if(!kwsysProcesses.Initialized) + { + InitializeCriticalSection(&kwsysProcesses.Lock); + + /* Set up console ctrl handler. */ + if(!SetConsoleCtrlHandler(kwsysCtrlHandler, TRUE)) + { + return 0; + } + + kwsysProcesses.Initialized = 1; + } + return 1; +} + +/*--------------------------------------------------------------------------*/ +/* The Ctrl handler waits on the global list of processes. To prevent an + orphaned process, do not create a new process if the Ctrl handler is + already running. Do so by using this function to check if it is ok to + create a process. */ +static int kwsysTryEnterCreateProcessSection(void) +{ + /* Enter main critical section; this means creating a process and the Ctrl + handler are mutually exclusive. */ + EnterCriticalSection(&kwsysProcesses.Lock); + /* Indicate to the caller if they can create a process. */ + if(kwsysProcesses.Exiting) + { + LeaveCriticalSection(&kwsysProcesses.Lock); + return 0; + } + else + { + return 1; + } +} + +/*--------------------------------------------------------------------------*/ +/* Matching function on successful kwsysTryEnterCreateProcessSection return. + Make sure you called kwsysProcessesAdd if applicable before calling this.*/ +static void kwsysLeaveCreateProcessSection(void) +{ + LeaveCriticalSection(&kwsysProcesses.Lock); +} + +/*--------------------------------------------------------------------------*/ +/* Add new process to global process list. The Ctrl handler will wait for + the process to exit before it returns. Do not close the process handle + until after calling kwsysProcessesRemove. The newProcessGroup parameter + must be set if the process was created with CREATE_NEW_PROCESS_GROUP. */ +static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid, + int newProcessGroup) +{ + if(!kwsysProcessesInitialize() || !hProcess || + hProcess == INVALID_HANDLE_VALUE) + { + return 0; + } + + /* Enter the critical section. */ + EnterCriticalSection(&kwsysProcesses.Lock); + + /* Make sure there is enough space for the new process handle. */ + if(kwsysProcesses.Count == kwsysProcesses.Size) + { + size_t newSize; + kwsysProcessInstance *newArray; + /* Start with enough space for a small number of process handles + and double the size each time more is needed. */ + newSize = kwsysProcesses.Size? kwsysProcesses.Size*2 : 4; + + /* Try allocating the new block of memory. */ + if(newArray = (kwsysProcessInstance*)malloc( + newSize*sizeof(kwsysProcessInstance))) + { + /* Copy the old process handles to the new memory. */ + if(kwsysProcesses.Count > 0) + { + memcpy(newArray, kwsysProcesses.Processes, + kwsysProcesses.Count * sizeof(kwsysProcessInstance)); + } + } + else + { + /* Failed to allocate memory for the new process handle set. */ + LeaveCriticalSection(&kwsysProcesses.Lock); + return 0; + } + + /* Free original array. */ + free(kwsysProcesses.Processes); + + /* Update original structure with new allocation. */ + kwsysProcesses.Size = newSize; + kwsysProcesses.Processes = newArray; + } + + /* Append the new process information to the set. */ + kwsysProcesses.Processes[kwsysProcesses.Count].hProcess = hProcess; + kwsysProcesses.Processes[kwsysProcesses.Count].dwProcessId = dwProcessid; + kwsysProcesses.Processes[kwsysProcesses.Count++].NewProcessGroup = + newProcessGroup; + + /* Leave critical section and return success. */ + LeaveCriticalSection(&kwsysProcesses.Lock); + + return 1; +} + +/*--------------------------------------------------------------------------*/ +/* Removes process to global process list. */ +static void kwsysProcessesRemove(HANDLE hProcess) +{ + size_t i; + + if (!hProcess || hProcess == INVALID_HANDLE_VALUE) + { + return; + } + + EnterCriticalSection(&kwsysProcesses.Lock); + + /* Find the given process in the set. */ + for(i=0; i < kwsysProcesses.Count; ++i) + { + if(kwsysProcesses.Processes[i].hProcess == hProcess) + { + break; + } + } + if(i < kwsysProcesses.Count) + { + /* Found it! Remove the process from the set. */ + --kwsysProcesses.Count; + for(; i < kwsysProcesses.Count; ++i) + { + kwsysProcesses.Processes[i] = kwsysProcesses.Processes[i+1]; + } + + /* If this was the last process, free the array. */ + if(kwsysProcesses.Count == 0) + { + kwsysProcesses.Size = 0; + free(kwsysProcesses.Processes); + kwsysProcesses.Processes = 0; + } + } + + LeaveCriticalSection(&kwsysProcesses.Lock); +} + +/*--------------------------------------------------------------------------*/ +static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType) +{ + size_t i; + (void)dwCtrlType; + /* Enter critical section. */ + EnterCriticalSection(&kwsysProcesses.Lock); + + /* Set flag indicating that we are exiting. */ + kwsysProcesses.Exiting = 1; + + /* If some of our processes were created in a new process group, we must + manually interrupt them. They won't otherwise receive a Ctrl+C/Break. */ + for(i=0; i < kwsysProcesses.Count; ++i) + { + if(kwsysProcesses.Processes[i].NewProcessGroup) + { + DWORD groupId = kwsysProcesses.Processes[i].dwProcessId; + if(groupId) + { + GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, groupId); + } + } + } + + /* Wait for each child process to exit. This is the key step that prevents + us from leaving several orphaned children processes running in the + background when the user presses Ctrl+C. */ + for(i=0; i < kwsysProcesses.Count; ++i) + { + WaitForSingleObject(kwsysProcesses.Processes[i].hProcess, INFINITE); + } + + /* Leave critical section. */ + LeaveCriticalSection(&kwsysProcesses.Lock); + + /* Continue on to default Ctrl handler (which calls ExitProcess). */ + return FALSE; +} diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 3452259..0714344 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -3198,8 +3198,16 @@ bool SystemTools::FileIsDirectory(const kwsys_stl::string& inName) bool SystemTools::FileIsSymlink(const kwsys_stl::string& name) { #if defined( _WIN32 ) - (void)name; - return false; + DWORD attr = GetFileAttributesW( + SystemTools::ConvertToWindowsExtendedPath(name).c_str()); + if (attr != INVALID_FILE_ATTRIBUTES) + { + return (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + } + else + { + return false; + } #else struct stat fs; if(lstat(name.c_str(), &fs) == 0) @@ -4230,6 +4238,11 @@ SystemTools::DetectFileType(const char *filename, return SystemTools::FileTypeUnknown; } + if (SystemTools::FileIsDirectory(filename)) + { + return SystemTools::FileTypeUnknown; + } + FILE *fp = Fopen(filename, "rb"); if (!fp) { @@ -4243,6 +4256,7 @@ SystemTools::DetectFileType(const char *filename, fclose(fp); if (read_length == 0) { + delete [] buffer; return SystemTools::FileTypeUnknown; } diff --git a/Source/kwsys/testProcess.c b/Source/kwsys/testProcess.c index 47c3fb0..d0e20c1 100644 --- a/Source/kwsys/testProcess.c +++ b/Source/kwsys/testProcess.c @@ -29,26 +29,48 @@ # include <windows.h> #else # include <unistd.h> +# include <signal.h> #endif #if defined(__BORLANDC__) # pragma warn -8060 /* possibly incorrect assignment */ #endif +/* Platform-specific sleep functions. */ + #if defined(__BEOS__) && !defined(__ZETA__) /* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */ # include <be/kernel/OS.h> -static inline void testProcess_usleep(unsigned int msec) +static inline void testProcess_usleep(unsigned int usec) +{ + snooze(usec); +} +#elif defined(_WIN32) +/* Windows can only sleep in millisecond intervals. */ +static void testProcess_usleep(unsigned int usec) { - snooze(msec); + Sleep(usec / 1000); } #else # define testProcess_usleep usleep #endif +#if defined(_WIN32) +static void testProcess_sleep(unsigned int sec) +{ + Sleep(sec*1000); +} +#else +static void testProcess_sleep(unsigned int sec) +{ + sleep(sec); +} +#endif + int runChild(const char* cmd[], int state, int exception, int value, int share, int output, int delay, double timeout, int poll, - int repeat, int disown); + int repeat, int disown, int createNewGroup, + unsigned int interruptDelay); static int test1(int argc, const char* argv[]) { @@ -73,11 +95,7 @@ static int test3(int argc, const char* argv[]) fprintf(stderr, "Output before sleep on stderr from timeout test.\n"); fflush(stdout); fflush(stderr); -#if defined(_WIN32) - Sleep(15000); -#else - sleep(15); -#endif + testProcess_sleep(15); fprintf(stdout, "Output after sleep on stdout from timeout test.\n"); fprintf(stderr, "Output after sleep on stderr from timeout test.\n"); return 0; @@ -102,7 +120,7 @@ static int test4(int argc, const char* argv[]) #endif (void)argc; (void)argv; fprintf(stdout, "Output before crash on stdout from crash test.\n"); - fprintf(stderr, "Output before crash on stderr from crash test.\n"); + fprintf(stderr, "Output before crash on stderr from crash test.\n"); fflush(stdout); fflush(stderr); assert(invalidAddress); /* Quiet Clang scan-build. */ @@ -127,7 +145,7 @@ static int test5(int argc, const char* argv[]) fflush(stdout); fflush(stderr); r = runChild(cmd, kwsysProcess_State_Exception, - kwsysProcess_Exception_Fault, 1, 1, 1, 0, 15, 0, 1, 0); + kwsysProcess_Exception_Fault, 1, 1, 1, 0, 15, 0, 1, 0, 0, 0); fprintf(stdout, "Output on stdout after recursive test.\n"); fprintf(stderr, "Output on stderr after recursive test.\n"); fflush(stdout); @@ -168,11 +186,7 @@ static int test7(int argc, const char* argv[]) fflush(stdout); fflush(stderr); /* Sleep for 1 second. */ -#if defined(_WIN32) - Sleep(1000); -#else - sleep(1); -#endif + testProcess_sleep(1); fprintf(stdout, "Output on stdout after sleep.\n"); fprintf(stderr, "Output on stderr after sleep.\n"); fflush(stdout); @@ -196,7 +210,7 @@ static int test8(int argc, const char* argv[]) fflush(stdout); fflush(stderr); r = runChild(cmd, kwsysProcess_State_Disowned, kwsysProcess_Exception_None, - 1, 1, 1, 0, 10, 0, 1, 1); + 1, 1, 1, 0, 10, 0, 1, 1, 0, 0); fprintf(stdout, "Output on stdout after grandchild test.\n"); fprintf(stderr, "Output on stderr after grandchild test.\n"); fflush(stdout); @@ -217,18 +231,137 @@ static int test8_grandchild(int argc, const char* argv[]) implemented. */ fclose(stdout); fclose(stderr); + testProcess_sleep(15); + return 0; +} + +static int test9(int argc, const char* argv[]) +{ + /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this + process. Here, we start a child process that sleeps for a long time + while ignoring signals. The test is successful if this process waits + for the child to return before exiting from the Ctrl+C handler. + + WARNING: This test will falsely pass if the share parameter of runChild + was set to 0 when invoking the test9 process. */ + int r; + const char* cmd[4]; + (void)argc; + cmd[0] = argv[0]; + cmd[1] = "run"; + cmd[2] = "109"; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before grandchild test.\n"); + fprintf(stderr, "Output on stderr before grandchild test.\n"); + fflush(stdout); + fflush(stderr); + r = runChild(cmd, kwsysProcess_State_Exited, + kwsysProcess_Exception_None, + 0, 1, 1, 0, 30, 0, 1, 0, 0, 0); + /* This sleep will avoid a race condition between this function exiting + normally and our Ctrl+C handler exiting abnormally after the process + exits. */ + testProcess_sleep(1); + fprintf(stdout, "Output on stdout after grandchild test.\n"); + fprintf(stderr, "Output on stderr after grandchild test.\n"); + fflush(stdout); + fflush(stderr); + return r; +} + #if defined(_WIN32) - Sleep(15000); +static BOOL WINAPI test9_grandchild_handler(DWORD dwCtrlType) +{ + /* Ignore all Ctrl+C/Break signals. We must use an actual handler function + instead of using SetConsoleCtrlHandler(NULL, TRUE) so that we can also + ignore Ctrl+Break in addition to Ctrl+C. */ + (void)dwCtrlType; + return TRUE; +} +#endif + +static int test9_grandchild(int argc, const char* argv[]) +{ + /* The grandchild just sleeps for a few seconds while ignoring signals. */ + (void)argc; (void)argv; +#if defined(_WIN32) + if(!SetConsoleCtrlHandler(test9_grandchild_handler, TRUE)) + { + return 1; + } #else - sleep(15); + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + if(sigaction(SIGINT, &sa, 0) < 0) + { + return 1; + } #endif + fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); + fflush(stdout); + fflush(stderr); + /* Sleep for 9 seconds. */ + testProcess_sleep(9); + fprintf(stdout, "Output on stdout from grandchild after sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild after sleep.\n"); + fflush(stdout); + fflush(stderr); + return 0; +} + +static int test10(int argc, const char* argv[]) +{ + /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this + process. Here, we start a child process that sleeps for a long time and + processes signals normally. However, this grandchild is created in a new + process group - ensuring that Ctrl+C we receive is sent to our process + groups. We make sure it exits anyway. */ + int r; + const char* cmd[4]; + (void)argc; + cmd[0] = argv[0]; + cmd[1] = "run"; + cmd[2] = "110"; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before grandchild test.\n"); + fprintf(stderr, "Output on stderr before grandchild test.\n"); + fflush(stdout); + fflush(stderr); + r = runChild(cmd, kwsysProcess_State_Exception, + kwsysProcess_Exception_Interrupt, + 0, 1, 1, 0, 30, 0, 1, 0, 1, 0); + fprintf(stdout, "Output on stdout after grandchild test.\n"); + fprintf(stderr, "Output on stderr after grandchild test.\n"); + fflush(stdout); + fflush(stderr); + return r; +} + +static int test10_grandchild(int argc, const char* argv[]) +{ + /* The grandchild just sleeps for a few seconds and handles signals. */ + (void)argc; (void)argv; + fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); + fflush(stdout); + fflush(stderr); + /* Sleep for 6 seconds. */ + testProcess_sleep(6); + fprintf(stdout, "Output on stdout from grandchild after sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild after sleep.\n"); + fflush(stdout); + fflush(stderr); return 0; } static int runChild2(kwsysProcess* kp, const char* cmd[], int state, int exception, int value, int share, int output, int delay, double timeout, - int poll, int disown) + int poll, int disown, int createNewGroup, + unsigned int interruptDelay) { int result = 0; char* data = 0; @@ -249,6 +382,10 @@ static int runChild2(kwsysProcess* kp, { kwsysProcess_SetOption(kp, kwsysProcess_Option_Detach, 1); } + if(createNewGroup) + { + kwsysProcess_SetOption(kp, kwsysProcess_Option_CreateProcessGroup, 1); + } kwsysProcess_Execute(kp); if(poll) @@ -256,6 +393,12 @@ static int runChild2(kwsysProcess* kp, pUserTimeout = &userTimeout; } + if(interruptDelay) + { + testProcess_sleep(interruptDelay); + kwsysProcess_Interrupt(kp); + } + if(!share && !disown) { int p; @@ -286,17 +429,13 @@ static int runChild2(kwsysProcess* kp, if(poll) { /* Delay to avoid busy loop during polling. */ -#if defined(_WIN32) - Sleep(100); -#else testProcess_usleep(100000); -#endif } if(delay) { /* Purposely sleeping only on Win32 to let pipe fill up. */ #if defined(_WIN32) - Sleep(100); + testProcess_usleep(100000); #endif } } @@ -337,7 +476,7 @@ static int runChild2(kwsysProcess* kp, printf("Error in administrating child process: [%s]\n", kwsysProcess_GetErrorString(kp)); break; }; - + if(result) { if(exception != kwsysProcess_GetExitException(kp)) @@ -353,7 +492,7 @@ static int runChild2(kwsysProcess* kp, value, kwsysProcess_GetExitValue(kp)); } } - + if(kwsysProcess_GetState(kp) != state) { fprintf(stderr, "Mismatch in state. " @@ -374,9 +513,37 @@ static int runChild2(kwsysProcess* kp, return result; } +/** + * Runs a child process and blocks until it returns. Arguments as follows: + * + * cmd = Command line to run. + * state = Expected return value of kwsysProcess_GetState after exit. + * exception = Expected return value of kwsysProcess_GetExitException. + * value = Expected return value of kwsysProcess_GetExitValue. + * share = Whether to share stdout/stderr child pipes with our pipes + * by way of kwsysProcess_SetPipeShared. If false, new pipes + * are created. + * output = If !share && !disown, whether to write the child's stdout + * and stderr output to our stdout. + * delay = If !share && !disown, adds an additional short delay to + * the pipe loop to allow the pipes to fill up; Windows only. + * timeout = Non-zero to sets a timeout in seconds via + * kwsysProcess_SetTimeout. + * poll = If !share && !disown, we count the number of 0.1 second + * intervals where the child pipes had no new data. We fail + * if not in the bounds of MINPOLL/MAXPOLL. + * repeat = Number of times to run the process. + * disown = If set, the process is disowned. + * createNewGroup = If set, the process is created in a new process group. + * interruptDelay = If non-zero, number of seconds to delay before + * interrupting the process. Note that this delay will occur + * BEFORE any reading/polling of pipes occurs and before any + * detachment occurs. + */ int runChild(const char* cmd[], int state, int exception, int value, int share, int output, int delay, double timeout, - int poll, int repeat, int disown) + int poll, int repeat, int disown, int createNewGroup, + unsigned int interruptDelay) { int result = 1; kwsysProcess* kp = kwsysProcess_New(); @@ -388,7 +555,8 @@ int runChild(const char* cmd[], int state, int exception, int value, while(repeat-- > 0) { result = runChild2(kp, cmd, state, exception, value, share, - output, delay, timeout, poll, disown); + output, delay, timeout, poll, disown, createNewGroup, + interruptDelay); } kwsysProcess_Delete(kp); return result; @@ -435,7 +603,7 @@ int main(int argc, const char* argv[]) n = atoi(argv[2]); } /* Check arguments. */ - if(((n >= 1 && n <= 8) || n == 108) && argc == 3) + if(((n >= 1 && n <= 10) || n == 108 || n == 109 || n == 110) && argc == 3) { /* This is the child process for a requested test number. */ switch (n) @@ -448,15 +616,19 @@ int main(int argc, const char* argv[]) case 6: test6(argc, argv); return 0; case 7: return test7(argc, argv); case 8: return test8(argc, argv); + case 9: return test9(argc, argv); + case 10: return test10(argc, argv); case 108: return test8_grandchild(argc, argv); + case 109: return test9_grandchild(argc, argv); + case 110: return test10_grandchild(argc, argv); } fprintf(stderr, "Invalid test number %d.\n", n); return 1; } - else if(n >= 1 && n <= 8) + else if(n >= 1 && n <= 10) { /* This is the parent process for a requested test number. */ - int states[8] = + int states[10] = { kwsysProcess_State_Exited, kwsysProcess_State_Exited, @@ -465,9 +637,11 @@ int main(int argc, const char* argv[]) kwsysProcess_State_Exited, kwsysProcess_State_Expired, kwsysProcess_State_Exited, - kwsysProcess_State_Exited + kwsysProcess_State_Exited, + kwsysProcess_State_Expired, /* Ctrl+C handler test */ + kwsysProcess_State_Exception /* Process group test */ }; - int exceptions[8] = + int exceptions[10] = { kwsysProcess_Exception_None, kwsysProcess_Exception_None, @@ -476,14 +650,19 @@ int main(int argc, const char* argv[]) kwsysProcess_Exception_None, kwsysProcess_Exception_None, kwsysProcess_Exception_None, - kwsysProcess_Exception_None + kwsysProcess_Exception_None, + kwsysProcess_Exception_None, + kwsysProcess_Exception_Interrupt }; - int values[8] = {0, 123, 1, 1, 0, 0, 0, 0}; - int outputs[8] = {1, 1, 1, 1, 1, 0, 1, 1}; - int delays[8] = {0, 0, 0, 0, 0, 1, 0, 0}; - double timeouts[8] = {10, 10, 10, 30, 30, 10, -1, 10}; - int polls[8] = {0, 0, 0, 0, 0, 0, 1, 0}; - int repeat[8] = {2, 1, 1, 1, 1, 1, 1, 1}; + int values[10] = {0, 123, 1, 1, 0, 0, 0, 0, 1, 1}; + int shares[10] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}; + int outputs[10] = {1, 1, 1, 1, 1, 0, 1, 1, 1, 1}; + int delays[10] = {0, 0, 0, 0, 0, 1, 0, 0, 0, 0}; + double timeouts[10] = {10, 10, 10, 30, 30, 10, -1, 10, 6, 4}; + int polls[10] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}; + int repeat[10] = {2, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + int createNewGroups[10] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}; + unsigned int interruptDelays[10] = {0, 0, 0, 0, 0, 0, 0, 0, 3, 2}; int r; const char* cmd[4]; #ifdef _WIN32 @@ -515,9 +694,10 @@ int main(int argc, const char* argv[]) fprintf(stderr, "Output on stderr before test %d.\n", n); fflush(stdout); fflush(stderr); - r = runChild(cmd, states[n-1], exceptions[n-1], values[n-1], 0, + r = runChild(cmd, states[n-1], exceptions[n-1], values[n-1], shares[n-1], outputs[n-1], delays[n-1], timeouts[n-1], - polls[n-1], repeat[n-1], 0); + polls[n-1], repeat[n-1], 0, createNewGroups[n-1], + interruptDelays[n-1]); fprintf(stdout, "Output on stdout after test %d.\n", n); fprintf(stderr, "Output on stderr after test %d.\n", n); fflush(stdout); @@ -536,7 +716,8 @@ int main(int argc, const char* argv[]) int exception = kwsysProcess_Exception_None; int value = 0; double timeout = 0; - int r = runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1, 0); + int r = runChild(cmd, state, exception, value, 0, 1, 0, timeout, + 0, 1, 0, 0, 0); return r; } else diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index 15d8eab..7b5c025 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -98,6 +98,10 @@ static bool CheckEscapeChars(kwsys_stl::string input, static bool CheckFileOperations() { bool res = true; + const kwsys_stl::string testNonExistingFile(TEST_SYSTEMTOOLS_SOURCE_DIR + "/testSystemToolsNonExistingFile"); + const kwsys_stl::string testDotFile(TEST_SYSTEMTOOLS_SOURCE_DIR + "/."); const kwsys_stl::string testBinFile(TEST_SYSTEMTOOLS_SOURCE_DIR "/testSystemTools.bin"); const kwsys_stl::string testTxtFile(TEST_SYSTEMTOOLS_SOURCE_DIR @@ -106,6 +110,24 @@ static bool CheckFileOperations() "/testSystemToolsNewDir"); const kwsys_stl::string testNewFile(testNewDir + "/testNewFile.txt"); + if (kwsys::SystemTools::DetectFileType(testNonExistingFile.c_str()) != + kwsys::SystemTools::FileTypeUnknown) + { + kwsys_ios::cerr + << "Problem with DetectFileType - failed to detect type of: " + << testNonExistingFile << kwsys_ios::endl; + res = false; + } + + if (kwsys::SystemTools::DetectFileType(testDotFile.c_str()) != + kwsys::SystemTools::FileTypeUnknown) + { + kwsys_ios::cerr + << "Problem with DetectFileType - failed to detect type of: " + << testDotFile << kwsys_ios::endl; + res = false; + } + if (kwsys::SystemTools::DetectFileType(testBinFile.c_str()) != kwsys::SystemTools::FileTypeBinary) { |