/*========================================================================= Program: CMake - Cross-Platform Makefile Generator Module: $RCSfile$ Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "cmGlobalVisualStudioGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmTarget.h" //---------------------------------------------------------------------------- cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator() { } //---------------------------------------------------------------------------- cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator() { } //---------------------------------------------------------------------------- void cmGlobalVisualStudioGenerator::Generate() { // Add a special target that depends on ALL projects for easy build // of one configuration only. const char* no_working_dir = 0; std::vector no_depends; cmCustomCommandLines no_commands; std::map >::iterator it; for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it) { std::vector& gen = it->second; // add the ALL_BUILD to the first local generator of each project if(gen.size()) { // Use no actual command lines so that the target itself is not // considered always out of date. gen[0]->GetMakefile()-> AddUtilityCommand("ALL_BUILD", true, no_working_dir, no_depends, no_commands, false, "Build all projects"); } } // Fix utility dependencies to avoid linking to libraries. this->FixUtilityDepends(); // Run all the local generators. this->cmGlobalGenerator::Generate(); } //---------------------------------------------------------------------------- void cmGlobalVisualStudioGenerator::FixUtilityDepends() { // For VS versions before 8: // // When a target that links contains a project-level dependency on a // library target that library is automatically linked. In order to // allow utility-style project-level dependencies that do not // actually link we need to automatically insert an intermediate // custom target. // // Here we edit the utility dependencies of a target to add the // intermediate custom target when necessary. for(unsigned i = 0; i < this->LocalGenerators.size(); ++i) { cmTargets* targets = &(this->LocalGenerators[i]->GetMakefile()->GetTargets()); for(cmTargets::iterator tarIt = targets->begin(); tarIt != targets->end(); ++tarIt) { this->FixUtilityDependsForTarget(tarIt->second); } } } //---------------------------------------------------------------------------- void cmGlobalVisualStudioGenerator::FixUtilityDependsForTarget(cmTarget& target) { // Only targets that link need to be fixed. if(target.GetType() != cmTarget::STATIC_LIBRARY && target.GetType() != cmTarget::SHARED_LIBRARY && target.GetType() != cmTarget::MODULE_LIBRARY && target.GetType() != cmTarget::EXECUTABLE) { return; } // Look at each utility dependency. for(std::set::const_iterator ui = target.GetUtilities().begin(); ui != target.GetUtilities().end(); ++ui) { if(cmTarget* depTarget = this->FindTarget(0, ui->c_str(), false)) { if(depTarget->GetType() == cmTarget::STATIC_LIBRARY || depTarget->GetType() == cmTarget::SHARED_LIBRARY || depTarget->GetType() == cmTarget::MODULE_LIBRARY) { // This utility dependency will cause an attempt to link. If // the depender does not already link the dependee we need an // intermediate target. if(!this->CheckTargetLinks(target, ui->c_str())) { this->CreateUtilityDependTarget(*depTarget); } } } } } //---------------------------------------------------------------------------- void cmGlobalVisualStudioGenerator::CreateUtilityDependTarget(cmTarget& target) { // This target is a library on which a utility dependency exists. // We need to create an intermediate custom target to hook up the // dependency without causing a link. const char* altName = target.GetProperty("ALTERNATIVE_DEPENDENCY_NAME"); if(!altName) { // Create the intermediate utility target. std::string altNameStr = target.GetName(); altNameStr += "_UTILITY"; const std::vector no_depends; cmCustomCommandLines no_commands; const char* no_working_dir = 0; const char* no_comment = 0; target.GetMakefile()->AddUtilityCommand(altNameStr.c_str(), true, no_working_dir, no_depends, no_commands, false, no_comment); target.SetProperty("ALTERNATIVE_DEPENDENCY_NAME", altNameStr.c_str()); // Most targets have a GUID created in ConfigureFinalPass. Since // that has already been called, create one for this target now. this->CreateGUID(altNameStr.c_str()); // The intermediate target should depend on the original target. if(cmTarget* alt = this->FindTarget(0, altNameStr.c_str(), false)) { alt->AddUtility(target.GetName()); } } } //---------------------------------------------------------------------------- bool cmGlobalVisualStudioGenerator::CheckTargetLinks(cmTarget& target, const char* name) { // Return whether the given target links to a target with the given name. if(target.GetType() == cmTarget::STATIC_LIBRARY) { // Static libraries never link to anything. return false; } cmTarget::LinkLibraryVectorType const& libs = target.GetLinkLibraries(); for(cmTarget::LinkLibraryVectorType::const_iterator i = libs.begin(); i != libs.end(); ++i) { if(i->first == name) { return true; } } return false; } //---------------------------------------------------------------------------- const char* cmGlobalVisualStudioGenerator::GetUtilityForTarget(cmTarget& target, const char* name) { // Handle the external MS project special case. if(strncmp(name, "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) { // Note from Ken: // kind of weird removing the first 27 letters. my // recommendatsions: use cmCustomCommand::GetCommand() to get the // project name or get rid of the target name starting with // "INCLUDE_EXTERNAL_MSPROJECT_" and use another indicator/flag // somewhere. These external project names shouldn't conflict // with cmake target names anyways. return name+27; } // Possibly depend on an intermediate utility target to avoid // linking. if(target.GetType() == cmTarget::STATIC_LIBRARY || target.GetType() == cmTarget::SHARED_LIBRARY || target.GetType() == cmTarget::MODULE_LIBRARY || target.GetType() == cmTarget::EXECUTABLE) { // The depender is a target that links. Lookup the dependee to // see if it provides an alternative dependency name. if(cmTarget* depTarget = this->FindTarget(0, name, false)) { // Check for an alternative name created by FixUtilityDepends. if(const char* altName = depTarget->GetProperty("ALTERNATIVE_DEPENDENCY_NAME")) { // The alternative name is needed only if the depender does // not really link to the dependee. if(!this->CheckTargetLinks(target, name)) { return altName; } } } } // No special case. Just use the original dependency name. return name; }