diff options
Diffstat (limited to 'Source')
47 files changed, 1199 insertions, 356 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 354f123..8bf6c40 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -176,6 +176,10 @@ set(SRCS cmExportFileGenerator.cxx cmExportInstallFileGenerator.h cmExportInstallFileGenerator.cxx + cmExportSet.h + cmExportSet.cxx + cmExportSetMap.h + cmExportSetMap.cxx cmExtraCodeBlocksGenerator.cxx cmExtraCodeBlocksGenerator.h cmExtraEclipseCDT4Generator.cxx @@ -183,6 +187,8 @@ set(SRCS cmFileTimeComparison.cxx cmFileTimeComparison.h cmGeneratedFileStream.cxx + cmGeneratorExpressionDAGChecker.cxx + cmGeneratorExpressionDAGChecker.h cmGeneratorExpressionEvaluator.cxx cmGeneratorExpressionEvaluator.h cmGeneratorExpressionLexer.cxx @@ -257,6 +263,7 @@ set(SRCS cmSystemTools.h cmTarget.cxx cmTarget.h + cmTargetExport.h cmTest.cxx cmTest.h cmTestGenerator.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 31b2bf2..84cc45b 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -2,5 +2,5 @@ set(CMake_VERSION_MAJOR 2) set(CMake_VERSION_MINOR 8) set(CMake_VERSION_PATCH 9) -set(CMake_VERSION_TWEAK 20120928) +set(CMake_VERSION_TWEAK 20121002) #set(CMake_VERSION_RC 1) diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index 49cea2e..2668c8e 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -38,11 +38,11 @@ cmCTestSVN::~cmCTestSVN() //---------------------------------------------------------------------------- void cmCTestSVN::CleanupImpl() { - const char* svn = this->CommandLineTool.c_str(); - const char* svn_cleanup[] = {svn, "cleanup", 0}; + std::vector<const char*> svn_cleanup; + svn_cleanup.push_back("cleanup"); OutputLogger out(this->Log, "cleanup-out> "); OutputLogger err(this->Log, "cleanup-err> "); - this->RunChild(svn_cleanup, &out, &err); + this->RunSVNCommand(svn_cleanup, &out, &err); } //---------------------------------------------------------------------------- @@ -106,12 +106,13 @@ static bool cmCTestSVNPathStarts(std::string const& p1, std::string const& p2) std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo) { // Run "svn info" to get the repository info from the work tree. - const char* svn = this->CommandLineTool.c_str(); - const char* svn_info[] = {svn, "info", svninfo.LocalPath.c_str(), 0}; + std::vector<const char*> svn_info; + svn_info.push_back("info"); + svn_info.push_back(svninfo.LocalPath.c_str()); std::string rev; InfoParser out(this, "info-out> ", rev, svninfo); OutputLogger err(this->Log, "info-err> "); - this->RunChild(svn_info, &out, &err); + this->RunSVNCommand(svn_info, &out, &err); return rev; } @@ -285,19 +286,52 @@ bool cmCTestSVN::UpdateImpl() } std::vector<char const*> svn_update; - svn_update.push_back(this->CommandLineTool.c_str()); svn_update.push_back("update"); - svn_update.push_back("--non-interactive"); for(std::vector<cmStdString>::const_iterator ai = args.begin(); ai != args.end(); ++ai) { svn_update.push_back(ai->c_str()); } - svn_update.push_back(0); UpdateParser out(this, "up-out> "); OutputLogger err(this->Log, "up-err> "); - return this->RunUpdateCommand(&svn_update[0], &out, &err); + return this->RunSVNCommand(svn_update, &out, &err); +} + +//---------------------------------------------------------------------------- +bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters, + OutputParser* out, OutputParser* err) +{ + if(parameters.empty()) return false; + + std::vector<char const*> args; + args.push_back(this->CommandLineTool.c_str()); + + args.insert(args.end(), parameters.begin(), parameters.end()); + + args.push_back("--non-interactive"); + + std::string userOptions = + this->CTest->GetCTestConfiguration("SVNOptions"); + + std::vector<cmStdString> parsedUserOptions = + cmSystemTools::ParseArguments(userOptions.c_str()); + for(std::vector<cmStdString>::iterator i = parsedUserOptions.begin(); + i != parsedUserOptions.end(); ++i) + { + args.push_back(i->c_str()); + } + + args.push_back(0); + + if(strcmp(parameters[0], "update") == 0) + { + return RunUpdateCommand(&args[0], out, err); + } + else + { + return RunChild(&args[0], out, err); + } } //---------------------------------------------------------------------------- @@ -417,14 +451,15 @@ void cmCTestSVN::LoadRevisions(SVNInfo &svninfo) } // Run "svn log" to get all global revisions of interest. - const char* svn = this->CommandLineTool.c_str(); - const char* svn_log[] = {svn, "log", "--xml", "-v", revs.c_str(), - svninfo.LocalPath.c_str(), 0}; - { + std::vector<const char*> svn_log; + svn_log.push_back("log"); + svn_log.push_back("--xml"); + svn_log.push_back("-v"); + svn_log.push_back(revs.c_str()); + svn_log.push_back(svninfo.LocalPath.c_str()); LogParser out(this, "log-out> ", svninfo); OutputLogger err(this->Log, "log-err> "); - this->RunChild(svn_log, &out, &err); - } + this->RunSVNCommand(svn_log, &out, &err); } //---------------------------------------------------------------------------- @@ -492,11 +527,11 @@ private: void cmCTestSVN::LoadModifications() { // Run "svn status" which reports local modifications. - const char* svn = this->CommandLineTool.c_str(); - const char* svn_status[] = {svn, "status", "--non-interactive", 0}; + std::vector<const char*> svn_status; + svn_status.push_back("status"); StatusParser out(this, "status-out> "); OutputLogger err(this->Log, "status-err> "); - this->RunChild(svn_status, &out, &err); + this->RunSVNCommand(svn_status, &out, &err); } //---------------------------------------------------------------------------- @@ -550,11 +585,11 @@ private: void cmCTestSVN::LoadExternals() { // Run "svn status" to get the list of external repositories - const char* svn = this->CommandLineTool.c_str(); - const char* svn_status[] = {svn, "status", 0}; + std::vector<const char*> svn_status; + svn_status.push_back("status"); ExternalParser out(this, "external-out> "); OutputLogger err(this->Log, "external-err> "); - this->RunChild(svn_status, &out, &err); + this->RunSVNCommand(svn_status, &out, &err); } //---------------------------------------------------------------------------- diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h index 56265d0..73d676e 100644 --- a/Source/CTest/cmCTestSVN.h +++ b/Source/CTest/cmCTestSVN.h @@ -33,6 +33,9 @@ private: virtual void NoteNewRevision(); virtual bool UpdateImpl(); + bool RunSVNCommand(std::vector<char const*> const& parameters, + OutputParser* out, OutputParser* err); + // Information about an SVN repository (root repository or external) struct SVNInfo { diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx index 8414349..2ca9f6c 100644 --- a/Source/CTest/cmCTestUpdateCommand.cxx +++ b/Source/CTest/cmCTestUpdateCommand.cxx @@ -44,6 +44,8 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler() this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, "SVNUpdateOptions", "CTEST_SVN_UPDATE_OPTIONS"); this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, + "SVNOptions", "CTEST_SVN_OPTIONS"); + this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, "BZRCommand", "CTEST_BZR_COMMAND"); this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, "BZRUpdateOptions", "CTEST_BZR_UPDATE_OPTIONS"); diff --git a/Source/cmAddTestCommand.h b/Source/cmAddTestCommand.h index b11bff9..6a0cd9d 100644 --- a/Source/cmAddTestCommand.h +++ b/Source/cmAddTestCommand.h @@ -81,7 +81,7 @@ public: "\n" "Arguments after COMMAND may use \"generator expressions\" with the " "syntax \"$<...>\". " - CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS + CM_DOCUMENT_ADD_TEST_GENERATOR_EXPRESSIONS "Example usage:\n" " add_test(NAME mytest\n" " COMMAND testDriver --config $<CONFIGURATION>\n" diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h index 74c673a..445fd0e 100644 --- a/Source/cmDocumentGeneratorExpressions.h +++ b/Source/cmDocumentGeneratorExpressions.h @@ -12,7 +12,7 @@ #ifndef cmDocumentGeneratorExpressions_h #define cmDocumentGeneratorExpressions_h -#define CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS \ +#define CM_DOCUMENT_ADD_TEST_GENERATOR_EXPRESSIONS \ "Generator expressions are evaluted during build system generation " \ "to produce information specific to each build configuration. " \ "Valid expressions are:\n" \ @@ -20,6 +20,12 @@ " $<1:...> = content of \"...\"\n" \ " $<CONFIG:cfg> = '1' if config is \"cfg\", else '0'\n" \ " $<CONFIGURATION> = configuration name\n" \ + " $<BOOL:...> = '1' if the '...' is true, else '0'\n" \ + " $<STREQUAL:a,b> = '1' if a is STREQUAL b, else '0'\n" \ + " $<ANGLE-R> = A literal '>'. Used to compare " \ + "strings which contain a '>' for example.\n" \ + " $<COMMA> = A literal ','. Used to compare " \ + "strings which contain a ',' for example.\n" \ " $<TARGET_FILE:tgt> = main file (.exe, .so.1.2, .a)\n" \ " $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n" \ " $<TARGET_SONAME_FILE:tgt> = file with soname (.so.3)\n" \ @@ -29,6 +35,10 @@ " $<TARGET_FILE_DIR:tgt>/$<TARGET_FILE_NAME:tgt>\n" \ " $<TARGET_LINKER_FILE_DIR:tgt>/$<TARGET_LINKER_FILE_NAME:tgt>\n" \ " $<TARGET_SONAME_FILE_DIR:tgt>/$<TARGET_SONAME_FILE_NAME:tgt>\n" \ + "\n" \ + " $<TARGET_PROPERTY:tgt,prop> = The value of the property prop\n" \ + "on the target tgt. Note that tgt is not added as a dependency of\n" \ + "the target this expression is evaluated on.\n" \ "Boolean expressions:\n" \ " $<AND:?[,?]...> = '1' if all '?' are '1', else '0'\n" \ " $<OR:?[,?]...> = '0' if all '?' are '0', else '1'\n" \ @@ -36,4 +46,11 @@ "where '?' is always either '0' or '1'.\n" \ "" +#define CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS \ + CM_DOCUMENT_ADD_TEST_GENERATOR_EXPRESSIONS \ + "Expressions with an implicit 'this' target:\n" \ + " $<TARGET_PROPERTY:prop> = The value of the property prop on\n" \ + "the target on which the generator expression is evaluated.\n" \ + "" + #endif diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index 5e7e081..8db0e8f 100644 --- a/Source/cmDocumentVariables.cxx +++ b/Source/cmDocumentVariables.cxx @@ -701,7 +701,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_SYSTEM_IGNORE_PATH", cmProperty::VARIABLE, "Path to be ignored by FIND_XXX() commands.", - "Specifies directories to be ignored by searches in FIND_XXX() commands " + "Specifies directories to be ignored by searches in FIND_XXX() " + "commands. " "This is useful in cross-compiled environments where some system " "directories contain incompatible but possibly linkable libraries. For " "example, on cross-compiled cluster environments, this allows a user to " @@ -716,7 +717,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm) cm->DefineProperty ("CMAKE_IGNORE_PATH", cmProperty::VARIABLE, "Path to be ignored by FIND_XXX() commands.", - "Specifies directories to be ignored by searches in FIND_XXX() commands " + "Specifies directories to be ignored by searches in FIND_XXX() " + "commands. " "This is useful in cross-compiled environments where some system " "directories contain incompatible but possibly linkable libraries. For " "example, on cross-compiled cluster environments, this allows a user to " @@ -1211,6 +1213,15 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "Variables that Control the Build"); cm->DefineProperty + ("CMAKE_PDB_OUTPUT_DIRECTORY", cmProperty::VARIABLE, + "Where to put all the MS debug symbol files.", + "This variable is used to initialize the " + "PDB_OUTPUT_DIRECTORY property on all the targets. " + "See that target property for additional information.", + false, + "Variables that Control the Build"); + + cm->DefineProperty ("CMAKE_AUTOMOC", cmProperty::VARIABLE, "Whether to handle moc automatically for Qt targets.", "This variable is used to initialize the " diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 32595ee..fb3f39f 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -72,8 +72,9 @@ cmExportBuildFileGenerator if(!properties.empty()) { // Get the rest of the target details. + std::vector<std::string> missingTargets; this->SetImportDetailProperties(config, suffix, - target, properties); + target, properties, missingTargets); // TOOD: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff @@ -82,6 +83,7 @@ cmExportBuildFileGenerator // properties); // Generate code in the export file. + this->GenerateMissingTargetsCheckCode(os, missingTargets); this->GenerateImportPropertyCode(os, config, target, properties); } } @@ -133,6 +135,25 @@ cmExportBuildFileGenerator //---------------------------------------------------------------------------- void +cmExportBuildFileGenerator::HandleMissingTarget( + std::string& link_libs, std::vector<std::string>&, + cmMakefile*, cmTarget* depender, cmTarget* dependee) +{ + // The target is not in the export. + if(!this->AppendMode) + { + // We are not appending, so all exported targets should be + // known here. This is probably user-error. + this->ComplainAboutMissingTarget(depender, dependee); + } + // Assume the target will be exported by another command. + // Append it with the export namespace. + link_libs += this->Namespace; + link_libs += dependee->GetName(); +} + +//---------------------------------------------------------------------------- +void cmExportBuildFileGenerator ::ComplainAboutMissingTarget(cmTarget* depender, cmTarget* dependee) diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 0f37626..726537b 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -45,8 +45,14 @@ protected: virtual void GenerateImportTargetsConfig(std::ostream& os, const char* config, std::string const& suffix); - virtual void ComplainAboutMissingTarget(cmTarget* depender, - cmTarget* dependee); + virtual void HandleMissingTarget(std::string& link_libs, + std::vector<std::string>& missingTargets, + cmMakefile* mf, + cmTarget* depender, + cmTarget* dependee); + + void ComplainAboutMissingTarget(cmTarget* depender, + cmTarget* dependee); /** Fill in properties indicating built file locations. */ void SetImportLocationProperty(const char* config, diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index eb19df5e..8dffae4 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -11,10 +11,15 @@ ============================================================================*/ #include "cmExportFileGenerator.h" +#include "cmExportSet.h" #include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmInstallExportGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSystemTools.h" #include "cmTarget.h" +#include "cmTargetExport.h" #include "cmVersion.h" #include <cmsys/auto_ptr.hxx> @@ -123,7 +128,9 @@ void cmExportFileGenerator::GenerateImportConfig(std::ostream& os, void cmExportFileGenerator ::SetImportDetailProperties(const char* config, std::string const& suffix, - cmTarget* target, ImportPropertyMap& properties) + cmTarget* target, ImportPropertyMap& properties, + std::vector<std::string>& missingTargets + ) { // Get the makefile in which to lookup target information. cmMakefile* mf = target->GetMakefile(); @@ -159,13 +166,13 @@ cmExportFileGenerator { this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_INTERFACE_LANGUAGES", - iface->Languages, properties); + iface->Languages, properties, missingTargets); this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_INTERFACE_LIBRARIES", - iface->Libraries, properties); + iface->Libraries, properties, missingTargets); this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_DEPENDENT_LIBRARIES", - iface->SharedDeps, properties); + iface->SharedDeps, properties, missingTargets); if(iface->Multiplicity > 0) { std::string prop = "IMPORTED_LINK_INTERFACE_MULTIPLICITY"; @@ -184,7 +191,9 @@ cmExportFileGenerator cmTarget* target, const char* propName, std::vector<std::string> const& libs, - ImportPropertyMap& properties) + ImportPropertyMap& properties, + std::vector<std::string>& missingTargets + ) { // Skip the property if there are no libraries. if(libs.empty()) @@ -224,17 +233,7 @@ cmExportFileGenerator } else { - // The target is not in the export. - if(!this->AppendMode) - { - // We are not appending, so all exported targets should be - // known here. This is probably user-error. - this->ComplainAboutMissingTarget(target, tgt); - } - // Assume the target will be exported by another command. - // Append it with the export namespace. - link_libs += this->Namespace; - link_libs += *li; + this->HandleMissingTarget(link_libs, missingTargets, mf, target, tgt); } } else @@ -250,6 +249,7 @@ cmExportFileGenerator properties[prop] = link_libs; } + //---------------------------------------------------------------------------- void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os, const char* config) @@ -381,6 +381,30 @@ cmExportFileGenerator //---------------------------------------------------------------------------- +void cmExportFileGenerator::GenerateMissingTargetsCheckCode(std::ostream& os, + const std::vector<std::string>& missingTargets) +{ + os << "# Make sure the targets which have been exported in some other \n" + "# export set exist.\n"; + for(unsigned int i=0; i<missingTargets.size(); ++i) + { + os << "IF(NOT TARGET \"" << missingTargets[i] << "\" )\n" + << " IF(CMAKE_FIND_PACKAGE_NAME)\n" + << " SET( ${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)\n" + << " SET( ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE " + << "\"Required imported target \\\"" << missingTargets[i] + << "\\\" not found ! \")\n" + << " ELSE()\n" + << " MESSAGE(FATAL_ERROR \"Required imported target \\\"" + << missingTargets[i] << "\\\" not found ! \")\n" + << " ENDIF()\n" + << "ENDIF()\n"; + } + os << "\n"; +} + + +//---------------------------------------------------------------------------- void cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os) { diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index f271e55..70bc65d 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -60,17 +60,21 @@ protected: ImportPropertyMap const& properties, const std::set<std::string>& importedLocations); void GenerateImportedFileCheckLoop(std::ostream& os); + void GenerateMissingTargetsCheckCode(std::ostream& os, + const std::vector<std::string>& missingTargets); // Collect properties with detailed information about targets beyond // their location on disk. void SetImportDetailProperties(const char* config, std::string const& suffix, cmTarget* target, - ImportPropertyMap& properties); + ImportPropertyMap& properties, + std::vector<std::string>& missingTargets); void SetImportLinkProperty(std::string const& suffix, cmTarget* target, const char* propName, std::vector<std::string> const& libs, - ImportPropertyMap& properties); + ImportPropertyMap& properties, + std::vector<std::string>& missingTargets); /** Each subclass knows how to generate its kind of export file. */ virtual bool GenerateMainFile(std::ostream& os) = 0; @@ -80,10 +84,13 @@ protected: const char* config, std::string const& suffix) = 0; - /** Each subclass knows how to complain about a target that is - missing from an export set. */ - virtual void ComplainAboutMissingTarget(cmTarget* depender, - cmTarget* dependee) = 0; + /** Each subclass knows how to deal with a target that is missing from an + * export set. */ + virtual void HandleMissingTarget(std::string& link_libs, + std::vector<std::string>& missingTargets, + cmMakefile* mf, + cmTarget* depender, + cmTarget* dependee) = 0; // The namespace in which the exports are placed in the generated file. std::string Namespace; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index da14dd7..7841731 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -11,14 +11,19 @@ ============================================================================*/ #include "cmExportInstallFileGenerator.h" +#include "cmExportSet.h" +#include "cmExportSetMap.h" #include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmLocalGenerator.h" #include "cmInstallExportGenerator.h" #include "cmInstallTargetGenerator.h" +#include "cmTargetExport.h" //---------------------------------------------------------------------------- cmExportInstallFileGenerator ::cmExportInstallFileGenerator(cmInstallExportGenerator* iegen): - InstallExportGenerator(iegen) + IEGen(iegen) { } @@ -36,10 +41,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) { // Create all the imported targets. for(std::vector<cmTargetExport*>::const_iterator - tei = this->ExportSet->begin(); - tei != this->ExportSet->end(); ++tei) + tei = this->IEGen->GetExportSet()->GetTargetExports()->begin(); + tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei) { - cmTargetExport* te = *tei; + cmTargetExport const* te = *tei; if(this->ExportedTargets.insert(te->Target).second) { this->GenerateImportTargetCode(os, te->Target); @@ -47,8 +52,9 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) else { cmOStringStream e; - e << "INSTALL(EXPORT \"" << this->Name << "\" ...) " - << "includes target \"" << te->Target->GetName() + e << "INSTALL(EXPORT \"" + << this->IEGen->GetExportSet()->GetName() + << "\" ...) " << "includes target \"" << te->Target->GetName() << "\" more than once in the export set."; cmSystemTools::Error(e.str().c_str()); return false; @@ -84,7 +90,7 @@ bool cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config) { // Skip configurations not enabled for this export. - if(!this->InstallExportGenerator->InstallsForConfig(config)) + if(!this->IEGen->InstallsForConfig(config)) { return true; } @@ -140,7 +146,7 @@ cmExportInstallFileGenerator { // Add code to compute the installation prefix relative to the // import file location. - const char* installDest = this->InstallExportGenerator->GetDestination(); + const char* installDest = this->IEGen->GetDestination(); if(!cmSystemTools::FileIsFullPath(installDest)) { std::string dest = installDest; @@ -161,11 +167,11 @@ cmExportInstallFileGenerator // Add each target in the set to the export. for(std::vector<cmTargetExport*>::const_iterator - tei = this->ExportSet->begin(); - tei != this->ExportSet->end(); ++tei) + tei = this->IEGen->GetExportSet()->GetTargetExports()->begin(); + tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei) { // Collect import properties for this target. - cmTargetExport* te = *tei; + cmTargetExport const* te = *tei; ImportPropertyMap properties; std::set<std::string> importedLocations; this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator, @@ -185,8 +191,9 @@ cmExportInstallFileGenerator if(!properties.empty()) { // Get the rest of the target details. + std::vector<std::string> missingTargets; this->SetImportDetailProperties(config, suffix, - te->Target, properties); + te->Target, properties, missingTargets); // TOOD: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff @@ -195,6 +202,7 @@ cmExportInstallFileGenerator // properties); // Generate code in the export file. + this->GenerateMissingTargetsCheckCode(os, missingTargets); this->GenerateImportPropertyCode(os, config, te->Target, properties); this->GenerateImportedFileChecksCode(os, te->Target, properties, importedLocations); @@ -306,12 +314,80 @@ cmExportInstallFileGenerator //---------------------------------------------------------------------------- void +cmExportInstallFileGenerator::HandleMissingTarget( + std::string& link_libs, std::vector<std::string>& missingTargets, + cmMakefile* mf, cmTarget* depender, cmTarget* dependee) +{ + std::string name = dependee->GetName(); + std::vector<std::string> namespaces = this->FindNamespaces(mf, name); + int targetOccurrences = (int)namespaces.size(); + if (targetOccurrences == 1) + { + std::string missingTarget = namespaces[0]; + missingTarget += name; + link_libs += missingTarget; + missingTargets.push_back(missingTarget); + } + else + { + // We are not appending, so all exported targets should be + // known here. This is probably user-error. + this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences); + } +} + +//---------------------------------------------------------------------------- +std::vector<std::string> +cmExportInstallFileGenerator +::FindNamespaces(cmMakefile* mf, const std::string& name) +{ + std::vector<std::string> namespaces; + cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator(); + const cmExportSetMap& exportSets = gg->GetExportSets(); + + for(cmExportSetMap::const_iterator expIt = exportSets.begin(); + expIt != exportSets.end(); + ++expIt) + { + const cmExportSet* exportSet = expIt->second; + std::vector<cmTargetExport*> const* targets = + exportSet->GetTargetExports(); + + bool containsTarget = false; + for(unsigned int i=0; i<targets->size(); i++) + { + if (name == (*targets)[i]->Target->GetName()) + { + containsTarget = true; + break; + } + } + + if (containsTarget) + { + std::vector<cmInstallExportGenerator const*> const* installs = + exportSet->GetInstallations(); + for(unsigned int i=0; i<installs->size(); i++) + { + namespaces.push_back((*installs)[i]->GetNamespace()); + } + } + } + + return namespaces; +} + + +//---------------------------------------------------------------------------- +void cmExportInstallFileGenerator ::ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen) { - const char* installDest = this->InstallExportGenerator->GetDestination(); + const char* installDest = this->IEGen->GetDestination(); cmOStringStream e; - e << "INSTALL(EXPORT \"" << this->Name << "\") given absolute " + e << "INSTALL(EXPORT \"" + << this->IEGen->GetExportSet()->GetName() + << "\") given absolute " << "DESTINATION \"" << installDest << "\" but the export " << "references an installation of target \"" << itgen->GetTarget()->GetName() << "\" which has relative " @@ -322,12 +398,24 @@ cmExportInstallFileGenerator //---------------------------------------------------------------------------- void cmExportInstallFileGenerator -::ComplainAboutMissingTarget(cmTarget* depender, cmTarget* dependee) +::ComplainAboutMissingTarget(cmTarget* depender, + cmTarget* dependee, + int occurrences) { cmOStringStream e; - e << "INSTALL(EXPORT \"" << this->Name << "\" ...) " + e << "INSTALL(EXPORT \"" + << this->IEGen->GetExportSet()->GetName() + << "\" ...) " << "includes target \"" << depender->GetName() - << "\" which requires target \"" << dependee->GetName() - << "\" that is not in the export set."; + << "\" which requires target \"" << dependee->GetName() << "\" "; + if (occurrences == 0) + { + e << "that is not in the export set."; + } + else + { + e << "that is not in this export set, but " << occurrences + << " times in others."; + } cmSystemTools::Error(e.str().c_str()); } diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index fb678e8..e719ecc 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -18,6 +18,7 @@ class cmInstallExportGenerator; class cmInstallFilesGenerator; class cmInstallTargetGenerator; class cmTargetExport; +class cmExportSet; /** \class cmExportInstallFileGenerator * \brief Generate a file exporting targets from an install tree. @@ -40,15 +41,6 @@ public: files. */ cmExportInstallFileGenerator(cmInstallExportGenerator* iegen); - /** Set the name of the export associated with the files. This is - the name given to the install(EXPORT) command mode. */ - void SetName(const char* name) { this->Name = name; } - - /** Set the set of targets to be exported. These are the targets - associated with the export name. */ - void SetExportSet(std::vector<cmTargetExport*> const* eSet) - { this->ExportSet = eSet; } - /** Get the per-config file generated for each configuraiton. This maps from the configuration name to the file temporary location for installation. */ @@ -65,8 +57,19 @@ protected: virtual void GenerateImportTargetsConfig(std::ostream& os, const char* config, std::string const& suffix); - virtual void ComplainAboutMissingTarget(cmTarget* depender, - cmTarget* dependee); + virtual void HandleMissingTarget(std::string& link_libs, + std::vector<std::string>& missingTargets, + cmMakefile* mf, + cmTarget* depender, + cmTarget* dependee); + + void ComplainAboutMissingTarget(cmTarget* depender, + cmTarget* dependee, + int occurrences); + + std::vector<std::string> FindNamespaces(cmMakefile* mf, + const std::string& name); + /** Generate a per-configuration file for the targets. */ bool GenerateImportFileConfig(const char* config); @@ -81,9 +84,7 @@ protected: void ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen); - cmInstallExportGenerator* InstallExportGenerator; - std::string Name; - std::vector<cmTargetExport*> const* ExportSet; + cmInstallExportGenerator* IEGen; std::string ImportPrefix; @@ -91,34 +92,4 @@ protected: std::map<cmStdString, cmStdString> ConfigImportFiles; }; -/* - cmTargetExport is used in cmGlobalGenerator to collect the install - generators for targets associated with an export. -*/ -class cmTargetExport -{ -public: - cmTargetExport(cmTarget* tgt, - cmInstallTargetGenerator* archive, - cmInstallTargetGenerator* runtime, - cmInstallTargetGenerator* library, - cmInstallTargetGenerator* framework, - cmInstallTargetGenerator* bundle, - cmInstallFilesGenerator* headers - ) : Target(tgt), ArchiveGenerator(archive), - RuntimeGenerator(runtime), LibraryGenerator(library), - FrameworkGenerator(framework), BundleGenerator(bundle), - HeaderGenerator(headers) {} - - cmTarget* Target; - cmInstallTargetGenerator* ArchiveGenerator; - cmInstallTargetGenerator* RuntimeGenerator; - cmInstallTargetGenerator* LibraryGenerator; - cmInstallTargetGenerator* FrameworkGenerator; - cmInstallTargetGenerator* BundleGenerator; - cmInstallFilesGenerator* HeaderGenerator; -private: - cmTargetExport(); -}; - #endif diff --git a/Source/cmExportSet.cxx b/Source/cmExportSet.cxx new file mode 100644 index 0000000..33b0630 --- /dev/null +++ b/Source/cmExportSet.cxx @@ -0,0 +1,32 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmExportSet.h" +#include "cmTargetExport.h" + +cmExportSet::~cmExportSet() +{ + for(unsigned int i = 0; i < this->TargetExports.size(); ++ i) + { + delete this->TargetExports[i]; + } +} + +void cmExportSet::AddTargetExport(cmTargetExport* te) +{ + this->TargetExports.push_back(te); +} + +void cmExportSet::AddInstallation(cmInstallExportGenerator const* installation) +{ + this->Installations.push_back(installation); +} diff --git a/Source/cmExportSet.h b/Source/cmExportSet.h new file mode 100644 index 0000000..a57aa12 --- /dev/null +++ b/Source/cmExportSet.h @@ -0,0 +1,46 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmExportSet_h +#define cmExportSet_h + +#include "cmSystemTools.h" +class cmTargetExport; +class cmInstallExportGenerator; + +/// A set of targets that were installed with the same EXPORT parameter. +class cmExportSet +{ +public: + /// Construct an empty export set named \a name + cmExportSet(const std::string &name) : Name(name) {} + /// Destructor + ~cmExportSet(); + + void AddTargetExport(cmTargetExport* tgt); + + void AddInstallation(cmInstallExportGenerator const* installation); + + std::string const& GetName() const { return this->Name; } + + std::vector<cmTargetExport*> const* GetTargetExports() const + { return &this->TargetExports; } + + std::vector<cmInstallExportGenerator const*> const* GetInstallations() const + { return &this->Installations; } + +private: + std::vector<cmTargetExport*> TargetExports; + std::string Name; + std::vector<cmInstallExportGenerator const*> Installations; +}; + +#endif diff --git a/Source/cmExportSetMap.cxx b/Source/cmExportSetMap.cxx new file mode 100644 index 0000000..96fdb3e --- /dev/null +++ b/Source/cmExportSetMap.cxx @@ -0,0 +1,34 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmExportSetMap.h" +#include "cmExportSet.h" + +cmExportSet* cmExportSetMap::operator[](const std::string &name) +{ + std::map<std::string, cmExportSet*>::iterator it = this->find(name); + if (it == this->end()) // Export set not found + { + it = this->insert(std::make_pair(name, new cmExportSet(name))).first; + } + return it->second; +} + +cmExportSetMap::~cmExportSetMap() +{ + for(std::map<std::string, cmExportSet*>::iterator it = this->begin(); + it != this->end(); + ++ it) + { + delete it->second; + } +} diff --git a/Source/cmExportSetMap.h b/Source/cmExportSetMap.h new file mode 100644 index 0000000..4663c55 --- /dev/null +++ b/Source/cmExportSetMap.h @@ -0,0 +1,33 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmExportSetMap_h +#define cmExportSetMap_h + +#include "cmSystemTools.h" +class cmExportSet; + +/// A name -> cmExportSet map with overloaded operator[]. +class cmExportSetMap : public std::map<std::string, cmExportSet*> +{ +public: + /** \brief Overloaded operator[]. + * + * The operator is overloaded because cmExportSet has no default constructor: + * we do not want unnamed export sets. + */ + cmExportSet* operator[](const std::string &name); + + /// Overloaded destructor deletes all member export sets. + ~cmExportSetMap(); +}; + +#endif diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index b1bbd90..8b2daba 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -617,14 +617,17 @@ void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout, " <Option compiler=\"" << compiler << "\" />\n" " <Compiler>\n"; + cmGeneratorTarget *gtgt = this->GlobalGenerator + ->GetGeneratorTarget(target); + // the compilerdefines for this target - const char* cdefs = target->GetMakefile()->GetProperty( - "COMPILE_DEFINITIONS"); - if(cdefs) + std::string cdefs = gtgt->GetCompileDefinitions(); + + if(cdefs.empty()) { // Expand the list. std::vector<std::string> defs; - cmSystemTools::ExpandListArgument(cdefs, defs); + cmSystemTools::ExpandListArgument(cdefs.c_str(), defs); for(std::vector<std::string>::const_iterator di = defs.begin(); di != defs.end(); ++di) { @@ -633,59 +636,57 @@ void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout, } } - // the include directories for this target - std::set<std::string> uniqIncludeDirs; + // the include directories for this target + std::set<std::string> uniqIncludeDirs; + + std::vector<std::string> includes; + target->GetMakefile()->GetLocalGenerator()-> + GetIncludeDirectories(includes, gtgt); + for(std::vector<std::string>::const_iterator dirIt=includes.begin(); + dirIt != includes.end(); + ++dirIt) + { + uniqIncludeDirs.insert(*dirIt); + } - cmGeneratorTarget *gtgt = this->GlobalGenerator - ->GetGeneratorTarget(target); - std::vector<std::string> includes; - target->GetMakefile()->GetLocalGenerator()-> - GetIncludeDirectories(includes, gtgt); - for(std::vector<std::string>::const_iterator dirIt=includes.begin(); - dirIt != includes.end(); + std::string systemIncludeDirs = makefile->GetSafeDefinition( + "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS"); + if (!systemIncludeDirs.empty()) + { + std::vector<std::string> dirs; + cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs); + for(std::vector<std::string>::const_iterator dirIt=dirs.begin(); + dirIt != dirs.end(); ++dirIt) { uniqIncludeDirs.insert(*dirIt); } + } - std::string systemIncludeDirs = makefile->GetSafeDefinition( - "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS"); - if (!systemIncludeDirs.empty()) - { - std::vector<std::string> dirs; - cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs); - for(std::vector<std::string>::const_iterator dirIt=dirs.begin(); - dirIt != dirs.end(); - ++dirIt) - { - uniqIncludeDirs.insert(*dirIt); - } - } - - systemIncludeDirs = makefile->GetSafeDefinition( - "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS"); - if (!systemIncludeDirs.empty()) - { - std::vector<std::string> dirs; - cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs); - for(std::vector<std::string>::const_iterator dirIt=dirs.begin(); - dirIt != dirs.end(); - ++dirIt) - { - uniqIncludeDirs.insert(*dirIt); - } - } - - for(std::set<std::string>::const_iterator dirIt=uniqIncludeDirs.begin(); - dirIt != uniqIncludeDirs.end(); + systemIncludeDirs = makefile->GetSafeDefinition( + "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS"); + if (!systemIncludeDirs.empty()) + { + std::vector<std::string> dirs; + cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs); + for(std::vector<std::string>::const_iterator dirIt=dirs.begin(); + dirIt != dirs.end(); ++dirIt) { - fout <<" <Add directory=\"" << dirIt->c_str() << "\" />\n"; + uniqIncludeDirs.insert(*dirIt); } + } - fout<<" </Compiler>\n"; + for(std::set<std::string>::const_iterator dirIt=uniqIncludeDirs.begin(); + dirIt != uniqIncludeDirs.end(); + ++dirIt) + { + fout <<" <Add directory=\"" << dirIt->c_str() << "\" />\n"; } - else // e.g. all and the GLOBAL and UTILITY targets + + fout<<" </Compiler>\n"; + } + else // e.g. all and the GLOBAL and UTILITY targets { fout<<" <Option working_dir=\"" << makefile->GetStartOutputDirectory() << "\" />\n" diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index be47f95..470ceca 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -840,6 +840,8 @@ bool cmFindPackageCommand //---------------------------------------------------------------------------- void cmFindPackageCommand::SetModuleVariables(const std::string& components) { + this->AddFindDefinition("CMAKE_FIND_PACKAGE_NAME", this->Name.c_str()); + // Store the list of components. std::string components_var = this->Name + "_FIND_COMPONENTS"; this->AddFindDefinition(components_var.c_str(), components.c_str()); @@ -1016,6 +1018,9 @@ bool cmFindPackageCommand::HandlePackageMode() std::string foundVar = this->Name; foundVar += "_FOUND"; + std::string notFoundMessageVar = this->Name; + notFoundMessageVar += "_NOT_FOUND_MESSAGE"; + std::string notFoundMessage; // If the directory for the config file was found, try to read the file. bool result = true; @@ -1033,6 +1038,7 @@ bool cmFindPackageCommand::HandlePackageMode() // has set Foo_FOUND to FALSE itself: this->Makefile->RemoveDefinition(foundVar.c_str()); } + this->Makefile->RemoveDefinition(notFoundMessageVar.c_str()); // Set the version variables before loading the config file. // It may override them. @@ -1051,6 +1057,8 @@ bool cmFindPackageCommand::HandlePackageMode() // we get here if the Config file has set Foo_FOUND actively to FALSE found = false; configFileSetFOUNDFalse = true; + notFoundMessage = this->Makefile->GetSafeDefinition( + notFoundMessageVar.c_str()); } } else @@ -1071,6 +1079,10 @@ bool cmFindPackageCommand::HandlePackageMode() " " << this->FileFound << "\n" "but it set " << foundVar << " to FALSE so package \"" << this->Name << "\" is considered to be NOT FOUND."; + if (!notFoundMessage.empty()) + { + e << " Reason given by package: \n" << notFoundMessage << "\n"; + } } // If there are files in ConsideredConfigs, it means that FooConfig.cmake // have been found, but they didn't have appropriate versions. diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 0885616..3f8e962 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -19,6 +19,7 @@ #include "cmGeneratorExpressionEvaluator.h" #include "cmGeneratorExpressionLexer.h" #include "cmGeneratorExpressionParser.h" +#include "cmGeneratorExpressionDAGChecker.h" //---------------------------------------------------------------------------- cmGeneratorExpression::cmGeneratorExpression( @@ -65,7 +66,9 @@ cmGeneratorExpression::~cmGeneratorExpression() //---------------------------------------------------------------------------- const char *cmCompiledGeneratorExpression::Evaluate( - cmMakefile* mf, const char* config, bool quiet) const + cmMakefile* mf, const char* config, bool quiet, + cmGeneratorTarget *target, + cmGeneratorExpressionDAGChecker *dagChecker) const { if (!this->NeedsParsing) { @@ -84,11 +87,12 @@ const char *cmCompiledGeneratorExpression::Evaluate( context.Config = config; context.Quiet = quiet; context.HadError = false; + context.Target = target; context.Backtrace = this->Backtrace; for ( ; it != end; ++it) { - this->Output += (*it)->Evaluate(&context); + this->Output += (*it)->Evaluate(&context, dagChecker); if (context.HadError) { this->Output = ""; diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index b8467c2..d37ce97 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -9,6 +9,10 @@ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more information. ============================================================================*/ + +#ifndef cmGeneratorExpression_h +#define cmGeneratorExpression_h + #include "cmStandardIncludes.h" #include <stack> @@ -16,10 +20,12 @@ #include <cmsys/RegularExpression.hxx> class cmTarget; +class cmGeneratorTarget; class cmMakefile; class cmListFileBacktrace; struct cmGeneratorExpressionEvaluator; +struct cmGeneratorExpressionDAGChecker; class cmCompiledGeneratorExpression; @@ -54,7 +60,9 @@ class cmCompiledGeneratorExpression { public: const char* Evaluate(cmMakefile* mf, const char* config, - bool quiet = false) const; + bool quiet = false, + cmGeneratorTarget *target = 0, + cmGeneratorExpressionDAGChecker *dagChecker = 0) const; /** Get set of targets found during evaluations. */ std::set<cmTarget*> const& GetTargets() const @@ -80,3 +88,5 @@ private: mutable std::set<cmTarget*> Targets; mutable std::string Output; }; + +#endif diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx new file mode 100644 index 0000000..bfb0ddf --- /dev/null +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -0,0 +1,106 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2012 Stephen Kelly <steveire@gmail.com> + + 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. +============================================================================*/ + +#include "cmGeneratorExpressionDAGChecker.h" + +#include "cmMakefile.h" + +//---------------------------------------------------------------------------- +cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( + const cmListFileBacktrace &backtrace, + const std::string &target, + const std::string &property, + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *parent) + : Parent(parent), Target(target), Property(property), + Content(content), Backtrace(backtrace) +{ + this->IsDAG = this->isDAG(); +} + +//---------------------------------------------------------------------------- +bool cmGeneratorExpressionDAGChecker::check() const +{ + return this->IsDAG; +} + +//---------------------------------------------------------------------------- +void cmGeneratorExpressionDAGChecker::reportError( + cmGeneratorExpressionContext *context, + const std::string &expr) +{ + if (this->IsDAG) + { + return; + } + + context->HadError = true; + if (context->Quiet) + { + return; + } + + const cmGeneratorExpressionDAGChecker *parent = this->Parent; + + if (parent && !parent->Parent) + { + cmOStringStream e; + e << "Error evaluating generator expression:\n" + << " " << expr << "\n" + << "Self reference on target \"" + << context->Target->GetName() << "\".\n"; + context->Makefile->GetCMakeInstance() + ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(), + parent->Backtrace); + return; + } + + { + cmOStringStream e; + e << "Error evaluating generator expression:\n" + << " " << expr << "\n" + << "Dependency loop found."; + context->Makefile->GetCMakeInstance() + ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(), + context->Backtrace); + } + + int loopStep = 1; + while (parent) + { + cmOStringStream e; + e << "Loop step " << loopStep << "\n" + << " " + << (parent->Content ? parent->Content->GetOriginalExpression() : expr) + << "\n"; + context->Makefile->GetCMakeInstance() + ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(), + parent->Backtrace); + parent = parent->Parent; + ++loopStep; + } +} + +//---------------------------------------------------------------------------- +bool cmGeneratorExpressionDAGChecker::isDAG() const +{ + const cmGeneratorExpressionDAGChecker *parent = this->Parent; + while (parent) + { + if (this->Target == parent->Target && this->Property == parent->Property) + { + return false; + } + parent = parent->Parent; + } + return true; +} diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h new file mode 100644 index 0000000..ffc84f8 --- /dev/null +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -0,0 +1,44 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2012 Stephen Kelly <steveire@gmail.com> + + 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 cmGeneratorExpressionDAGChecker_h +#define cmGeneratorExpressionDAGChecker_h + +#include "cmStandardIncludes.h" + +#include "cmGeneratorExpressionEvaluator.h" + +//---------------------------------------------------------------------------- +struct cmGeneratorExpressionDAGChecker +{ + cmGeneratorExpressionDAGChecker(const cmListFileBacktrace &backtrace, + const std::string &target, + const std::string &property, + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *parent); + + bool check() const; + + void reportError(cmGeneratorExpressionContext *context, + const std::string &expr); +private: + bool isDAG() const; + +private: + const cmGeneratorExpressionDAGChecker * const Parent; + const std::string Target; + const std::string Property; + const GeneratorExpressionContent * const Content; + const cmListFileBacktrace Backtrace; + bool IsDAG; +}; + +#endif diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 9f84ed2..22f60d4 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -13,6 +13,8 @@ #include "cmGeneratorExpressionEvaluator.h" #include "cmGeneratorExpressionParser.h" +#include "cmGeneratorExpressionDAGChecker.h" +#include "cmGeneratorExpression.h" //---------------------------------------------------------------------------- static void reportError(cmGeneratorExpressionContext *context, @@ -47,7 +49,8 @@ struct cmGeneratorExpressionNode virtual std::string Evaluate(const std::vector<std::string> ¶meters, cmGeneratorExpressionContext *context, - const GeneratorExpressionContent *content + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *dagChecker ) const = 0; }; @@ -60,7 +63,8 @@ static const struct ZeroNode : public cmGeneratorExpressionNode std::string Evaluate(const std::vector<std::string> &, cmGeneratorExpressionContext *, - const GeneratorExpressionContent *) const + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const { // Unreachable return std::string(); @@ -76,7 +80,8 @@ static const struct OneNode : public cmGeneratorExpressionNode std::string Evaluate(const std::vector<std::string> &, cmGeneratorExpressionContext *, - const GeneratorExpressionContent *) const + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const { // Unreachable return std::string(); @@ -93,7 +98,8 @@ static const struct OP ## Node : public cmGeneratorExpressionNode \ \ std::string Evaluate(const std::vector<std::string> ¶meters, \ cmGeneratorExpressionContext *context, \ - const GeneratorExpressionContent *content) const \ + const GeneratorExpressionContent *content, \ + cmGeneratorExpressionDAGChecker *) const \ { \ std::vector<std::string>::const_iterator it = parameters.begin(); \ const std::vector<std::string>::const_iterator end = parameters.end(); \ @@ -123,9 +129,11 @@ BOOLEAN_OP_NODE(orNode, OR, 0, 1) static const struct NotNode : public cmGeneratorExpressionNode { NotNode() {} + std::string Evaluate(const std::vector<std::string> ¶meters, cmGeneratorExpressionContext *context, - const GeneratorExpressionContent *content) const + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *) const { if (*parameters.begin() != "0" && *parameters.begin() != "1") { @@ -138,14 +146,80 @@ static const struct NotNode : public cmGeneratorExpressionNode } notNode; //---------------------------------------------------------------------------- +static const struct BoolNode : public cmGeneratorExpressionNode +{ + BoolNode() {} + + virtual int NumExpectedParameters() const { return 1; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0"; + } +} boolNode; + +//---------------------------------------------------------------------------- +static const struct StrEqualNode : public cmGeneratorExpressionNode +{ + StrEqualNode() {} + + virtual int NumExpectedParameters() const { return 2; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + return *parameters.begin() == parameters.at(1) ? "1" : "0"; + } +} strEqualNode; + +//---------------------------------------------------------------------------- +static const struct Angle_RNode : public cmGeneratorExpressionNode +{ + Angle_RNode() {} + + virtual int NumExpectedParameters() const { return 0; } + + std::string Evaluate(const std::vector<std::string> &, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + return ">"; + } +} angle_rNode; + +//---------------------------------------------------------------------------- +static const struct CommaNode : public cmGeneratorExpressionNode +{ + CommaNode() {} + + virtual int NumExpectedParameters() const { return 0; } + + std::string Evaluate(const std::vector<std::string> &, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + return ","; + } +} commaNode; + +//---------------------------------------------------------------------------- static const struct ConfigurationNode : public cmGeneratorExpressionNode { ConfigurationNode() {} + virtual int NumExpectedParameters() const { return 0; } std::string Evaluate(const std::vector<std::string> &, cmGeneratorExpressionContext *context, - const GeneratorExpressionContent *) const + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const { return context->Config ? context->Config : ""; } @@ -160,7 +234,8 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode std::string Evaluate(const std::vector<std::string> ¶meters, cmGeneratorExpressionContext *context, - const GeneratorExpressionContent *content) const + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *) const { if (!context->Config) { @@ -180,6 +255,61 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode } configurationTestNode; //---------------------------------------------------------------------------- +static const struct TargetPropertyNode : public cmGeneratorExpressionNode +{ + TargetPropertyNode() {} + + // This node handles errors on parameter count itself. + virtual int NumExpectedParameters() const { return -1; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *dagCheckerParent + ) const + { + if (parameters.size() != 1 && parameters.size() != 2) + { + reportError(context, content->GetOriginalExpression(), + "$<TARGET_PROPERTY:...> expression requires one or two parameters"); + return std::string(); + } + cmGeneratorTarget* target = context->Target; + std::string propertyName = *parameters.begin(); + if (parameters.size() == 2) + { + target = context->Makefile->FindGeneratorTargetToUse( + parameters.begin()->c_str()); + + if (!target) + { + cmOStringStream e; + e << "Target \"" + << target + << "\" not found."; + reportError(context, content->GetOriginalExpression(), e.str()); + } + propertyName = parameters.at(1); + } + + cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, + target->GetName(), + propertyName, + content, + dagCheckerParent); + + if (!dagChecker.check()) + { + dagChecker.reportError(context, content->GetOriginalExpression()); + return std::string(); + } + + const char *prop = target->GetProperty(propertyName.c_str()); + return prop ? prop : ""; + } +} targetPropertyNode; + +//---------------------------------------------------------------------------- template<bool linker, bool soname> struct TargetFilesystemArtifactResultCreator { @@ -293,7 +423,8 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode std::string Evaluate(const std::vector<std::string> ¶meters, cmGeneratorExpressionContext *context, - const GeneratorExpressionContent *content) const + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *) const { // Lookup the referenced target. std::string name = *parameters.begin(); @@ -392,7 +523,18 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) return &targetLinkerFileDirNode; else if (identifier == "TARGET_SONAME_FILE_DIR") return &targetSoNameFileDirNode; + else if (identifier == "STREQUAL") + return &strEqualNode; + else if (identifier == "BOOL") + return &boolNode; + else if (identifier == "ANGLE-R") + return &angle_rNode; + else if (identifier == "COMMA") + return &commaNode; + else if (identifier == "TARGET_PROPERTY") + return &targetPropertyNode; return 0; + } //---------------------------------------------------------------------------- @@ -412,7 +554,8 @@ std::string GeneratorExpressionContent::GetOriginalExpression() const //---------------------------------------------------------------------------- std::string GeneratorExpressionContent::Evaluate( - cmGeneratorExpressionContext *context) const + cmGeneratorExpressionContext *context, + cmGeneratorExpressionDAGChecker *dagChecker) const { std::string identifier; { @@ -422,7 +565,7 @@ std::string GeneratorExpressionContent::Evaluate( = this->IdentifierChildren.end(); for ( ; it != end; ++it) { - identifier += (*it)->Evaluate(context); + identifier += (*it)->Evaluate(context, dagChecker); if (context->HadError) { return std::string(); @@ -465,7 +608,7 @@ std::string GeneratorExpressionContent::Evaluate( = pit->end(); for ( ; it != end; ++it) { - result += (*it)->Evaluate(context); + result += (*it)->Evaluate(context, dagChecker); if (context->HadError) { return std::string(); @@ -491,7 +634,7 @@ std::string GeneratorExpressionContent::Evaluate( pit->end(); for ( ; it != end; ++it) { - parameter += (*it)->Evaluate(context); + parameter += (*it)->Evaluate(context, dagChecker); if (context->HadError) { return std::string(); @@ -534,7 +677,7 @@ std::string GeneratorExpressionContent::Evaluate( return std::string(); } - return node->Evaluate(parameters, context, this); + return node->Evaluate(parameters, context, this, dagChecker); } //---------------------------------------------------------------------------- diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index 5163ca0..04a2acd 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -15,6 +15,11 @@ #include <vector> #include <string> +#include "cmListFileCache.h" + +class cmTarget; +class cmGeneratorTarget; + //---------------------------------------------------------------------------- struct cmGeneratorExpressionContext { @@ -22,11 +27,13 @@ struct cmGeneratorExpressionContext std::set<cmTarget*> Targets; cmMakefile *Makefile; const char *Config; - cmTarget *Target; + cmGeneratorTarget *Target; bool Quiet; bool HadError; }; +struct cmGeneratorExpressionDAGChecker; + //---------------------------------------------------------------------------- struct cmGeneratorExpressionEvaluator { @@ -41,8 +48,8 @@ struct cmGeneratorExpressionEvaluator virtual Type GetType() const = 0; - virtual std::string Evaluate(cmGeneratorExpressionContext *context - ) const = 0; + virtual std::string Evaluate(cmGeneratorExpressionContext *context, + cmGeneratorExpressionDAGChecker *) const = 0; private: cmGeneratorExpressionEvaluator(const cmGeneratorExpressionEvaluator &); @@ -57,7 +64,8 @@ struct TextContent : public cmGeneratorExpressionEvaluator } - std::string Evaluate(cmGeneratorExpressionContext *) const + std::string Evaluate(cmGeneratorExpressionContext *, + cmGeneratorExpressionDAGChecker *) const { return std::string(this->Content, this->Length); } @@ -102,7 +110,8 @@ struct GeneratorExpressionContent : public cmGeneratorExpressionEvaluator return cmGeneratorExpressionEvaluator::Generator; } - std::string Evaluate(cmGeneratorExpressionContext *context) const; + std::string Evaluate(cmGeneratorExpressionContext *context, + cmGeneratorExpressionDAGChecker *) const; std::string GetOriginalExpression() const; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 91f16d1..d4b57f4 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -17,6 +17,8 @@ #include "cmComputeLinkInformation.h" #include "cmGlobalGenerator.h" #include "cmSourceFile.h" +#include "cmGeneratorExpression.h" +#include "cmGeneratorExpressionDAGChecker.h" #include <assert.h> @@ -289,19 +291,40 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories() { std::vector<std::string> includes; const char *prop = this->Target->GetProperty("INCLUDE_DIRECTORIES"); - if(prop) + if(!prop) { - cmSystemTools::ExpandListArgument(prop, includes); + return includes; } + const char *config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + "INCLUDE_DIRECTORIES", 0, 0); + + cmSystemTools::ExpandListArgument(ge.Parse(prop) + .Evaluate(this->Makefile, + config, + false, + this, + &dagChecker), + includes); + std::set<std::string> uniqueIncludes; std::vector<std::string> orderedAndUniqueIncludes; for(std::vector<std::string>::const_iterator li = includes.begin(); li != includes.end(); ++li) { - if(uniqueIncludes.insert(*li).second) + std::string inc = *li; + if (!cmSystemTools::IsOff(inc.c_str())) + { + cmSystemTools::ConvertToUnixSlashes(inc); + } + if(uniqueIncludes.insert(inc).second) { - orderedAndUniqueIncludes.push_back(*li); + orderedAndUniqueIncludes.push_back(inc); } } @@ -309,15 +332,30 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories() } //---------------------------------------------------------------------------- -const char *cmGeneratorTarget::GetCompileDefinitions(const char *config) +std::string cmGeneratorTarget::GetCompileDefinitions(const char *config) { - if (!config) + std::string defPropName = "COMPILE_DEFINITIONS"; + if (config) { - return this->Target->GetProperty("COMPILE_DEFINITIONS"); + defPropName += "_" + cmSystemTools::UpperCase(config); } - std::string defPropName = "COMPILE_DEFINITIONS_"; - defPropName += - cmSystemTools::UpperCase(config); - return this->Target->GetProperty(defPropName.c_str()); + const char *prop = this->Target->GetProperty(defPropName.c_str()); + + if (!prop) + { + return ""; + } + + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + defPropName, 0, 0); + return ge.Parse(prop).Evaluate(this->Makefile, + config, + false, + this, + &dagChecker); } diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 4487c11..8ea17d7 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -74,7 +74,7 @@ public: /** Get the include directories for this target. */ std::vector<std::string> GetIncludeDirectories(); - const char *GetCompileDefinitions(const char *config = 0); + std::string GetCompileDefinitions(const char *config = 0); private: void ClassifySources(); diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index ac75933..09588f9 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -21,7 +21,7 @@ #include "cmQtAutomoc.h" #include "cmSourceFile.h" #include "cmVersion.h" -#include "cmExportInstallFileGenerator.h" +#include "cmTargetExport.h" #include "cmComputeTargetDepends.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" @@ -76,12 +76,12 @@ cmGlobalGenerator::~cmGlobalGenerator() } this->ClearGeneratorTargets(); - this->ClearExportSets(); } void cmGlobalGenerator::ResolveLanguageCompiler(const std::string &lang, cmMakefile *mf, - bool optional) { + bool optional) +{ std::string langComp = "CMAKE_"; langComp += lang; langComp += "_COMPILER"; @@ -817,7 +817,7 @@ void cmGlobalGenerator::Configure() { this->FirstTimeProgress = 0.0f; this->ClearGeneratorTargets(); - this->ClearExportSets(); + this->ExportSets.clear(); // Delete any existing cmLocalGenerators unsigned int i; for (i = 0; i < this->LocalGenerators.size(); ++i) @@ -893,7 +893,7 @@ bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() << "The \"" << this->GetName() << "\" generator does not support " << "duplicate custom targets. " << "Consider using a Makefiles generator or fix the project to not " - << "use duplicat target names."; + << "use duplicate target names."; cmSystemTools::Error(e.str().c_str()); return false; } @@ -1489,52 +1489,6 @@ void cmGlobalGenerator::AddInstallComponent(const char* component) } } -void cmGlobalGenerator::AddTargetToExports(const char* exportSetName, - cmTarget* target, - cmInstallTargetGenerator* archive, - cmInstallTargetGenerator* runTime, - cmInstallTargetGenerator* library, - cmInstallTargetGenerator* framework, - cmInstallTargetGenerator* bundle, - cmInstallFilesGenerator* headers) -{ - if ((exportSetName) && (*exportSetName) && (target)) - { - cmTargetExport* te = new cmTargetExport(target, archive, runTime, library, - framework, bundle, headers); - this->ExportSets[exportSetName].push_back(te); - } -} - -//---------------------------------------------------------------------------- -void cmGlobalGenerator::ClearExportSets() -{ - for(std::map<cmStdString, std::vector<cmTargetExport*> >::iterator - setIt = this->ExportSets.begin(); - setIt != this->ExportSets.end(); ++setIt) - { - for(unsigned int i = 0; i < setIt->second.size(); ++i) - { - delete setIt->second[i]; - } - } - this->ExportSets.clear(); -} - -const std::vector<cmTargetExport*>* cmGlobalGenerator::GetExportSet( - const char* name) const -{ - std::map<cmStdString, std::vector<cmTargetExport*> >::const_iterator - exportSetIt = this->ExportSets.find(name); - if (exportSetIt != this->ExportSets.end()) - { - return &exportSetIt->second; - } - - return 0; -} - - void cmGlobalGenerator::EnableInstallTarget() { this->InstallTargetEnabled = true; diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 2f4ebc3..0aab2d6 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -18,14 +18,15 @@ #include "cmTarget.h" // For cmTargets #include "cmTargetDepend.h" // For cmTargetDependSet #include "cmSystemTools.h" // for cmSystemTools::OutputOption +#include "cmExportSetMap.h" // For cmExportSetMap #include "cmGeneratorTarget.h" + class cmake; class cmGeneratorTarget; class cmMakefile; class cmLocalGenerator; class cmExternalMakefileProjectGenerator; class cmTarget; -class cmTargetExport; class cmInstallTargetGenerator; class cmInstallFilesGenerator; @@ -128,8 +129,8 @@ public: void SetCMakeInstance(cmake *cm); ///! Get the CMake instance - cmake *GetCMakeInstance() { return this->CMakeInstance; }; - const cmake *GetCMakeInstance() const { return this->CMakeInstance; }; + cmake *GetCMakeInstance() { return this->CMakeInstance; } + const cmake *GetCMakeInstance() const { return this->CMakeInstance; } void SetConfiguredFilesPath(cmGlobalGenerator* gen); const std::vector<cmLocalGenerator *>& GetLocalGenerators() const { @@ -152,18 +153,9 @@ public: void AddInstallComponent(const char* component); const std::set<cmStdString>* GetInstallComponents() const - { return &InstallComponents; } - - ///! Add one installed target to the sets of the exports - void AddTargetToExports(const char* exportSet, cmTarget* target, - cmInstallTargetGenerator* archive, - cmInstallTargetGenerator* runTime, - cmInstallTargetGenerator* library, - cmInstallTargetGenerator* framework, - cmInstallTargetGenerator* bundle, - cmInstallFilesGenerator* publicHeaders); - ///! Get the export target set with the given name - const std::vector<cmTargetExport*>* GetExportSet(const char* name) const; + { return &this->InstallComponents; } + + cmExportSetMap& GetExportSets() {return this->ExportSets;} /** Add a file to the manifest of generated targets for a configuration. */ void AddToManifest(const char* config, std::string const& f); @@ -223,7 +215,7 @@ public: /** 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; } + { return this->TargetManifest; } /** Get the content of a directory. Directory listings are loaded from disk at most once and cached. During the generation step @@ -329,15 +321,13 @@ protected: cmLocalGenerator* CurrentLocalGenerator; // map from project name to vector of local generators in that project std::map<cmStdString, std::vector<cmLocalGenerator*> > ProjectMap; - std::map<cmLocalGenerator*, std::set<cmTarget *> > - LocalGeneratorToTargetMap; + std::map<cmLocalGenerator*, std::set<cmTarget *> > LocalGeneratorToTargetMap; // Set of named installation components requested by the project. std::set<cmStdString> InstallComponents; bool InstallTargetEnabled; // Sets of named target exports - std::map<cmStdString, std::vector<cmTargetExport*> > ExportSets; - void ClearExportSets(); + cmExportSetMap ExportSets; // Manifest of all targets that will be built for each configuration. // This is computed just before local generators generate. diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 39b0ffe..95c6807 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1647,16 +1647,12 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, // Add the export symbol definition for shared library objects. this->AppendDefines(ppDefs, exportMacro); } - this->AppendDefines - (ppDefs, this->CurrentMakefile->GetProperty("COMPILE_DEFINITIONS")); - this->AppendDefines(ppDefs, target.GetProperty("COMPILE_DEFINITIONS")); + cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target); + this->AppendDefines(ppDefs, gtgt->GetCompileDefinitions().c_str()); if(configName) { - std::string defVarName = "COMPILE_DEFINITIONS_"; - defVarName += cmSystemTools::UpperCase(configName); - this->AppendDefines - (ppDefs, this->CurrentMakefile->GetProperty(defVarName.c_str())); - this->AppendDefines(ppDefs, target.GetProperty(defVarName.c_str())); + this->AppendDefines(ppDefs, + gtgt->GetCompileDefinitions(configName).c_str()); } buildSettings->AddAttribute ("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList()); @@ -1713,10 +1709,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, // Set target-specific architectures. std::vector<std::string> archs; - { - cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target); gtgt->GetAppleArchs(configName, archs); - } + if(!archs.empty()) { // Enable ARCHS attribute. @@ -1953,7 +1947,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, BuildObjectListOrString dirs(this, this->XcodeVersion >= 30); BuildObjectListOrString fdirs(this, this->XcodeVersion >= 30); std::vector<std::string> includes; - cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target); this->CurrentLocalGenerator->GetIncludeDirectories(includes, gtgt); std::set<cmStdString> emitted; emitted.insert("/System/Library/Frameworks"); diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx index 4dd98a1..ba81849 100644 --- a/Source/cmIncludeDirectoryCommand.cxx +++ b/Source/cmIncludeDirectoryCommand.cxx @@ -55,6 +55,11 @@ bool cmIncludeDirectoryCommand return true; } +static bool StartsWithGeneratorExpression(const std::string &input) +{ + return input[0] == '$' && input[1] == '<'; +} + // do a lot of cleanup on the arguments because this is one place where folks // sometimes take the output of a program and pass it directly into this // command not thinking that a single argument could be filled with spaces @@ -105,10 +110,13 @@ void cmIncludeDirectoryCommand::AddDirectory(const char *i, cmSystemTools::ConvertToUnixSlashes(ret); if(!cmSystemTools::FileIsFullPath(ret.c_str())) { - std::string tmp = this->Makefile->GetStartDirectory(); - tmp += "/"; - tmp += ret; - ret = tmp; + if(!StartsWithGeneratorExpression(ret)) + { + std::string tmp = this->Makefile->GetStartDirectory(); + tmp += "/"; + tmp += ret; + ret = tmp; + } } } this->Makefile->AddIncludeDirectory(ret.c_str(), before); diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 4016734..dcd418b 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -17,6 +17,8 @@ #include "cmInstallTargetGenerator.h" #include "cmInstallExportGenerator.h" #include "cmInstallCommandArguments.h" +#include "cmTargetExport.h" +#include "cmExportSet.h" #include <cmsys/Glob.hxx> @@ -735,11 +737,16 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // this is not a namelink-only rule. if(!exports.GetString().empty() && !namelinkOnly) { + cmTargetExport *te = new cmTargetExport; + te->Target = ⌖ + te->ArchiveGenerator = archiveGenerator; + te->BundleGenerator = bundleGenerator; + te->FrameworkGenerator = frameworkGenerator; + te->HeaderGenerator = publicHeaderGenerator; + te->LibraryGenerator = libraryGenerator; + te->RuntimeGenerator = runtimeGenerator; this->Makefile->GetLocalGenerator()->GetGlobalGenerator() - ->AddTargetToExports(exports.GetCString(), &target, - archiveGenerator, runtimeGenerator, - libraryGenerator, frameworkGenerator, - bundleGenerator, publicHeaderGenerator); + ->GetExportSets()[exports.GetString()]->AddTargetExport(te); } } @@ -1264,7 +1271,9 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args) // Create the export install generator. cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator( - exp.GetCString(), ica.GetDestination().c_str(), + this->Makefile->GetLocalGenerator() + ->GetGlobalGenerator()->GetExportSets()[exp.GetString()], + ica.GetDestination().c_str(), ica.GetPermissions().c_str(), ica.GetConfigurations(), ica.GetComponent().c_str(), fname.c_str(), name_space.GetCString(), this->Makefile); diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 28a19d7..0a645a8 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -23,10 +23,11 @@ #include "cmInstallFilesGenerator.h" #include "cmExportInstallFileGenerator.h" +#include "cmExportSet.h" //---------------------------------------------------------------------------- cmInstallExportGenerator::cmInstallExportGenerator( - const char* name, + cmExportSet* exportSet, const char* destination, const char* file_permissions, std::vector<std::string> const& configurations, @@ -34,13 +35,14 @@ cmInstallExportGenerator::cmInstallExportGenerator( const char* filename, const char* name_space, cmMakefile* mf) :cmInstallGenerator(destination, configurations, component) - ,Name(name) + ,ExportSet(exportSet) ,FilePermissions(file_permissions) ,FileName(filename) ,Namespace(name_space) ,Makefile(mf) { this->EFGen = new cmExportInstallFileGenerator(this); + exportSet->AddInstallation(this); } //---------------------------------------------------------------------------- @@ -113,16 +115,12 @@ void cmInstallExportGenerator::ComputeTempDir() //---------------------------------------------------------------------------- void cmInstallExportGenerator::GenerateScript(std::ostream& os) { - // Get the export set requested. - ExportSet const* exportSet = - this->Makefile->GetLocalGenerator()->GetGlobalGenerator() - ->GetExportSet(this->Name.c_str()); - // Skip empty sets. - if(!exportSet) + if(ExportSet->GetTargetExports()->empty()) { cmOStringStream e; - e << "INSTALL(EXPORT) given unknown export \"" << this->Name << "\""; + e << "INSTALL(EXPORT) given unknown export \"" + << ExportSet->GetName() << "\""; cmSystemTools::Error(e.str().c_str()); return; } @@ -137,8 +135,6 @@ void cmInstallExportGenerator::GenerateScript(std::ostream& os) this->MainImportFile += this->FileName; // Generate the import file for this export set. - this->EFGen->SetName(this->Name.c_str()); - this->EFGen->SetExportSet(exportSet); this->EFGen->SetExportFile(this->MainImportFile.c_str()); this->EFGen->SetNamespace(this->Namespace.c_str()); if(this->ConfigurationTypes->empty()) diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h index 1ff6e38..ee92906 100644 --- a/Source/cmInstallExportGenerator.h +++ b/Source/cmInstallExportGenerator.h @@ -17,8 +17,7 @@ class cmExportInstallFileGenerator; class cmInstallFilesGenerator; class cmInstallTargetGenerator; -class cmTarget; -class cmTargetExport; +class cmExportSet; class cmMakefile; /** \class cmInstallExportGenerator @@ -27,24 +26,27 @@ class cmMakefile; class cmInstallExportGenerator: public cmInstallGenerator { public: - cmInstallExportGenerator(const char* name, + cmInstallExportGenerator(cmExportSet* exportSet, const char* dest, const char* file_permissions, const std::vector<std::string>& configurations, const char* component, const char* filename, const char* name_space, cmMakefile* mf); ~cmInstallExportGenerator(); -protected: - typedef std::vector<cmTargetExport*> ExportSet; + cmExportSet* GetExportSet() {return this->ExportSet;} + + const std::string& GetNamespace() const { return this->Namespace; } + +protected: virtual void GenerateScript(std::ostream& os); virtual void GenerateScriptConfigs(std::ostream& os, Indent const& indent); virtual void GenerateScriptActions(std::ostream& os, Indent const& indent); - void GenerateImportFile(ExportSet const* exportSet); - void GenerateImportFile(const char* config, ExportSet const* exportSet); + void GenerateImportFile(cmExportSet const* exportSet); + void GenerateImportFile(const char* config, cmExportSet const* exportSet); void ComputeTempDir(); - std::string Name; + cmExportSet* ExportSet; std::string FilePermissions; std::string FileName; std::string Namespace; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2b36ad0..c7995a3 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1394,6 +1394,11 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, } } + if(!target) + { + return; + } + // Load implicit include directories for this language. std::string impDirVar = "CMAKE_"; impDirVar += lang; @@ -1411,10 +1416,8 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, // Get the target-specific include directories. std::vector<std::string> includes; - if(target) - { - includes = target->GetIncludeDirectories(); - } + + includes = target->GetIncludeDirectories(); // Support putting all the in-project include directories first if // it is requested by the project. diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 51d5924..49bce38 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -157,6 +157,11 @@ public: */ void AppendDefines(std::set<std::string>& defines, const char* defines_list); + void AppendDefines(std::set<std::string>& defines, + std::string defines_list) + { + this->AppendDefines(defines, defines_list.c_str()); + } /** * Join a set of defines into a definesString with a space separator. */ diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 2ededfe..33d6e05 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -724,10 +724,6 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, flags += targetFlags; } - std::string configUpper = cmSystemTools::UpperCase(configName); - std::string defPropName = "COMPILE_DEFINITIONS_"; - defPropName += configUpper; - // Get preprocessor definitions for this directory. std::string defineFlags = this->Makefile->GetDefineFlags(); Options::Tool t = Options::Compiler; @@ -744,11 +740,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, targetOptions.Parse(flags.c_str()); targetOptions.Parse(defineFlags.c_str()); targetOptions.ParseFinish(); - targetOptions.AddDefines - (this->Makefile->GetProperty("COMPILE_DEFINITIONS")); - targetOptions.AddDefines(target.GetProperty("COMPILE_DEFINITIONS")); - targetOptions.AddDefines(this->Makefile->GetProperty(defPropName.c_str())); - targetOptions.AddDefines(target.GetProperty(defPropName.c_str())); + cmGeneratorTarget* gt = + this->GlobalGenerator->GetGeneratorTarget(&target); + targetOptions.AddDefines(gt->GetCompileDefinitions().c_str()); + targetOptions.AddDefines(gt->GetCompileDefinitions(configName).c_str()); targetOptions.SetVerboseMakefile( this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")); @@ -819,8 +814,6 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, targetOptions.OutputAdditionalOptions(fout, "\t\t\t\t", "\n"); fout << "\t\t\t\tAdditionalIncludeDirectories=\""; std::vector<std::string> includes; - cmGeneratorTarget* gt = - this->GlobalGenerator->GetGeneratorTarget(&target); this->GetIncludeDirectories(includes, gt); std::vector<std::string>::iterator i = includes.begin(); for(;i != includes.end(); ++i) @@ -849,7 +842,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, // non-debug configurations because VS still creates .idb files. fout << "\t\t\t\tProgramDataBaseFileName=\"" << this->ConvertToXMLOutputPathSingle( - target.GetDirectory(configName).c_str()) + target.GetPDBDirectory(configName).c_str()) << "/" << target.GetPDBName(configName) << "\"\n"; } @@ -1129,7 +1122,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, fout << "\t\t\t\tAdditionalLibraryDirectories=\""; this->OutputLibraryDirectories(fout, cli.GetDirectories()); fout << "\"\n"; - temp = target.GetDirectory(configName); + temp = target.GetPDBDirectory(configName); temp += "/"; temp += targetNamePDB; fout << "\t\t\t\tProgramDatabaseFile=\"" << @@ -1217,7 +1210,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, this->OutputLibraryDirectories(fout, cli.GetDirectories()); fout << "\"\n"; std::string path = this->ConvertToXMLOutputPathSingle( - target.GetDirectory(configName).c_str()); + target.GetPDBDirectory(configName).c_str()); fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/" << targetNamePDB << "\"\n"; diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index da66656..b7a454b 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -131,9 +131,14 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) outpathImp += "/"; } } + + std::string pdbOutputPath = this->Target->GetPDBDirectory(); + cmSystemTools::MakeDirectory(pdbOutputPath.c_str()); + pdbOutputPath += "/"; + std::string targetFullPath = outpath + targetName; std::string targetFullPathReal = outpath + targetNameReal; - std::string targetFullPathPDB = outpath + targetNamePDB; + std::string targetFullPathPDB = pdbOutputPath + targetNamePDB; std::string targetFullPathImport = outpathImp + targetNameImport; std::string targetOutPathPDB = this->Convert(targetFullPathPDB.c_str(), diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index d39e7fa..e7004d6 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -328,8 +328,12 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules } } + std::string pdbOutputPath = this->Target->GetPDBDirectory(); + cmSystemTools::MakeDirectory(pdbOutputPath.c_str()); + pdbOutputPath += "/"; + std::string targetFullPath = outpath + targetName; - std::string targetFullPathPDB = outpath + targetNamePDB; + std::string targetFullPathPDB = pdbOutputPath + targetNamePDB; std::string targetFullPathSO = outpath + targetNameSO; std::string targetFullPathReal = outpath + targetNameReal; std::string targetFullPathImport = outpathImp + targetNameImport; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 9560c10..5cc67e2 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -647,7 +647,7 @@ cmMakefileTargetGenerator this->Target->GetType() == cmTarget::SHARED_LIBRARY || this->Target->GetType() == cmTarget::MODULE_LIBRARY) { - targetFullPathPDB = this->Target->GetDirectory(this->ConfigName); + targetFullPathPDB = this->Target->GetPDBDirectory(this->ConfigName); targetFullPathPDB += "/"; targetFullPathPDB += this->Target->GetPDBName(this->ConfigName); } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 57997ee..612e047 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -329,10 +329,10 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const this->Target->GetType() == cmTarget::SHARED_LIBRARY || this->Target->GetType() == cmTarget::MODULE_LIBRARY) { - pdbPath = this->Target->GetDirectory(this->GetConfigName()); + pdbPath = this->Target->GetPDBDirectory(this->GetConfigName()); pdbPath += "/"; pdbPath += this->Target->GetPDBName(this->GetConfigName()); - } + } vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat( ConvertToNinjaPath(pdbPath.c_str()).c_str(), @@ -508,8 +508,6 @@ void cmNinjaTargetGenerator ::WriteObjectBuildStatement(cmSourceFile* source) { - cmNinjaDeps emptyDeps; - std::string comment; const std::string language = source->GetLanguage(); std::string rule = this->LanguageCompilerRule(language); @@ -533,11 +531,12 @@ cmNinjaTargetGenerator cmNinjaDeps orderOnlyDeps; this->GetLocalGenerator()->AppendTargetDepends(this->Target, orderOnlyDeps); + cmNinjaDeps implicitDeps; if(const char* objectDeps = source->GetProperty("OBJECT_DEPENDS")) { std::vector<std::string> depList; cmSystemTools::ExpandListArgument(objectDeps, depList); std::transform(depList.begin(), depList.end(), - std::back_inserter(orderOnlyDeps), MapToNinjaPath()); + std::back_inserter(implicitDeps), MapToNinjaPath()); } // Add order-only dependencies on custom command outputs. @@ -619,7 +618,7 @@ cmNinjaTargetGenerator rule, outputs, explicitDeps, - emptyDeps, + implicitDeps, orderOnlyDeps, vars); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 532d482..423b350 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -16,6 +16,7 @@ #include "cmLocalGenerator.h" #include "cmGlobalGenerator.h" #include "cmDocumentCompileDefinitions.h" +#include "cmDocumentGeneratorExpressions.h" #include "cmDocumentLocationUndefined.h" #include "cmListFileCache.h" #include "cmGeneratorExpression.h" @@ -56,6 +57,7 @@ struct cmTarget::OutputInfo { std::string OutDir; std::string ImpDir; + std::string PdbDir; }; //---------------------------------------------------------------------------- @@ -204,6 +206,9 @@ void cmTarget::DefineProperties(cmake *cm) "are not supported by the native build tool. " "The VS6 IDE does not support definition values with spaces " "(but NMake does).\n" + "Contents of COMPILE_DEFINITIONS may use \"generator expressions\" with " + "the syntax \"$<...>\". " + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS CM_DOCUMENT_COMPILE_DEFINITIONS_DISCLAIMER); cm->DefineProperty @@ -497,8 +502,11 @@ void cmTarget::DefineProperties(cmake *cm) "to the include_directories command." "\n" "The target property values are used by the generators to set " - "the include paths for the compiler. " - "See also the include_directories command."); + "the include paths for the compiler. " + "See also the include_directories command.\n" + "Contents of INCLUDE_DIRECTORIES may use \"generator expressions\" with " + "the syntax \"$<...>\". " + CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS); cm->DefineProperty ("INSTALL_NAME_DIR", cmProperty::TARGET, @@ -740,6 +748,22 @@ void cmTarget::DefineProperties(cmake *cm) "Use OUTPUT_NAME_<CONFIG> instead."); cm->DefineProperty + ("PDB_NAME", cmProperty::TARGET, + "Output name for MS debug symbols .pdb file.", + "Set the base name for debug symbols file created for an " + "executable or library target. " + "If not set, the logical target name is used by default. " + "\n" + "This property is not implemented by the Visual Studio 6 generator."); + + cm->DefineProperty + ("PDB_NAME_<CONFIG>", cmProperty::TARGET, + "Per-configuration name for MS debug symbols .pdb file. ", + "This is the configuration-specific version of PDB_NAME. " + "\n" + "This property is not implemented by the Visual Studio 6 generator."); + + cm->DefineProperty ("PRE_INSTALL_SCRIPT", cmProperty::TARGET, "Deprecated install support.", "The PRE_INSTALL_SCRIPT and POST_INSTALL_SCRIPT properties are the " @@ -1189,6 +1213,27 @@ void cmTarget::DefineProperties(cmake *cm) CM_TARGET_OUTDIR_CONFIG_DOC(RUNTIME)); cm->DefineProperty + ("PDB_OUTPUT_DIRECTORY", cmProperty::TARGET, + "Output directory for MS debug symbols .pdb files.", + "This property specifies the directory into which the MS debug symbols " + "will be placed. " + "This property is initialized by the value of the variable " + "CMAKE_PDB_OUTPUT_DIRECTORY if it is set when a target is created." + "\n" + "This property is not implemented by the Visual Studio 6 generator."); + cm->DefineProperty + ("PDB_OUTPUT_DIRECTORY_<CONFIG>", cmProperty::TARGET, + "Per-configuration output directory for MS debug symbols .pdb files.", + "This is a per-configuration version of PDB_OUTPUT_DIRECTORY, " + "but multi-configuration generators (VS, Xcode) do NOT append " + "a per-configuration subdirectory to the specified directory. " + "This property is initialized by the value of the variable " + "CMAKE_PDB_OUTPUT_DIRECTORY_<CONFIG> " + "if it is set when a target is created." + "\n" + "This property is not implemented by the Visual Studio 6 generator."); + + cm->DefineProperty ("ARCHIVE_OUTPUT_NAME", cmProperty::TARGET, "Output name for ARCHIVE target files.", "This property specifies the base name for archive target files. " @@ -1262,6 +1307,7 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", 0); + this->SetPropertyDefault("PDB_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("Fortran_FORMAT", 0); this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", 0); this->SetPropertyDefault("GNUtoMS", 0); @@ -1281,6 +1327,7 @@ void cmTarget::SetMakefile(cmMakefile* mf) "ARCHIVE_OUTPUT_DIRECTORY_", "LIBRARY_OUTPUT_DIRECTORY_", "RUNTIME_OUTPUT_DIRECTORY_", + "PDB_OUTPUT_DIRECTORY_", 0}; for(std::vector<std::string>::iterator ci = configNames.begin(); ci != configNames.end(); ++ci) @@ -2013,9 +2060,8 @@ bool cmTarget::NameResolvesToFramework(const std::string& libname) } //---------------------------------------------------------------------------- -bool cmTarget::AddFramework(const std::string& libname, LinkLibraryType llt) +bool cmTarget::AddFramework(const std::string& libname, LinkLibraryType) { - (void)llt; // TODO: What is this? if(this->NameResolvesToFramework(libname.c_str())) { std::string frameworkDir = libname; @@ -2295,7 +2341,7 @@ void cmTarget::Emit(const LibraryID lib, // be preserved. // This variable will keep track of the libraries that were - // emitted directory from the current node, and not from a + // emitted directly from the current node, and not from a // recursive call. This way, if we come across a library that // has already been emitted, we repeat it iff it has been // emitted here. @@ -2413,7 +2459,7 @@ void cmTarget::AppendProperty(const char* prop, const char* value, //---------------------------------------------------------------------------- void cmTarget::MaybeInvalidatePropertyCache(const char* prop) { - // Wipe wipe out maps caching information affected by this property. + // Wipe out maps caching information affected by this property. if(this->IsImported() && strncmp(prop, "IMPORTED", 8) == 0) { this->Internal->ImportInfoMap.clear(); @@ -2538,6 +2584,7 @@ cmTarget::OutputInfo const* cmTarget::GetOutputInfo(const char* config) OutputInfo info; this->ComputeOutputDir(config, false, info.OutDir); this->ComputeOutputDir(config, true, info.ImpDir); + this->ComputePDBOutputDir(config, info.PdbDir); OutputInfoMapType::value_type entry(config_upper, info); i = this->Internal->OutputInfoMap.insert(entry).first; } @@ -2563,6 +2610,17 @@ std::string cmTarget::GetDirectory(const char* config, bool implib) } //---------------------------------------------------------------------------- +std::string cmTarget::GetPDBDirectory(const char* config) +{ + if(OutputInfo const* info = this->GetOutputInfo(config)) + { + // Return the directory in which the target will be built. + return info->PdbDir; + } + return ""; +} + +//---------------------------------------------------------------------------- const char* cmTarget::GetLocation(const char* config) { if (this->IsImported()) @@ -3008,6 +3066,28 @@ std::string cmTarget::GetPDBName(const char* config) std::string base; std::string suffix; this->GetFullNameInternal(config, false, prefix, base, suffix); + + std::vector<std::string> props; + std::string configUpper = + cmSystemTools::UpperCase(config? 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->c_str())) + { + base = outName; + break; + } + } return prefix+base+".pdb"; } @@ -3392,7 +3472,7 @@ void cmTarget::GetLibraryNames(std::string& name, } // The program database file name. - pdbName = prefix+base+".pdb"; + pdbName = this->GetPDBName(config); } //---------------------------------------------------------------------------- @@ -3471,7 +3551,7 @@ void cmTarget::GetExecutableNames(std::string& name, impName = this->GetFullNameInternal(config, true); // The program database file name. - pdbName = prefix+base+".pdb"; + pdbName = this->GetPDBName(config); } //---------------------------------------------------------------------------- @@ -3550,7 +3630,7 @@ void cmTarget::GenerateTargetManifest(const char* config) } if(!pdbName.empty()) { - f = dir; + f = this->GetPDBDirectory(config); f += "/"; f += pdbName; gg->AddToManifest(config? config:"", f); @@ -3860,6 +3940,65 @@ bool cmTarget::ComputeOutputDir(const char* config, } //---------------------------------------------------------------------------- +void cmTarget::ComputePDBOutputDir(const char* config, std::string& out) +{ + // Look for a target property defining the target output directory + // based on the target type. + std::string targetTypeName = "PDB"; + const char* propertyName = 0; + std::string propertyNameStr = targetTypeName; + if(!propertyNameStr.empty()) + { + propertyNameStr += "_OUTPUT_DIRECTORY"; + propertyName = propertyNameStr.c_str(); + } + + // Check for a per-configuration output directory target property. + std::string configUpper = cmSystemTools::UpperCase(config? config : ""); + const char* configProp = 0; + std::string configPropStr = targetTypeName; + if(!configPropStr.empty()) + { + configPropStr += "_OUTPUT_DIRECTORY_"; + configPropStr += configUpper; + configProp = configPropStr.c_str(); + } + + // Select an output directory. + if(const char* config_outdir = this->GetProperty(configProp)) + { + // Use the user-specified per-configuration output directory. + out = config_outdir; + + // Skip per-configuration subdirectory. + config = 0; + } + else if(const char* outdir = this->GetProperty(propertyName)) + { + // Use the user-specified output directory. + out = outdir; + } + if(out.empty()) + { + // Default to the current output directory. + out = "."; + } + + // Convert the output path to a full path in case it is + // specified as a relative path. Treat a relative path as + // relative to the current output directory for this makefile. + out = (cmSystemTools::CollapseFullPath + (out.c_str(), this->Makefile->GetStartOutputDirectory())); + + // The generator may add the configuration's subdirectory. + if(config && *config) + { + this->Makefile->GetLocalGenerator()->GetGlobalGenerator()-> + AppendDirectoryForConfig("/", config, "", out); + } +} + +//---------------------------------------------------------------------------- bool cmTarget::UsesDefaultOutputDir(const char* config, bool implib) { std::string dir; diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 1f6bb46..558bfab 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -291,6 +291,12 @@ public: output directory is given. */ std::string GetDirectory(const char* config = 0, bool implib = false); + /** Get the directory in which this targets .pdb files will be placed. + If the configuration name is given then the generator will add its + subdirectory for that configuration. Otherwise just the canonical + pdb output directory is given. */ + std::string GetPDBDirectory(const char* config = 0); + /** Get the location of the target in the build tree for the given configuration. This location is suitable for use as the LOCATION target property. */ @@ -571,6 +577,7 @@ private: struct OutputInfo; OutputInfo const* GetOutputInfo(const char* config); bool ComputeOutputDir(const char* config, bool implib, std::string& out); + void ComputePDBOutputDir(const char* config, std::string& out); // Cache import information from properties for each configuration. struct ImportInfo; diff --git a/Source/cmTargetExport.h b/Source/cmTargetExport.h new file mode 100644 index 0000000..c9d87fb --- /dev/null +++ b/Source/cmTargetExport.h @@ -0,0 +1,39 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmTargetExport_h +#define cmTargetExport_h + +class cmTarget; +class cmInstallTargetGenerator; +class cmInstallFilesGenerator; + +/** \brief A member of an ExportSet + * + * This struct holds pointers to target and all relevant generators. + */ +class cmTargetExport +{ +public: + cmTarget* Target; ///< The target + + ///@name Generators + ///@{ + cmInstallTargetGenerator* ArchiveGenerator; + cmInstallTargetGenerator* RuntimeGenerator; + cmInstallTargetGenerator* LibraryGenerator; + cmInstallTargetGenerator* FrameworkGenerator; + cmInstallTargetGenerator* BundleGenerator; + cmInstallFilesGenerator* HeaderGenerator; + ///@} +}; + +#endif diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index dbea1c3..f42b0f6 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -108,8 +108,8 @@ bool cmTargetLinkLibrariesCommand // specification if the keyword is encountered as the first argument. this->CurrentProcessingState = ProcessingLinkLibraries; - // add libraries, nothe that there is an optional prefix - // of debug and optimized than can be used + // add libraries, note that there is an optional prefix + // of debug and optimized that can be used for(unsigned int i=1; i < args.size(); ++i) { if(args[i] == "LINK_INTERFACE_LIBRARIES") diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index fea117a..ab57a32 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1225,21 +1225,16 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( flags += " "; flags += targetFlags; } - std::string configUpper = cmSystemTools::UpperCase(configName); - std::string defPropName = "COMPILE_DEFINITIONS_"; - defPropName += configUpper; - // Get preprocessor definitions for this directory. std::string defineFlags = this->Target->GetMakefile()->GetDefineFlags(); clOptions.FixExceptionHandlingDefault(); clOptions.AddFlag("PrecompiledHeader", "NotUsing"); clOptions.Parse(flags.c_str()); clOptions.Parse(defineFlags.c_str()); - clOptions.AddDefines - (this->Makefile->GetProperty("COMPILE_DEFINITIONS")); - clOptions.AddDefines(this->Target->GetProperty("COMPILE_DEFINITIONS")); - clOptions.AddDefines(this->Makefile->GetProperty(defPropName.c_str())); - clOptions.AddDefines(this->Target->GetProperty(defPropName.c_str())); + clOptions.AddDefines( + this->GeneratorTarget->GetCompileDefinitions().c_str()); + clOptions.AddDefines(this->GeneratorTarget->GetCompileDefinitions( + configName.c_str()).c_str()); clOptions.SetVerboseMakefile( this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")); @@ -1284,9 +1279,8 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3); if(this->Target->GetType() != cmTarget::OBJECT_LIBRARY) { - // TODO: PDB for object library? this->WriteString("<ProgramDataBaseFileName>", 3); - *this->BuildFileStream << this->Target->GetDirectory(configName.c_str()) + *this->BuildFileStream << this->Target->GetPDBDirectory(configName.c_str()) << "/" << this->Target->GetPDBName(configName.c_str()) << "</ProgramDataBaseFileName>\n"; @@ -1511,9 +1505,8 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions(std::string const& config.c_str()); } - std::string dir = this->Target->GetDirectory(config.c_str()); - dir += "/"; - std::string pdb = dir; + std::string pdb = this->Target->GetPDBDirectory(config.c_str()); + pdb += "/"; pdb += targetNamePDB; std::string imLib = this->Target->GetDirectory(config.c_str(), true); imLib += "/"; |