From 8a83f096371ecc4f73afe43830e94899c704d5cf Mon Sep 17 00:00:00 2001 From: Bill Hoffman Date: Wed, 30 Jan 2008 12:04:38 -0500 Subject: [PATCH] ENH: fix for bug 3218 dependant projects are written out automatically if they are in the project. Also fix bug 5829, remove hard coded CMAKE_CONFIGURATION_TYPES from vs 7 generator --- Source/cmGlobalGenerator.cxx | 62 ++- Source/cmGlobalGenerator.h | 14 +- Source/cmGlobalUnixMakefileGenerator3.cxx | 4 +- Source/cmGlobalVisualStudio71Generator.cxx | 231 +-------- Source/cmGlobalVisualStudio71Generator.h | 3 +- Source/cmGlobalVisualStudio7Generator.cxx | 523 +++++++++------------ Source/cmGlobalVisualStudio7Generator.h | 24 +- Source/cmLocalVisualStudio7Generator.cxx | 18 +- Source/cmLocalVisualStudio7Generator.h | 2 +- Tests/CMakeLists.txt | 36 +- Tests/SubProject/CMakeLists.txt | 5 + Tests/SubProject/bar.cxx | 4 + Tests/SubProject/car.cxx | 6 + 13 files changed, 400 insertions(+), 532 deletions(-) create mode 100644 Tests/SubProject/CMakeLists.txt create mode 100644 Tests/SubProject/bar.cxx create mode 100644 Tests/SubProject/car.cxx diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index dfa6e05f1..a287ad613 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1036,7 +1036,6 @@ int cmGlobalGenerator::Build( std::string makeCommand = this->GenerateBuildCommand(makeCommandCSTR, projectName, 0, target, config, false, fast); - if (!cmSystemTools::RunSingleCommand(makeCommand.c_str(), output, &retVal, 0, false, timeout)) { @@ -1291,7 +1290,7 @@ void cmGlobalGenerator::FillLocalGeneratorToTargetMap() // Add dependencies of the included target. An excluded // target may still be included if it is a dependency of a // non-excluded target. - TargetDependSet const& tgtdeps = this->GetTargetDepends(target); + TargetDependSet const& tgtdeps = this->GetTargetDirectDepends(target); for(TargetDependSet::const_iterator ti = tgtdeps.begin(); ti != tgtdeps.end(); ++ti) { @@ -1684,7 +1683,7 @@ void cmGlobalGenerator::AppendDirectoryForConfig(const char*, const char*, //---------------------------------------------------------------------------- cmGlobalGenerator::TargetDependSet const& -cmGlobalGenerator::GetTargetDepends(cmTarget const& target) +cmGlobalGenerator::GetTargetDirectDepends(cmTarget const& target) { // Clarify the role of the input target. cmTarget const* depender = ⌖ @@ -1863,6 +1862,62 @@ cmGlobalGenerator std::back_inserter(filenames)); } +void +cmGlobalGenerator +::GetTargetSets(cmGlobalGenerator::TargetDependSet& projectTargets, + cmGlobalGenerator::TargetDependSet& originalTargets, + cmLocalGenerator* root, + std::vector const& generators) +{ + // loop over all local generators + for(std::vector::const_iterator i = generators.begin(); + i != generators.end(); ++i) + { + // check to make sure generator is not excluded + if(this->IsExcluded(root, *i)) + { + continue; + } + cmMakefile* mf = (*i)->GetMakefile(); + // Get the targets in the makefile + cmTargets &tgts = mf->GetTargets(); + // loop over all the targets + for (cmTargets::iterator l = tgts.begin(); l != tgts.end(); ++l) + { + cmTarget* target = &l->second; + // put the target in the set of original targets + originalTargets.insert(target); + // Get the set of targets that depend on target + this->AddTargetDepends(target, + projectTargets); + } + } +} + +void +cmGlobalGenerator::AddTargetDepends(cmTarget* target, + cmGlobalGenerator::TargetDependSet& + projectTargets) +{ + // add the target itself + projectTargets.insert(target); + // get the direct depends of target + cmGlobalGenerator::TargetDependSet const& tset + = this->GetTargetDirectDepends(*target); + if(tset.size()) + { + // if there are targets that depend on target + // add them and their depends as well + for(cmGlobalGenerator::TargetDependSet::const_iterator i = + tset.begin(); i != tset.end(); ++i) + { + cmTarget* dtarget = const_cast(*i); + this->AddTargetDepends(dtarget, projectTargets); + } + } +} + + //---------------------------------------------------------------------------- void cmGlobalGenerator::AddToManifest(const char* config, std::string const& f) @@ -1901,3 +1956,4 @@ cmGlobalGenerator::GetDirectoryContent(std::string const& dir, bool needDisk) } return dc; } + diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 4654a410a..b40b5d83a 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -234,8 +234,9 @@ public: // Class to track a set of dependencies. class TargetDependSet: public std::set {}; - // what targets does the specified target depend on - TargetDependSet const& GetTargetDepends(cmTarget const& target); + // what targets does the specified target depend on directly + // via a target_link_libraries or add_dependencies + TargetDependSet const& GetTargetDirectDepends(cmTarget const& target); const std::map >& GetProjectMap() const {return this->ProjectMap;} @@ -245,6 +246,15 @@ public: void GetFilesReplacedDuringGenerate(std::vector& filenames); protected: + // for a project collect all its targets by following depend + // information, and also collect all the targets + void GetTargetSets(cmGlobalGenerator::TargetDependSet& projectTargets, + cmGlobalGenerator::TargetDependSet& originalTargets, + cmLocalGenerator* root, + std::vector const& generators); + void AddTargetDepends(cmTarget* target, + cmGlobalGenerator::TargetDependSet& + projectTargets); void SetLanguageEnabledFlag(const char* l, cmMakefile* mf); void SetLanguageEnabledMaps(const char* l, cmMakefile* mf); diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index ff29c4a30..746ddfa05 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -861,7 +861,7 @@ int cmGlobalUnixMakefileGenerator3 (target.GetMakefile()->GetLocalGenerator()); result = static_cast(lg->ProgressFiles[target.GetName()].size()); - TargetDependSet const& depends = this->GetTargetDepends(target); + TargetDependSet const& depends = this->GetTargetDirectDepends(target); TargetDependSet::const_iterator i; for (i = depends.begin(); i != depends.end(); ++i) @@ -898,7 +898,7 @@ cmGlobalUnixMakefileGenerator3 ::AppendGlobalTargetDepends(std::vector& depends, cmTarget& target) { - TargetDependSet const& depends_set = this->GetTargetDepends(target); + TargetDependSet const& depends_set = this->GetTargetDirectDepends(target); for(TargetDependSet::const_iterator i = depends_set.begin(); i != depends_set.end(); ++i) { diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index 48efee19a..26a095ec6 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -45,228 +45,34 @@ void cmGlobalVisualStudio71Generator::AddPlatformDefinitions(cmMakefile* mf) mf->AddDefinition("MSVC71", "1"); } -// Write a SLN file to the stream + void cmGlobalVisualStudio71Generator ::WriteSLNFile(std::ostream& fout, cmLocalGenerator* root, std::vector& generators) -{ +{ // Write out the header for a SLN file this->WriteSLNHeader(fout); - // Get the start directory with the trailing slash - std::string rootdir = root->GetMakefile()->GetStartOutputDirectory(); - rootdir += "/"; - bool doneAllBuild = false; - bool doneCheckBuild = false; - bool doneRunTests = false; - bool doneInstall = false; - bool doneEditCache = false; - bool doneRebuildCache = false; - bool donePackage = false; - - // For each cmMakefile, create a VCProj for it, and - // add it to this SLN file - unsigned int i; - for(i = 0; i < generators.size(); ++i) - { - if(this->IsExcluded(root, generators[i])) - { - continue; - } - cmMakefile* mf = generators[i]->GetMakefile(); - - // Get the source directory from the makefile - std::string dir = mf->GetStartOutputDirectory(); - // remove the home directory and / from the source directory - // this gives a relative path - cmSystemTools::ReplaceString(dir, rootdir.c_str(), ""); - - // Get the list of create dsp files names from the cmVCProjWriter, more - // than one dsp could have been created per input CMakeLists.txt file - // for each target - cmTargets &tgts = generators[i]->GetMakefile()->GetTargets(); - cmTargets::iterator l = tgts.begin(); - for(; l != tgts.end(); ++l) - { - // special handling for the current makefile - if(mf == generators[0]->GetMakefile()) - { - dir = "."; // no subdirectory for project generated - // if this is the special ALL_BUILD utility, then - // make it depend on every other non UTILITY project. - // This is done by adding the names to the GetUtilities - // vector on the makefile - if(l->first == "ALL_BUILD" && !doneAllBuild) - { - unsigned int j; - for(j = 0; j < generators.size(); ++j) - { - cmTargets &atgts = generators[j]->GetMakefile()->GetTargets(); - for(cmTargets::iterator al = atgts.begin(); - al != atgts.end(); ++al) - { - if (!al->second.GetPropertyAsBool("EXCLUDE_FROM_ALL")) - { - if (al->second.GetType() == cmTarget::UTILITY || - al->second.GetType() == cmTarget::GLOBAL_TARGET) - { - l->second.AddUtility(al->first.c_str()); - } - else - { - l->second.AddLinkLibrary(al->first,cmTarget::GENERAL); - } - } - } - } - } - } - // Write the project into the SLN file - if (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) - { - cmCustomCommand cc = l->second.GetPostBuildCommands()[0]; - const cmCustomCommandLines& cmds = cc.GetCommandLines(); - std::string project = cmds[0][0]; - std::string location = cmds[0][1]; - this->WriteExternalProject(fout, project.c_str(), - location.c_str(), cc.GetDepends()); - } - else - { - bool skip = false; - if(l->first == "ALL_BUILD" ) - { - if(doneAllBuild) - { - skip = true; - } - else - { - doneAllBuild = true; - } - } - if(l->first == CMAKE_CHECK_BUILD_SYSTEM_TARGET) - { - if(doneCheckBuild) - { - skip = true; - } - else - { - doneCheckBuild = true; - } - } - if(l->first == "INSTALL") - { - if(doneInstall) - { - skip = true; - } - else - { - doneInstall = true; - } - } - if(l->first == "RUN_TESTS") - { - if(doneRunTests) - { - skip = true; - } - else - { - doneRunTests = true; - } - } - if(l->first == "EDIT_CACHE") - { - if(doneEditCache) - { - skip = true; - } - else - { - doneEditCache = true; - } - } - if(l->first == "REBUILD_CACHE") - { - if(doneRebuildCache) - { - skip = true; - } - else - { - doneRebuildCache = true; - } - } - if(l->first == "PACKAGE") - { - if(donePackage) - { - skip = true; - } - else - { - donePackage = true; - } - } - if(!skip) - { - const char *dspname = - l->second.GetProperty("GENERATOR_FILE_NAME"); - if (dspname) - { - this->WriteProject(fout, dspname, dir.c_str(),l->second); - } - } - } - } - } + // collect the set of targets for this project by + // tracing depends of all targets. + // also collect the set of targets that are explicitly + // in this project. + cmGlobalGenerator::TargetDependSet projectTargets; + cmGlobalGenerator::TargetDependSet originalTargets; + this->GetTargetSets(projectTargets, + originalTargets, + root, generators); + this->WriteTargetsToSolution(fout, root, projectTargets, originalTargets); + // Write out the configurations information for the solution fout << "Global\n"; + // Write out the configurations for the solution this->WriteSolutionConfigurations(fout); fout << "\tGlobalSection(" << this->ProjectConfigurationSectionName << ") = postSolution\n"; - // loop over again and compute the depends - for(i = 0; i < generators.size(); ++i) - { - cmMakefile* mf = generators[i]->GetMakefile(); - cmLocalVisualStudio7Generator* pg = - static_cast(generators[i]); - // Get the list of create dsp files names from the cmVCProjWriter, more - // than one dsp could have been created per input CMakeLists.txt file - // for each target - cmTargets &tgts = pg->GetMakefile()->GetTargets(); - cmTargets::iterator l = tgts.begin(); - std::string dir = mf->GetStartDirectory(); - for(; l != tgts.end(); ++l) - { - if (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) - { - cmCustomCommand cc = l->second.GetPostBuildCommands()[0]; - const cmCustomCommandLines& cmds = cc.GetCommandLines(); - std::string project = cmds[0][0]; - this->WriteProjectConfigurations(fout, project.c_str(), - true); - } - else - { - bool partOfDefaultBuild = this->IsPartOfDefaultBuild( - root->GetMakefile()->GetProjectName(), - &l->second); - const char *dspname = - l->second.GetProperty("GENERATOR_FILE_NAME"); - if (dspname) - { - this->WriteProjectConfigurations(fout, dspname, - partOfDefaultBuild); - } - } - } - } + // Write out the configurations for all the targets in the project + this->WriteTargetConfigurations(fout, root, projectTargets); fout << "\tEndGlobalSection\n"; - // Write the footer for the SLN file this->WriteSLNFooter(fout); } @@ -338,7 +144,9 @@ cmGlobalVisualStudio71Generator if(j->first != dspname) { // is the library part of this SLN ? If so add dependency - if(this->FindTarget(this->CurrentProject.c_str(), j->first.c_str())) + // find target anywhere because all depend libraries are + // brought in as well + if(this->FindTarget(0, j->first.c_str())) { fout << "\t\t{" << this->GetGUID(j->first.c_str()) << "} = {" << this->GetGUID(j->first.c_str()) << "}\n"; @@ -379,6 +187,7 @@ void cmGlobalVisualStudio71Generator const char* location, const std::vector& depends) { + std::cout << "WriteExternalProject vs71\n"; fout << "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"" << name << "\", \"" << this->ConvertToSolutionPath(location) << "\", \"{" diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h index c8a238505..f357c8f23 100644 --- a/Source/cmGlobalVisualStudio71Generator.h +++ b/Source/cmGlobalVisualStudio71Generator.h @@ -56,7 +56,8 @@ protected: virtual void WriteProjectConfigurations(std::ostream& fout, const char* name, bool partOfDefaultBuild); - virtual void WriteExternalProject(std::ostream& fout, const char* name, + virtual void WriteExternalProject(std::ostream& fout, + const char* name, const char* path, const std::vector& depends); virtual void WriteSLNFooter(std::ostream& fout); diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index f3dcc60f3..0a084ee74 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -150,45 +150,20 @@ void cmGlobalVisualStudio7Generator::GenerateConfigurations(cmMakefile* mf) = this->CMakeInstance->GetCacheDefinition("CMAKE_CONFIGURATION_TYPES"); if ( ct ) { - std::string configTypes = ct; - - std::string::size_type start = 0; - std::string::size_type endpos = 0; - while(endpos != std::string::npos) + std::vector argsOut; + cmSystemTools::ExpandListArgument(ct, argsOut); + for(std::vector::iterator i = argsOut.begin(); + i != argsOut.end(); ++i) { - endpos = configTypes.find_first_of(" ;", start); - std::string config; - std::string::size_type len; - if(endpos != std::string::npos) + if(std::find(this->Configurations.begin(), + this->Configurations.end(), + *i) == this->Configurations.end()) { - len = endpos - start; + this->Configurations.push_back(*i); } - else - { - len = configTypes.size() - start; - } - config = configTypes.substr(start, len); - if(config == "Debug" || config == "Release" || - config == "MinSizeRel" || config == "RelWithDebInfo") - { - // only add unique configurations - if(std::find(this->Configurations.begin(), - this->Configurations.end(), - config) == this->Configurations.end()) - { - this->Configurations.push_back(config); - } - } - else - { - cmSystemTools::Error( - "Invalid configuration type in CMAKE_CONFIGURATION_TYPES: ", - config.c_str(), - " (Valid types are Debug,Release,MinSizeRel,RelWithDebInfo)"); - } - start = endpos+1; } } + // default to at least Debug and Release if(this->Configurations.size() == 0) { this->Configurations.push_back("Debug"); @@ -265,6 +240,199 @@ void cmGlobalVisualStudio7Generator::OutputSLNFile() } +void cmGlobalVisualStudio7Generator::AddAllBuildDepends( + cmLocalGenerator* root, + cmTarget* target, + cmGlobalGenerator::TargetDependSet& originalTargets) +{ + // if this is the special ALL_BUILD utility, then + // make it depend on every other non UTILITY project. + for(cmGlobalGenerator::TargetDependSet::iterator ot = + originalTargets.begin(); ot != originalTargets.end(); ++ot) + { + cmTarget* t = const_cast(*ot); + if(!this->IsExcluded(root, *t)) + { + if (t->GetType() == cmTarget::UTILITY || + t->GetType() == cmTarget::GLOBAL_TARGET) + { + target->AddUtility(t->GetName()); + } + else + { + target->AddLinkLibrary(t->GetName(),cmTarget::GENERAL); + } + } + } +} + +void cmGlobalVisualStudio7Generator::WriteTargetConfigurations( + std::ostream& fout, + cmLocalGenerator* root, + cmGlobalGenerator::TargetDependSet& projectTargets) +{ + // loop over again and write out configurations for each target + // in the solution + for(cmGlobalGenerator::TargetDependSet::iterator tt = + projectTargets.begin(); tt != projectTargets.end(); ++tt) + { + cmTarget* target = const_cast(*tt); + if (strncmp(target->GetName(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) + { + cmCustomCommand cc = target->GetPostBuildCommands()[0]; + const cmCustomCommandLines& cmds = cc.GetCommandLines(); + std::string project = cmds[0][0]; + this->WriteProjectConfigurations(fout, project.c_str(), + true); + } + else + { + bool partOfDefaultBuild = this->IsPartOfDefaultBuild( + root->GetMakefile()->GetProjectName(), target); + const char *vcprojName = + target->GetProperty("GENERATOR_FILE_NAME"); + if (vcprojName) + { + this->WriteProjectConfigurations(fout, vcprojName, + partOfDefaultBuild); + } + } + } +} + + +void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( + std::ostream& fout, + cmLocalGenerator* root, + cmGlobalGenerator::TargetDependSet& projectTargets, + cmGlobalGenerator::TargetDependSet& originalTargets + ) +{ + // Create a map of project that should only show up once + // in a project + const char* onlyOnceNames[] = + {"INCLUDE_EXTERNAL_MSPROJECT","CMAKE_CHECK_BUILD_SYSTEM_TARGET", + "INSTALL", "RUN_TESTS", "EDIT_CACHE", "REBUILD_CACHE", "PACKAGE", 0}; + std::map onlyOnceMap; + int i =0; + for(const char* name = onlyOnceNames[i]; + name != 0; name = onlyOnceNames[++i]) + { + onlyOnceMap[name] = 0; + } + // add the CMAKE_CHECK_BUILD_SYSTEM_TARGET + onlyOnceMap[CMAKE_CHECK_BUILD_SYSTEM_TARGET] = 0; + std::string rootdir = root->GetMakefile()->GetStartOutputDirectory(); + rootdir += "/"; + for(cmGlobalGenerator::TargetDependSet::iterator tt = + projectTargets.begin(); tt != projectTargets.end(); ++tt) + { + cmTarget* target = const_cast(*tt); + cmMakefile* mf = target->GetMakefile(); + // look for the all_build rule and add depends to all + // of the original targets (none that were "pulled" into this project) + if(mf == root->GetMakefile() && + strcmp(target->GetName(), "ALL_BUILD") == 0) + { + this->AddAllBuildDepends(root, target, originalTargets); + } + // handle external vc project files + if (strncmp(target->GetName(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) + { + cmCustomCommand cc = target->GetPostBuildCommands()[0]; + const cmCustomCommandLines& cmds = cc.GetCommandLines(); + std::string project = cmds[0][0]; + std::string location = cmds[0][1]; + std::cout << "About to call WriteExternalProject " << this->GetName() << "\n"; + this->WriteExternalProject(fout, project.c_str(), + location.c_str(), cc.GetDepends()); + } + else + { + // if the target is an onlyOnceNames do it once + std::map::iterator o = + onlyOnceMap.find(target->GetName()); + bool skip = false; + if(o != onlyOnceMap.end()) + { + if(o->second > 0) + { + skip = true; + } + else + { + o->second++; + } + } + // if not skipping the project then write it into the + // solution + if(!skip) + { + const char *vcprojName = + target->GetProperty("GENERATOR_FILE_NAME"); + if(vcprojName) + { + cmMakefile* tmf = target->GetMakefile(); + std::string dir = tmf->GetStartOutputDirectory(); + dir = root->Convert(dir.c_str(), + cmLocalGenerator::START_OUTPUT); + this->WriteProject(fout, vcprojName, dir.c_str(), + *target); + } + } + } + } +} + + +void cmGlobalVisualStudio7Generator::WriteTargetDepends( + std::ostream& fout, + cmGlobalGenerator::TargetDependSet& projectTargets + ) +{ + for(cmGlobalGenerator::TargetDependSet::iterator tt = + projectTargets.begin(); tt != projectTargets.end(); ++tt) + { + cmTarget* target = const_cast(*tt); + cmMakefile* mf = target->GetMakefile(); + if (strncmp(target->GetName(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) + { + cmCustomCommand cc = target->GetPostBuildCommands()[0]; + const cmCustomCommandLines& cmds = cc.GetCommandLines(); + std::string name = cmds[0][0]; + std::vector depends = cc.GetDepends(); + std::vector::iterator iter; + int depcount = 0; + for(iter = depends.begin(); iter != depends.end(); ++iter) + { + std::string guid = this->GetGUID(iter->c_str()); + if(guid.size() == 0) + { + std::string m = "Target: "; + m += target->GetName(); + m += " depends on unknown target: "; + m += iter->c_str(); + cmSystemTools::Error(m.c_str()); + } + + fout << "\t\t{" << this->GetGUID(name.c_str()) + << "}." << depcount << " = {" << guid.c_str() << "}\n"; + depcount++; + } + } + else + { + const char *vcprojName = + target->GetProperty("GENERATOR_FILE_NAME"); + if (vcprojName) + { + std::string dir = mf->GetStartDirectory(); + this->WriteProjectDepends(fout, vcprojName, + dir.c_str(), *target); + } + } + } +} // Write a SLN file to the stream void cmGlobalVisualStudio7Generator ::WriteSLNFile(std::ostream& fout, @@ -274,181 +442,17 @@ void cmGlobalVisualStudio7Generator // Write out the header for a SLN file this->WriteSLNHeader(fout); - // Get the start directory with the trailing slash - std::string rootdir = root->GetMakefile()->GetStartOutputDirectory(); - rootdir += "/"; - bool doneAllBuild = false; - bool doneRunTests = false; - bool doneInstall = false; - bool doneEditCache = false; - bool doneRebuildCache = false; - bool donePackage = false; - - - // 1. - // Collecte all targets in generators vector and the targets - // that they depend on - - // 2. loop over all targets and put .vcproj reference - // into .sln file. .vcproj files should already exist - // from local generation step. Do not add "pulled" in .vcproj - // to ALL_BUILD. - // See: cmGlobalGenerator::GetTargetDepends - // cmGlobalGenerator::TargetDependSet myset; - // foreach t in all targets - // cmGlobalGenerator::TargetDependSet const& tset = GetTargetDepends(t); - // myset.insert(tset.begin(), tset.end()); - // foreach t in myset - // t->GetMakefile()->GetLocalGenerator()->GetVCProjPath() - // if t was not in original set of targets disable all for it - - // For each cmMakefile, create a VCProj for it, and - // add it to this SLN file - unsigned int i; - for(i = 0; i < generators.size(); ++i) - { - if(this->IsExcluded(root, generators[i])) - { - continue; - } - cmMakefile* mf = generators[i]->GetMakefile(); - - // Get the source directory from the makefile - std::string dir = mf->GetStartOutputDirectory(); - // remove the home directory and / from the source directory - // this gives a relative path - cmSystemTools::ReplaceString(dir, rootdir.c_str(), ""); - - // Get the list of create dsp files names from the cmVCProjWriter, more - // than one dsp could have been created per input CMakeLists.txt file - // for each target - cmTargets &tgts = generators[i]->GetMakefile()->GetTargets(); - for (cmTargets::iterator l = tgts.begin(); l != tgts.end(); ++l) - { - // special handling for the current makefile - if(mf == generators[0]->GetMakefile()) - { - dir = "."; // no subdirectory for project generated - // if this is the special ALL_BUILD utility, then - // make it depend on every other non UTILITY project. - // This is done by adding the names to the GetUtilities - // vector on the makefile - if(l->first == "ALL_BUILD" && !doneAllBuild) - { - unsigned int j; - for(j = 0; j < generators.size(); ++j) - { - cmTargets &atgts = generators[j]->GetMakefile()->GetTargets(); - for(cmTargets::iterator al = atgts.begin(); - al != atgts.end(); ++al) - { - if (!al->second.GetPropertyAsBool("EXCLUDE_FROM_ALL")) - { - if (al->second.GetType() == cmTarget::UTILITY || - al->second.GetType() == cmTarget::GLOBAL_TARGET) - { - l->second.AddUtility(al->first.c_str()); - } - else - { - l->second.AddLinkLibrary(al->first,cmTarget::GENERAL); - } - } - } - } - } - } - // Write the project into the SLN file - if (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) - { - cmCustomCommand cc = l->second.GetPostBuildCommands()[0]; - const cmCustomCommandLines& cmds = cc.GetCommandLines(); - std::string project = cmds[0][0]; - std::string location = cmds[0][1]; - this->WriteExternalProject(fout, project.c_str(), - location.c_str(), cc.GetDepends()); - } - else - { - bool skip = false; - if(l->first == "ALL_BUILD" ) - { - if(doneAllBuild) - { - skip = true; - } - else - { - doneAllBuild = true; - } - } - if(l->first == "INSTALL") - { - if(doneInstall) - { - skip = true; - } - else - { - doneInstall = true; - } - } - if(l->first == "RUN_TESTS") - { - if(doneRunTests) - { - skip = true; - } - else - { - doneRunTests = true; - } - } - if(l->first == "EDIT_CACHE") - { - if(doneEditCache) - { - skip = true; - } - else - { - doneEditCache = true; - } - } - if(l->first == "REBUILD_CACHE") - { - if(doneRebuildCache) - { - skip = true; - } - else - { - doneRebuildCache = true; - } - } - if(l->first == "PACKAGE") - { - if(donePackage) - { - skip = true; - } - else - { - donePackage = true; - } - } - if(!skip) - { - const char *dspname = - l->second.GetProperty("GENERATOR_FILE_NAME"); - if (dspname) - { - this->WriteProject(fout, dspname, dir.c_str(),l->second); - } - } - } - } - } + // collect the set of targets for this project by + // tracing depends of all targets. + // also collect the set of targets that are explicitly + // in this project. + cmGlobalGenerator::TargetDependSet projectTargets; + cmGlobalGenerator::TargetDependSet originalTargets; + this->GetTargetSets(projectTargets, + originalTargets, + root, generators); + this->WriteTargetsToSolution(fout, root, projectTargets, originalTargets); + // Write out the configurations information for the solution fout << "Global\n" << "\tGlobalSection(SolutionConfiguration) = preSolution\n"; @@ -459,99 +463,15 @@ void cmGlobalVisualStudio7Generator fout << "\t\tConfigName." << c << " = " << *i << "\n"; c++; } - fout << "\tEndGlobalSection\n" - << "\tGlobalSection(ProjectDependencies) = postSolution\n"; - - // loop over again and compute the depends - for(i = 0; i < generators.size(); ++i) - { - cmMakefile* mf = generators[i]->GetMakefile(); - cmLocalVisualStudio7Generator* pg = - static_cast(generators[i]); - // Get the list of create dsp files names from the cmVCProjWriter, more - // than one dsp could have been created per input CMakeLists.txt file - // for each target - cmTargets &tgts = pg->GetMakefile()->GetTargets(); - cmTargets::iterator l = tgts.begin(); - std::string dir = mf->GetStartDirectory(); - for(; l != tgts.end(); ++l) - { - if (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) - { - cmCustomCommand cc = l->second.GetPostBuildCommands()[0]; - const cmCustomCommandLines& cmds = cc.GetCommandLines(); - std::string name = cmds[0][0]; - std::vector depends = cc.GetDepends(); - std::vector::iterator iter; - int depcount = 0; - for(iter = depends.begin(); iter != depends.end(); ++iter) - { - std::string guid = this->GetGUID(iter->c_str()); - if(guid.size() == 0) - { - std::string m = "Target: "; - m += l->first; - m += " depends on unknown target: "; - m += iter->c_str(); - cmSystemTools::Error(m.c_str()); - } - - fout << "\t\t{" << this->GetGUID(name.c_str()) - << "}." << depcount << " = {" << guid.c_str() << "}\n"; - depcount++; - } - } - else - { - const char *dspname = - l->second.GetProperty("GENERATOR_FILE_NAME"); - if (dspname) - { - this->WriteProjectDepends(fout, dspname, - dir.c_str(), l->second); - } - } - } - } fout << "\tEndGlobalSection\n"; + // Write out project(target) depends + fout << "\tGlobalSection(ProjectDependencies) = postSolution\n"; + this->WriteTargetDepends(fout, projectTargets); + fout << "\tEndGlobalSection\n"; + + // Write out the configurations for all the targets in the project fout << "\tGlobalSection(ProjectConfiguration) = postSolution\n"; - // loop over again and compute the depends - for(i = 0; i < generators.size(); ++i) - { - cmMakefile* mf = generators[i]->GetMakefile(); - cmLocalVisualStudio7Generator* pg = - static_cast(generators[i]); - // Get the list of create dsp files names from the cmVCProjWriter, more - // than one dsp could have been created per input CMakeLists.txt file - // for each target - cmTargets &tgts = pg->GetMakefile()->GetTargets(); - cmTargets::iterator l = tgts.begin(); - std::string dir = mf->GetStartDirectory(); - for(; l != tgts.end(); ++l) - { - if(strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) - { - cmCustomCommand cc = l->second.GetPostBuildCommands()[0]; - const cmCustomCommandLines& cmds = cc.GetCommandLines(); - std::string name = cmds[0][0]; - this->WriteProjectConfigurations(fout, name.c_str(), - true); - } - else - { - bool partOfDefaultBuild = this->IsPartOfDefaultBuild( - root->GetMakefile()->GetProjectName(), - &l->second); - const char *dspname = - l->second.GetProperty("GENERATOR_FILE_NAME"); - if (dspname) - { - this->WriteProjectConfigurations(fout, dspname, - partOfDefaultBuild); - } - } - } - } + this->WriteTargetConfigurations(fout, root, projectTargets); fout << "\tEndGlobalSection\n"; // Write the footer for the SLN file @@ -611,7 +531,7 @@ cmGlobalVisualStudio7Generator if(j->first != dspname) { // is the library part of this SLN ? If so add dependency - if(this->FindTarget(this->CurrentProject.c_str(), j->first.c_str())) + if(this->FindTarget(0, j->first.c_str())) { std::string guid = this->GetGUID(j->first.c_str()); if(guid.size() == 0) @@ -687,6 +607,7 @@ void cmGlobalVisualStudio7Generator::WriteExternalProject(std::ostream& fout, const char* location, const std::vector&) { + std::cout << "WriteExternalProject vs7\n"; std::string d = cmSystemTools::ConvertToOutputPath(location); fout << "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"" << name << "\", \"" diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index e90b4dbc4..7b723f21d 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -114,11 +114,29 @@ protected: virtual void WriteSLNHeader(std::ostream& fout); virtual void AddPlatformDefinitions(cmMakefile* mf); + virtual void WriteTargetsToSolution( + std::ostream& fout, + cmLocalGenerator* root, + cmGlobalGenerator::TargetDependSet& projectTargets, + cmGlobalGenerator::TargetDependSet& originalTargets); + virtual void WriteTargetDepends( + std::ostream& fout, + cmGlobalGenerator::TargetDependSet& projectTargets); + virtual void WriteTargetConfigurations( + std::ostream& fout, + cmLocalGenerator* root, + cmGlobalGenerator::TargetDependSet& projectTargets); + + void AddAllBuildDepends(cmLocalGenerator* root, + cmTarget* target, + cmGlobalGenerator::TargetDependSet& targets); + void GenerateConfigurations(cmMakefile* mf); - void WriteExternalProject(std::ostream& fout, - const char* name, const char* path, - const std::vector& dependencies); + virtual void WriteExternalProject(std::ostream& fout, + const char* name, + const char* path, + const std::vector& dependencies); std::string ConvertToSolutionPath(const char* path); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 18b57216d..a22f509b7 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -419,6 +419,7 @@ public: // Check for specific options. bool UsingUnicode(); + bool IsDebug(); // Write options to output. void OutputPreprocessorDefinitions(std::ostream& fout, const char* prefix, @@ -667,7 +668,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, } this->OutputTargetRules(fout, configName, target, libName); - this->OutputBuildTool(fout, configName, target); + this->OutputBuildTool(fout, configName, target, targetOptions.IsDebug()); fout << "\t\t\n"; } @@ -689,7 +690,8 @@ cmLocalVisualStudio7Generator void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, const char* configName, - cmTarget &target) + cmTarget &target, + bool isDebug) { std::string temp; std::string extraLinkOptions; @@ -802,8 +804,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, temp += targetNamePDB; fout << "\t\t\t\tProgramDataBaseFile=\"" << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n"; - if(strcmp(configName, "Debug") == 0 - || strcmp(configName, "RelWithDebInfo") == 0) + if(isDebug) { fout << "\t\t\t\tGenerateDebugInformation=\"TRUE\"\n"; } @@ -869,8 +870,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, fout << "\t\t\t\tProgramDataBaseFile=\"" << target.GetDirectory(configName) << "/" << targetNamePDB << "\"\n"; - if(strcmp(configName, "Debug") == 0 - || strcmp(configName, "RelWithDebInfo") == 0) + if(isDebug) { fout << "\t\t\t\tGenerateDebugInformation=\"TRUE\"\n"; } @@ -1813,6 +1813,12 @@ void cmLocalVisualStudio7GeneratorOptions::AddFlag(const char* flag, this->FlagMap[flag] = value; } + +bool cmLocalVisualStudio7GeneratorOptions::IsDebug() +{ + return this->FlagMap.find("DebugInformationFormat") != this->FlagMap.end(); +} + //---------------------------------------------------------------------------- bool cmLocalVisualStudio7GeneratorOptions::UsingUnicode() { diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 11b6736da..b59936245 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -96,7 +96,7 @@ private: void OutputTargetRules(std::ostream& fout, const char* configName, cmTarget &target, const char *libName); void OutputBuildTool(std::ostream& fout, const char* configName, - cmTarget& t); + cmTarget& t, bool debug); void OutputLibraryDirectories(std::ostream& fout, std::vector const& dirs); void OutputModuleDefinitionFile(std::ostream& fout, cmTarget &target); diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 09c62e172..8314fbd98 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -52,7 +52,40 @@ IF(BUILD_TESTING) ADD_TEST_MACRO(SourceGroups SourceGroups) ADD_TEST_MACRO(Preprocess Preprocess) ADD_TEST_MACRO(ExportImport ExportImport) - + + # test for correct sub-project generation + # not implemented in VS6 or Xcode + IF(NOT MSVC60 AND NOT XCODE) + # run cmake and configure all of SubProject + # but only build the independent executable car + ADD_TEST(SubProject ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/SubProject" + "${CMake_BINARY_DIR}/Tests/SubProject" + --build-project SubProject + --build-generator ${CMAKE_TEST_GENERATOR} + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --build-target car + --test-command car + ) + # For stage 2, do not run cmake again. + # Then build the foo sub project which should build + # the bar library which should be referenced because + # foo links to the static library bar, but bar is not + # directly in the foo sub project + ADD_TEST(SubProject-Stage2 ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/SubProject/foo" + "${CMake_BINARY_DIR}/Tests/SubProject/foo" + --build-generator ${CMAKE_TEST_GENERATOR} + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --build-nocmake + --build-project foo + --build-target foo + --test-command foo + ) + ENDIF(NOT MSVC60 AND NOT XCODE) + IF (CMAKE_STRICT) ADD_TEST_MACRO(DocTest DocTest) ENDIF (CMAKE_STRICT) @@ -505,7 +538,6 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=CVS -P ${CMake_SOURCE_DIR}/Utilities/Rel ENDIF(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG) ENDIF("${CMAKE_SYSTEM_NAME}" MATCHES syllable) - ADD_TEST(linkorder1 ${CMAKE_CTEST_COMMAND} --build-and-test "${CMake_SOURCE_DIR}/Tests/LinkLineOrder" diff --git a/Tests/SubProject/CMakeLists.txt b/Tests/SubProject/CMakeLists.txt new file mode 100644 index 000000000..f825749cf --- /dev/null +++ b/Tests/SubProject/CMakeLists.txt @@ -0,0 +1,5 @@ +project(SubProject) +message("${CMAKE_IMPORT_LIBRARY_SUFFIX}") +add_library(bar bar.cxx) +add_executable(car car.cxx) +add_subdirectory(foo) diff --git a/Tests/SubProject/bar.cxx b/Tests/SubProject/bar.cxx new file mode 100644 index 000000000..c3f6a181a --- /dev/null +++ b/Tests/SubProject/bar.cxx @@ -0,0 +1,4 @@ +int bar() +{ + return 10; +} diff --git a/Tests/SubProject/car.cxx b/Tests/SubProject/car.cxx new file mode 100644 index 000000000..95de4a327 --- /dev/null +++ b/Tests/SubProject/car.cxx @@ -0,0 +1,6 @@ +int main(int ac, char** av) +{ + (void) ac; + (void) av; + return 0; +}