From 3cf3bb664aa9b6c447c90c33cd6b5c1dff8c1a10 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 21 Dec 2007 15:04:06 -0500 Subject: [PATCH] ENH: Make static library targets depend on targets to which they "link" for the purpose of build ordering. This makes the build order consistent for static and shared library builds. It is also useful when custom command inputs of one library are generated as custom commands outputs of another. It may be useful in the future for Fortran module dependencies. Implemented for Makefiles, Xcode, and VS 8 and above. Added sample code to do it for VS 7.1 and below, but left it disabled with comments explaining why. Likely it will never be needed on VS 7.1 or below anyway. --- Source/cmGlobalUnixMakefileGenerator3.cxx | 43 ++++++---------------- Source/cmGlobalVisualStudio71Generator.cxx | 10 ++++- Source/cmGlobalVisualStudio8Generator.h | 3 +- Source/cmGlobalVisualStudioGenerator.cxx | 33 +++++++++++++++++ Source/cmGlobalVisualStudioGenerator.h | 7 +++- Source/cmGlobalXCodeGenerator.cxx | 43 +++++++++++----------- 6 files changed, 80 insertions(+), 59 deletions(-) diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 96d1b339f..8fc5fc2fd 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -903,24 +903,21 @@ cmGlobalUnixMakefileGenerator3 // A target should not depend on itself. emitted.insert(target.GetName()); - - // Loop over all library dependencies but not for static libs - if (target.GetType() != cmTarget::STATIC_LIBRARY) + + // Loop over all library dependencies. + const cmTarget::LinkLibraryVectorType& tlibs = target.GetLinkLibraries(); + for(cmTarget::LinkLibraryVectorType::const_iterator lib = tlibs.begin(); + lib != tlibs.end(); ++lib) { - const cmTarget::LinkLibraryVectorType& tlibs = target.GetLinkLibraries(); - for(cmTarget::LinkLibraryVectorType::const_iterator lib = tlibs.begin(); - lib != tlibs.end(); ++lib) + // Don't emit the same library twice for this target. + if(emitted.insert(lib->first).second) { - // Don't emit the same library twice for this target. - if(emitted.insert(lib->first).second) - { - // Add this dependency. - this->AppendAnyGlobalDepend(depends, lib->first.c_str(), - emitted, target); - } + // Add this dependency. + this->AppendAnyGlobalDepend(depends, lib->first.c_str(), + emitted, target); } } - + // Loop over all utility dependencies. const std::set& tutils = target.GetUtilities(); for(std::set::const_iterator util = tutils.begin(); @@ -967,24 +964,6 @@ cmGlobalUnixMakefileGenerator3 std::string tgtName = lg3->GetRelativeTargetDirectory(*result); tgtName += "/all"; depends.push_back(tgtName); - if(result->GetType() == cmTarget::STATIC_LIBRARY) - { - // Since the static library itself does not list dependencies we - // need to chain its dependencies here. - const cmTarget::LinkLibraryVectorType& tlibs - = result->GetLinkLibraries(); - for(cmTarget::LinkLibraryVectorType::const_iterator lib = tlibs.begin(); - lib != tlibs.end(); ++lib) - { - // Don't emit the same library twice for this target. - if(emitted.insert(lib->first).second) - { - // Add this dependency. - this->AppendAnyGlobalDepend(depends, lib->first.c_str(), - emitted, *result); - } - } - } return; } } diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index 345cfdf55..adb3f5752 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -317,8 +317,14 @@ cmGlobalVisualStudio71Generator const char* dspname, const char*, cmTarget& target) { - // insert Begin Project Dependency Project_Dep_Name project stuff here - if (target.GetType() != cmTarget::STATIC_LIBRARY) + // Create inter-target dependencies in the solution file. For VS + // 7.1 and below we cannot let static libraries depend directly on + // targets to which they "link" because the librarian tool will copy + // the targets into the static library. See + // cmGlobalVisualStudioGenerator::FixUtilityDependsForTarget for a + // work-around. VS 8 and above do not have this problem. + if (!this->VSLinksDependencies() || + target.GetType() != cmTarget::STATIC_LIBRARY) { cmTarget::LinkLibraryVectorType::const_iterator j, jend; j = target.GetLinkLibraries().begin(); diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h index b7250a13e..534258a40 100644 --- a/Source/cmGlobalVisualStudio8Generator.h +++ b/Source/cmGlobalVisualStudio8Generator.h @@ -59,8 +59,7 @@ public: protected: - // Utility target fix is not needed for VS8. - virtual void FixUtilityDepends() {} + virtual bool VSLinksDependencies() const { return false; } static cmVS7FlagTable const* GetExtraFlagTableVS8(); virtual void AddPlatformDefinitions(cmMakefile* mf); diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index fdc62f435..2319b047b 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -197,6 +197,12 @@ std::string cmGlobalVisualStudioGenerator::GetUserMacrosDirectory() //---------------------------------------------------------------------------- void cmGlobalVisualStudioGenerator::FixUtilityDepends() { + // Skip for VS versions 8 and above. + if(!this->VSLinksDependencies()) + { + return; + } + // For VS versions before 8: // // When a target that links contains a project-level dependency on a @@ -232,6 +238,33 @@ cmGlobalVisualStudioGenerator::FixUtilityDependsForTarget(cmTarget& target) return; } +#if 0 + // This feature makes a mess in SLN files for VS 7.1 and below. It + // creates an extra target for every target that is "linked" by a + // static library. Without this feature static libraries do not + // wait until their "link" dependencies are built to build. This is + // not a problem 99.9% of the time, and projects that do have the + // problem can enable this work-around by using add_dependencies. + + // Static libraries cannot depend directly on the targets to which + // they link because VS will copy those targets into the library + // (for VS < 8). To work around the problem we copy the + // dependencies to be utility dependencies so that the work-around + // below is used. + if(target.GetType() == cmTarget::STATIC_LIBRARY) + { + cmTarget::LinkLibraryVectorType const& libs = target.GetLinkLibraries(); + for(cmTarget::LinkLibraryVectorType::const_iterator i = libs.begin(); + i != libs.end(); ++i) + { + if(cmTarget* depTarget = this->FindTarget(0, i->first.c_str(), false)) + { + target.AddUtility(depTarget->GetName()); + } + } + } +#endif + // Look at each utility dependency. for(std::set::const_iterator ui = target.GetUtilities().begin(); diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 4237b9767..2fbb47847 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -60,9 +60,14 @@ public: protected: virtual void CreateGUID(const char*) {} - virtual void FixUtilityDepends(); + void FixUtilityDepends(); const char* GetUtilityForTarget(cmTarget& target, const char*); + // Does this VS version link targets to each other if there are + // dependencies in the SLN file? This was done for VS versions + // below 8. + virtual bool VSLinksDependencies() const { return true; } + private: void FixUtilityDependsForTarget(cmTarget& target); void CreateUtilityDependTarget(cmTarget& target); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index f08c36eb4..d02fe2674 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2006,34 +2006,33 @@ void cmGlobalXCodeGenerator } // Add dependencies on other CMake targets. - if(cmtarget->GetType() != cmTarget::STATIC_LIBRARY) + { + // Keep track of dependencies already listed. + std::set emitted; + + // A target should not depend on itself. + emitted.insert(cmtarget->GetName()); + + // Loop over all library dependencies. + const cmTarget::LinkLibraryVectorType& tlibs = + cmtarget->GetLinkLibraries(); + for(cmTarget::LinkLibraryVectorType::const_iterator lib = tlibs.begin(); + lib != tlibs.end(); ++lib) { - // Keep track of dependencies already listed. - std::set emitted; - - // A target should not depend on itself. - emitted.insert(cmtarget->GetName()); - - // Loop over all library dependencies. - const cmTarget::LinkLibraryVectorType& tlibs = - cmtarget->GetLinkLibraries(); - for(cmTarget::LinkLibraryVectorType::const_iterator lib = tlibs.begin(); - lib != tlibs.end(); ++lib) + // Don't emit the same library twice for this target. + if(emitted.insert(lib->first).second) { - // Don't emit the same library twice for this target. - if(emitted.insert(lib->first).second) + // Add this dependency. + cmTarget* t = this->FindTarget(this->CurrentProject.c_str(), + lib->first.c_str(), false); + cmXCodeObject* dptarget = this->FindXCodeTarget(t); + if(dptarget) { - // Add this dependency. - cmTarget* t = this->FindTarget(this->CurrentProject.c_str(), - lib->first.c_str(), false); - cmXCodeObject* dptarget = this->FindXCodeTarget(t); - if(dptarget) - { - this->AddDependTarget(target, dptarget); - } + this->AddDependTarget(target, dptarget); } } } + } // write utility dependencies. for(std::set::const_iterator i