From 8e4c7b99e1b73c641308c0177673dac33fe57df1 Mon Sep 17 00:00:00 2001 From: David Cole Date: Wed, 10 Oct 2007 11:06:15 -0400 Subject: ENH: Finish up the Framework creation code restructuring. Frameworks build and install now. More work needed on the packaging step. See Tests/Framework for example use. --- Source/cmGlobalGenerator.cxx | 22 ++++ Source/cmGlobalGenerator.h | 4 + Source/cmGlobalXCodeGenerator.cxx | 73 +++++++----- Source/cmInstallCommand.cxx | 176 +++++++++++++++------------- Source/cmInstallTargetGenerator.cxx | 14 ++- Source/cmMakefileLibraryTargetGenerator.cxx | 38 +++--- Source/cmMakefileTargetGenerator.cxx | 2 +- Source/cmOrderLinkDirectories.cxx | 35 +++--- Source/cmTarget.cxx | 110 +++++++++++++++-- Source/cmTarget.h | 21 ++++ Tests/CMakeLists.txt | 15 ++- Tests/Framework/CMakeLists.txt | 38 +++--- 12 files changed, 375 insertions(+), 173 deletions(-) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index a3b2cf3..b5323e1 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1277,6 +1277,7 @@ cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(const char* start_dir) } +//---------------------------------------------------------------------------- cmTarget* cmGlobalGenerator::FindTarget(const char* project, const char* name, bool useImportedTargets) @@ -1318,6 +1319,27 @@ cmTarget* cmGlobalGenerator::FindTarget(const char* project, return 0; } +//---------------------------------------------------------------------------- +bool cmGlobalGenerator::NameResolvesToFramework(const std::string& libname) +{ + if(cmSystemTools::IsPathToFramework(libname.c_str())) + { + return true; + } + + if(cmTarget* tgt = this->FindTarget(0, libname.c_str(), true)) + { + if(tgt->GetType() == cmTarget::SHARED_LIBRARY && + tgt->GetPropertyAsBool("FRAMEWORK")) + { + return true; + } + } + + return false; +} + +//---------------------------------------------------------------------------- inline std::string removeQuotes(const std::string& s) { if(s[0] == '\"' && s[s.size()-1] == '\"') diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index efc5fab..d88ef09 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -187,6 +187,10 @@ public: const char* name, bool useImportedTargets); + /** Determine if a name resolves to a framework on disk or a built target + that is a framework. */ + bool NameResolvesToFramework(const std::string& libname); + /** If check to see if the target is linked to by any other target in the project */ bool IsDependedOn(const char* project, cmTarget* target); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 8c60b9b..f4895d1 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -23,7 +23,6 @@ PURPOSE. See the above copyright notices for more information. #include "cmake.h" #include "cmGeneratedFileStream.h" #include "cmSourceFile.h" -#include "cmOrderLinkDirectories.h" //---------------------------------------------------------------------------- #if defined(CMAKE_BUILD_WITH_CMAKE) @@ -428,18 +427,6 @@ cmXCodeObject* cmGlobalXCodeGenerator } //---------------------------------------------------------------------------- -bool IsResource(cmSourceFile* sf) -{ - const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION"); - - bool isResource = - (sf->GetPropertyAsBool("FRAMEWORK_RESOURCE") || - (location && cmStdString(location) == "Resources")); - - return isResource; -} - -//---------------------------------------------------------------------------- cmStdString GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf) { cmStdString key(cmtarget.GetName()); @@ -449,8 +436,8 @@ cmStdString GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf) } //---------------------------------------------------------------------------- -cmXCodeObject* -cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg, +cmXCodeObject* +cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg, cmSourceFile* sf, cmTarget& cmtarget) { @@ -498,7 +485,8 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg, // Is this a resource file in this target? Add it to the resources group... // - bool isResource = IsResource(sf); + cmTarget::SourceFileFlags tsFlags = cmtarget.GetTargetSourceFileFlags(sf); + bool isResource = tsFlags.Resource; // Is this a "private" or "public" framework header file? // Set the ATTRIBUTES attribute appropriately... @@ -506,14 +494,14 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg, if(cmtarget.GetType() == cmTarget::SHARED_LIBRARY && cmtarget.GetPropertyAsBool("FRAMEWORK")) { - if(sf->GetPropertyAsBool("FRAMEWORK_PRIVATE_HEADER")) + if(tsFlags.PrivateHeader) { cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); attrs->AddObject(this->CreateString("Private")); settings->AddAttribute("ATTRIBUTES", attrs); isResource = true; } - else if(sf->GetPropertyAsBool("FRAMEWORK_PUBLIC_HEADER")) + else if(tsFlags.PublicHeader) { cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); attrs->AddObject(this->CreateString("Public")); @@ -693,6 +681,9 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, cmXCodeObject* filetype = fr->GetObject()->GetObject("lastKnownFileType"); + cmTarget::SourceFileFlags tsFlags = + cmtarget.GetTargetSourceFileFlags(*i); + if(strcmp(filetype->GetString(), "\"compiled.mach-o.objfile\"") == 0) { externalObjFiles.push_back(xsf); @@ -701,7 +692,7 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, { headerFiles.push_back(xsf); } - else if(IsResource(*i)) + else if(tsFlags.Resource) { resourceFiles.push_back(xsf); } @@ -813,8 +804,8 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, } copyFilesBuildPhase->AddAttribute("dstPath", this->CreateString(ostr.str().c_str())); - copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", - this->CreateString("0")); + copyFilesBuildPhase->AddAttribute( + "runOnlyForDeploymentPostprocessing", this->CreateString("0")); buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); copyFilesBuildPhase->AddAttribute("files", buildFiles); std::vector::iterator sfIt; @@ -1418,6 +1409,14 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, productType = "com.apple.product-type.framework"; const char* version = target.GetProperty("FRAMEWORK_VERSION"); + if(!version) + { + version = target.GetProperty("VERSION"); + } + if(!version) + { + version = "A"; + } buildSettings->AddAttribute("FRAMEWORK_VERSION", this->CreateString(version)); } @@ -1501,7 +1500,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, for(std::vector::iterator i = includes.begin(); i != includes.end(); ++i) { - if(cmSystemTools::IsPathToFramework(i->c_str())) + if(this->NameResolvesToFramework(i->c_str())) { std::string frameworkDir = *i; frameworkDir += "/../"; @@ -1927,9 +1926,22 @@ void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings, else { std::string oldValue = attr->GetString(); - cmSystemTools::ReplaceString(oldValue, "\"", ""); + + // unescape escaped quotes internal to the string: + cmSystemTools::ReplaceString(oldValue, "\\\"", "\""); + + // remove surrounding quotes, if any: + std::string::size_type len = oldValue.length(); + if(oldValue[0] == '\"' && oldValue[len-1] == '\"') + { + oldValue = oldValue.substr(1, len-2); + } + oldValue += " "; oldValue += value; + + // SetString automatically escapes internal quotes and then surrounds + // the result with quotes if necessary... attr->SetString(oldValue.c_str()); } } @@ -2098,8 +2110,8 @@ void cmGlobalXCodeGenerator { // now add the same one but append $(CONFIGURATION) to it: linkDirs += " "; - linkDirs += this->XCodeEscapePath(libDir->c_str()); - linkDirs += "/$(CONFIGURATION)"; + linkDirs += this->XCodeEscapePath( + (*libDir + "/$(CONFIGURATION)").c_str()); } linkDirs += " "; linkDirs += this->XCodeEscapePath(libDir->c_str()); @@ -2506,8 +2518,8 @@ cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( // one more pass for external depend information not handled // correctly by xcode makefileStream << "# DO NOT EDIT\n"; - makefileStream << "# This makefile makes sure all linkable targets are \n"; - makefileStream << "# up-to-date with anything they link to,avoiding a " + makefileStream << "# This makefile makes sure all linkable targets are\n"; + makefileStream << "# up-to-date with anything they link to, avoiding a " "bug in XCode 1.5\n"; for(std::vector::const_iterator ct = this->CurrentConfigurationTypes.begin(); @@ -2826,10 +2838,13 @@ cmGlobalXCodeGenerator { if(dir.find(".framework") != dir.npos) { + // Remove trailing slashes (so that the rfind does not find the one at + // the very end...!) + // + cmSystemTools::ConvertToUnixSlashes(dir); std::string::size_type pos = dir.rfind("/"); std::string framework = dir.substr(pos); - std::string newDir; - newDir = dir.substr(0, pos); + std::string newDir = dir.substr(0, pos); newDir += "/"; newDir += config; dir = newDir; diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 3fd3fef..6696629 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -175,9 +175,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) cmCAStringVector runtimeArgVector (&argHelper, "RUNTIME", &group); cmCAStringVector frameworkArgVector (&argHelper, "FRAMEWORK", &group); cmCAStringVector bundleArgVector (&argHelper, "BUNDLE", &group); - cmCAStringVector resourcesArgVector (&argHelper, "RESOURCE", &group); - cmCAStringVector publicHeaderArgVector(&argHelper, "PUBLIC_HEADER", &group); cmCAStringVector privateHeaderArgVector(&argHelper,"PRIVATE_HEADER", &group); + cmCAStringVector publicHeaderArgVector(&argHelper, "PUBLIC_HEADER", &group); + cmCAStringVector resourceArgVector (&argHelper, "RESOURCE", &group); genericArgVector.Follows(0); group.Follows(&genericArgVector); @@ -197,18 +197,18 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) cmInstallCommandArguments runtimeArgs; cmInstallCommandArguments frameworkArgs; cmInstallCommandArguments bundleArgs; - cmInstallCommandArguments resourcesArgs; - cmInstallCommandArguments publicHeaderArgs; cmInstallCommandArguments privateHeaderArgs; + cmInstallCommandArguments publicHeaderArgs; + cmInstallCommandArguments resourceArgs; archiveArgs.Parse (&archiveArgVector.GetVector(), &unknownArgs); libraryArgs.Parse (&libraryArgVector.GetVector(), &unknownArgs); runtimeArgs.Parse (&runtimeArgVector.GetVector(), &unknownArgs); frameworkArgs.Parse (&frameworkArgVector.GetVector(), &unknownArgs); bundleArgs.Parse (&bundleArgVector.GetVector(), &unknownArgs); - resourcesArgs.Parse (&resourcesArgVector.GetVector(), &unknownArgs); - publicHeaderArgs.Parse (&publicHeaderArgVector.GetVector(), &unknownArgs); privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs); + publicHeaderArgs.Parse (&publicHeaderArgVector.GetVector(), &unknownArgs); + resourceArgs.Parse (&resourceArgVector.GetVector(), &unknownArgs); if(!unknownArgs.empty()) { @@ -225,18 +225,18 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) runtimeArgs.SetGenericArguments(&genericArgs); frameworkArgs.SetGenericArguments(&genericArgs); bundleArgs.SetGenericArguments(&genericArgs); - resourcesArgs.SetGenericArguments(&genericArgs); - publicHeaderArgs.SetGenericArguments(&genericArgs); privateHeaderArgs.SetGenericArguments(&genericArgs); + publicHeaderArgs.SetGenericArguments(&genericArgs); + resourceArgs.SetGenericArguments(&genericArgs); success = success && archiveArgs.Finalize(); success = success && libraryArgs.Finalize(); success = success && runtimeArgs.Finalize(); success = success && frameworkArgs.Finalize(); success = success && bundleArgs.Finalize(); - success = success && resourcesArgs.Finalize(); - success = success && publicHeaderArgs.Finalize(); success = success && privateHeaderArgs.Finalize(); + success = success && publicHeaderArgs.Finalize(); + success = success && resourceArgs.Finalize(); if(!success) { @@ -299,9 +299,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) cmInstallTargetGenerator* runtimeGenerator = 0; cmInstallTargetGenerator* frameworkGenerator = 0; cmInstallTargetGenerator* bundleGenerator = 0; - cmInstallFilesGenerator* resourcesGenerator = 0; - cmInstallFilesGenerator* publicHeaderGenerator = 0; cmInstallFilesGenerator* privateHeaderGenerator = 0; + cmInstallFilesGenerator* publicHeaderGenerator = 0; + cmInstallFilesGenerator* resourceGenerator = 0; switch(target.GetType()) { @@ -465,84 +465,98 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) // if(target.GetProperty("ASSOCIATED_FILES"); - const char* files = target.GetProperty("PUBLIC_HEADER"); - if ((files) && (*files)) - { - std::vector relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - std::vector absFiles; - if (!this->MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) - { - return false; - } + // These well-known sets of files are installed *automatically* for FRAMEWORK + // SHARED library targets on the Mac as part of installing the FRAMEWORK. + // For other target types or on other platforms, they are not installed + // automatically and so we need to create install files generators for them. + // + bool createInstallGeneratorsForTargetFileSets = true; - // Create the files install generator. - if (!publicHeaderArgs.GetDestination().empty()) - { - publicHeaderGenerator = CreateInstallFilesGenerator(absFiles, - publicHeaderArgs, false); - } - else - { - cmOStringStream e; - e << "TARGETS given no PUBLIC_HEADER DESTINATION for header files\"" - << target.GetName() << "\"."; - this->SetError(e.str().c_str()); - return false; - } + if(cmTarget::SHARED_LIBRARY == target.GetType() && + target.GetPropertyAsBool("FRAMEWORK") && + this->Makefile->IsOn("APPLE")) + { + createInstallGeneratorsForTargetFileSets = false; } - files = target.GetProperty("PRIVATE_HEADER"); - if ((files) && (*files)) + if(createInstallGeneratorsForTargetFileSets) { - std::vector relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - std::vector absFiles; - if (!this->MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) + const char* files = target.GetProperty("PRIVATE_HEADER"); + if ((files) && (*files)) { - return false; - } + std::vector relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + std::vector absFiles; + if (!this->MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) + { + return false; + } - // Create the files install generator. - if (!privateHeaderArgs.GetDestination().empty()) - { - privateHeaderGenerator = CreateInstallFilesGenerator(absFiles, + // Create the files install generator. + if (!privateHeaderArgs.GetDestination().empty()) + { + privateHeaderGenerator = CreateInstallFilesGenerator(absFiles, privateHeaderArgs, false); + } + else + { + cmOStringStream e; + e << "INSTALL TARGETS - target " << target.GetName() << " has " + << "PRIVATE_HEADER files but no PRIVATE_HEADER DESTINATION."; + cmSystemTools::Message(e.str().c_str(), "Warning"); + } } - else - { - cmOStringStream e; - e << "TARGETS given no PRIVATE_HEADER DESTINATION for header files\"" - << target.GetName() << "\"."; - this->SetError(e.str().c_str()); - return false; - } - } - files = target.GetProperty("RESOURCE_FILES"); - if ((files) && (*files)) - { - std::vector relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - std::vector absFiles; - if (!this->MakeFilesFullPath("RESOURCE_FILES", relFiles, absFiles)) + files = target.GetProperty("PUBLIC_HEADER"); + if ((files) && (*files)) { - return false; - } + std::vector relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + std::vector absFiles; + if (!this->MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) + { + return false; + } - // Create the files install generator. - if (!privateHeaderArgs.GetDestination().empty()) - { - resourcesGenerator = CreateInstallFilesGenerator(absFiles, - resourcesArgs, false); + // Create the files install generator. + if (!publicHeaderArgs.GetDestination().empty()) + { + publicHeaderGenerator = CreateInstallFilesGenerator(absFiles, + publicHeaderArgs, false); + } + else + { + cmOStringStream e; + e << "INSTALL TARGETS - target " << target.GetName() << " has " + << "PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION."; + cmSystemTools::Message(e.str().c_str(), "Warning"); + } } - else + + files = target.GetProperty("RESOURCE"); + if ((files) && (*files)) { - cmOStringStream e; - e << "TARGETS given no RESOURCES DESTINATION for resource files\"" - << target.GetName() << "\"."; - this->SetError(e.str().c_str()); - return false; + std::vector relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + std::vector absFiles; + if (!this->MakeFilesFullPath("RESOURCE", relFiles, absFiles)) + { + return false; + } + + // Create the files install generator. + if (!resourceArgs.GetDestination().empty()) + { + resourceGenerator = CreateInstallFilesGenerator(absFiles, + resourceArgs, false); + } + else + { + cmOStringStream e; + e << "INSTALL TARGETS - target " << target.GetName() << " has " + << "RESOURCE files but no RESOURCE DESTINATION."; + cmSystemTools::Message(e.str().c_str(), "Warning"); + } } } @@ -551,9 +565,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) this->Makefile->AddInstallGenerator(runtimeGenerator); this->Makefile->AddInstallGenerator(frameworkGenerator); this->Makefile->AddInstallGenerator(bundleGenerator); - this->Makefile->AddInstallGenerator(publicHeaderGenerator); this->Makefile->AddInstallGenerator(privateHeaderGenerator); - this->Makefile->AddInstallGenerator(resourcesGenerator); + this->Makefile->AddInstallGenerator(publicHeaderGenerator); + this->Makefile->AddInstallGenerator(resourceGenerator); if (!exports.GetString().empty()) { @@ -577,11 +591,11 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) this->Makefile->GetLocalGenerator()->GetGlobalGenerator() ->AddInstallComponent(bundleArgs.GetComponent().c_str()); this->Makefile->GetLocalGenerator()->GetGlobalGenerator() - ->AddInstallComponent(resourcesArgs.GetComponent().c_str()); + ->AddInstallComponent(privateHeaderArgs.GetComponent().c_str()); this->Makefile->GetLocalGenerator()->GetGlobalGenerator() ->AddInstallComponent(publicHeaderArgs.GetComponent().c_str()); this->Makefile->GetLocalGenerator()->GetGlobalGenerator() - ->AddInstallComponent(privateHeaderArgs.GetComponent().c_str()); + ->AddInstallComponent(resourceArgs.GetComponent().c_str()); return true; } diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 347d8fe..abe9348 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -238,8 +238,18 @@ cmInstallTargetGenerator { // Compute the build tree location of the framework directory std::string from1 = fromDirConfig; - // Remove trailing slashes - cmSystemTools::ConvertToUnixSlashes(from1); + if(config && *config) + { + from1 += "/"; + from1 += targetName; + from1 += ".framework"; + } + else + { + // Remove trailing slashes... so that from1 ends with ".framework": + // + cmSystemTools::ConvertToUnixSlashes(from1); + } files.push_back(from1); type = cmTarget::INSTALL_DIRECTORY; diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 5f5cbee..a2aedd5 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -252,16 +252,12 @@ void cmMakefileLibraryTargetGenerator::CreateFrameworkLinksAndDirs( symlink2 = "Resources"; cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str()); this->Makefile->AddCMakeOutputFile((outpath + "Resources").c_str()); - // Libraries -> Versions/Current/Libraries - //symlink = "Versions/Current/Libraries"; - //symlink2 = "Libraries"; - //cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str()); - //this->Makefile->AddCMakeOutputFile((outpath + "Libraries").c_str()); // Headers -> Versions/Current/Headers symlink = "Versions/Current/Headers"; symlink2 = "Headers"; cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str()); this->Makefile->AddCMakeOutputFile((outpath + "Headers").c_str()); + // PrivateHeaders -> Versions/Current/PrivateHeaders symlink = "Versions/Current/PrivateHeaders"; symlink2 = "PrivateHeaders"; cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str()); @@ -278,12 +274,14 @@ void cmMakefileLibraryTargetGenerator::CopyFrameworkSources( const char* propertyName, const char* subdir) { - std::string fullOutput= outpath + targetName; + std::string fullOutput = outpath + targetName; cmCustomCommandLines commandLines; std::vector depends; const std::vector& sources = this->Target->GetSourceFiles(); + std::string propName(propertyName); + for(std::vector::const_iterator i = sources.begin(); i != sources.end(); ++i) { @@ -296,16 +294,20 @@ void cmMakefileLibraryTargetGenerator::CopyFrameworkSources( continue; } + cmTarget::SourceFileFlags tsFlags = + this->Target->GetTargetSourceFileFlags(sf); + // If processing public headers, skip headers also marked with the private // property. Private wins. // - if((std::string(propertyName) == "FRAMEWORK_PUBLIC_HEADER") && - sf->GetPropertyAsBool("FRAMEWORK_PRIVATE_HEADER")) + if(tsFlags.PrivateHeader && (propName == "PUBLIC_HEADER")) { continue; } - if(sf->GetPropertyAsBool(propertyName)) + if(tsFlags.PrivateHeader && (propName == "PRIVATE_HEADER") || + tsFlags.PublicHeader && (propName == "PUBLIC_HEADER") || + tsFlags.Resource && (propName == "RESOURCE")) { cmCustomCommandLine line; std::string dest = outpath + subdir + "/"; @@ -318,8 +320,7 @@ void cmMakefileLibraryTargetGenerator::CopyFrameworkSources( line.push_back(dest); commandLines.push_back(line); // make sure the target gets rebuilt if any of the headers is removed - this->GenerateExtraOutput(dest.c_str(), - fullOutput.c_str()); + this->GenerateExtraOutput(dest.c_str(), fullOutput.c_str()); } } @@ -345,12 +346,11 @@ void cmMakefileLibraryTargetGenerator::CreateFramework( const char* version = this->Target->GetProperty("FRAMEWORK_VERSION"); if(!version) { + version = this->Target->GetProperty("VERSION"); + } + if(!version) + { version = "A"; - //std::string message = - // "Warning: FRAMEWORK_VERSION property not found on "; - //message += targetName; - //message += ". Default to version A."; - //cmSystemTools::Message(message.c_str()); } // create the symbolic links and directories this->CreateFrameworkLinksAndDirs(targetName, @@ -383,13 +383,13 @@ void cmMakefileLibraryTargetGenerator::CreateFramework( false, false, false); this->CopyFrameworkSources(targetName, outpath, version, - "FRAMEWORK_PRIVATE_HEADER", "PrivateHeaders"); + "PRIVATE_HEADER", "PrivateHeaders"); this->CopyFrameworkSources(targetName, outpath, version, - "FRAMEWORK_PUBLIC_HEADER", "Headers"); + "PUBLIC_HEADER", "Headers"); this->CopyFrameworkSources(targetName, outpath, version, - "FRAMEWORK_RESOURCE", "Resources"); + "RESOURCE", "Resources"); } //---------------------------------------------------------------------------- diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 569d761..f0b2780 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1170,7 +1170,7 @@ std::string cmMakefileTargetGenerator::GetFrameworkFlags() // will already have added a -F for the framework for(i = includes.begin(); i != includes.end(); ++i) { - if(cmSystemTools::IsPathToFramework(i->c_str())) + if(this->Target->NameResolvesToFramework(i->c_str())) { std::string frameworkDir = *i; frameworkDir += "/../"; diff --git a/Source/cmOrderLinkDirectories.cxx b/Source/cmOrderLinkDirectories.cxx index 5636657..57b7470 100644 --- a/Source/cmOrderLinkDirectories.cxx +++ b/Source/cmOrderLinkDirectories.cxx @@ -466,28 +466,29 @@ bool cmOrderLinkDirectories::DetermineLibraryPathOrder() // if it is a full path to an item then separate it from the path // this only works with files and paths cmStdString& item = this->RawLinkItems[i]; + if(cmSystemTools::FileIsFullPath(item.c_str())) { - if(cmSystemTools::FileIsDirectory(item.c_str())) + if(cmSystemTools::IsPathToFramework(item.c_str())) { - if(cmSystemTools::IsPathToFramework(item.c_str())) + this->SplitFramework.find(item.c_str()); + cmStdString path = this->SplitFramework.match(1); + // Add the -F path if we have not yet done so + if(this->EmittedFrameworkPaths.insert(path).second) { - this->SplitFramework.find(item.c_str()); - cmStdString path = this->SplitFramework.match(1); - // Add the -F path if we have not yet done so - if(this->EmittedFrameworkPaths.insert(path).second) - { - std::string fpath = "-F"; - fpath += cmSystemTools::ConvertToOutputPath(path.c_str()); - this->LinkItems.push_back(fpath); - } - // now add the -framework option - std::string frame = "-framework "; - frame += this->SplitFramework.match(2); - this->LinkItems.push_back(frame); - framework = true; + std::string fpath = "-F"; + fpath += cmSystemTools::ConvertToOutputPath(path.c_str()); + this->LinkItems.push_back(fpath); } - else + // now add the -framework option + std::string frame = "-framework "; + frame += this->SplitFramework.match(2); + this->LinkItems.push_back(frame); + framework = true; + } + if(cmSystemTools::FileIsDirectory(item.c_str())) + { + if(!framework) { // A full path to a directory was found as a link item // warn user diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 0a2cda4..ba73615 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -688,6 +688,83 @@ cmSourceFile* cmTarget::AddSource(const char* s) } //---------------------------------------------------------------------------- +struct cmTarget::SourceFileFlags +cmTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) +{ + struct SourceFileFlags flags; + const char* files; + std::vector::iterator it; + + flags.PrivateHeader = false; + flags.PublicHeader = false; + flags.Resource = false; + + files = this->GetProperty("PRIVATE_HEADER"); + if ((files) && (*files)) + { + std::vector relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(it = relFiles.begin(); it != relFiles.end(); ++it) + { + if(sf == this->GetMakefile()->GetSource(it->c_str())) + { + flags.PrivateHeader = true; + break; + } + } + } + + // Only consider marking it as a public header if it is *NOT* already marked + // as a private header: + // + if(!flags.PrivateHeader) + { + files = this->GetProperty("PUBLIC_HEADER"); + if ((files) && (*files)) + { + std::vector relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(it = relFiles.begin(); it != relFiles.end(); ++it) + { + if(sf == this->GetMakefile()->GetSource(it->c_str())) + { + flags.PublicHeader = true; + break; + } + } + } + } + + const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION"); + if(location && cmStdString(location) == "Resources") + { + flags.Resource = true; + } + + // Don't bother with the loop if it's already marked as a resource: + // + if(!flags.Resource) + { + files = this->GetProperty("RESOURCE"); + if ((files) && (*files)) + { + std::vector relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(it = relFiles.begin(); it != relFiles.end(); ++it) + { + if(sf == this->GetMakefile()->GetSource(it->c_str())) + { + flags.Resource = true; + break; + } + } + } + } + + return flags; +} + +//---------------------------------------------------------------------------- void cmTarget::MergeLinkLibraries( cmMakefile& mf, const char *selfname, const LinkLibraryVectorType& libs ) @@ -816,10 +893,17 @@ void cmTarget::AddLinkLibrary(const std::string& lib, } //---------------------------------------------------------------------------- +bool cmTarget::NameResolvesToFramework(const std::string& libname) +{ + return this->GetMakefile()->GetLocalGenerator()->GetGlobalGenerator()-> + NameResolvesToFramework(libname); +} + +//---------------------------------------------------------------------------- bool cmTarget::AddFramework(const std::string& libname, LinkLibraryType llt) { (void)llt; // TODO: What is this? - if(cmSystemTools::IsPathToFramework(libname.c_str())) + if(this->NameResolvesToFramework(libname.c_str())) { std::string frameworkDir = libname; frameworkDir += "/../"; @@ -1239,7 +1323,8 @@ const char* cmTarget::NormalGetDirectory(const char* config, bool implib) { if(config && *config) { - this->Directory = this->GetOutputDir(implib); + // Do not create the directory when config is given: + this->Directory = this->GetAndCreateOutputDir(implib, false); // Add the configuration's subdirectory. this->Makefile->GetLocalGenerator()->GetGlobalGenerator()-> AppendDirectoryForConfig("/", config, "", this->Directory); @@ -2199,7 +2284,7 @@ std::string cmTarget::GetInstallNameDirForInstallTree(const char*) } //---------------------------------------------------------------------------- -const char* cmTarget::GetOutputDir(bool implib) +const char* cmTarget::GetAndCreateOutputDir(bool implib, bool create) { // The implib option is only allowed for shared libraries, module // libraries, and executables. @@ -2332,18 +2417,27 @@ const char* cmTarget::GetOutputDir(bool implib) } #endif - // Make sure the output path exists on disk. - if(!cmSystemTools::MakeDirectory(out.c_str())) + // Optionally make sure the output path exists on disk. + if(create) { - cmSystemTools::Error("Error failed to create output directory:", - out.c_str()); + if(!cmSystemTools::MakeDirectory(out.c_str())) + { + cmSystemTools::Error("Error failed to create output directory: ", + out.c_str()); + } } - } + } return out.c_str(); } //---------------------------------------------------------------------------- +const char* cmTarget::GetOutputDir(bool implib) +{ + return this->GetAndCreateOutputDir(implib, true); +} + +//---------------------------------------------------------------------------- const char* cmTarget::GetExportMacro() { // Define the symbol for targets that export symbols. diff --git a/Source/cmTarget.h b/Source/cmTarget.h index be0ed65..44e0a05 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -84,6 +84,23 @@ public: void AddSourceFile(cmSourceFile* sf) { this->SourceFiles.push_back(sf); } /** + * Flags for a given source file as used in this target. Typically assigned + * via SET_TARGET_PROPERTIES when the property is a list of source files. + */ + struct SourceFileFlags + { + bool PrivateHeader; // source is in "PRIVATE_HEADER" target property + bool PublicHeader; // source is in "PUBLIC_HEADER" target property + bool Resource; // source is in "RESOURCE" target property *or* + // source has MACOSX_PACKAGE_LOCATION=="Resources" + }; + + /** + * Get the flags for a given source file as used in this target + */ + struct SourceFileFlags GetTargetSourceFileFlags(const cmSourceFile* sf); + + /** * Add sources to the target. */ void AddSources(std::vector const& srcs); @@ -109,6 +126,7 @@ public: void ClearDependencyInformation(cmMakefile& mf, const char* target); // Check to see if a library is a framework and treat it different on Mac + bool NameResolvesToFramework(const std::string& libname); bool AddFramework(const std::string& lib, LinkLibraryType llt); void AddLinkLibrary(cmMakefile& mf, const char *target, const char* lib, @@ -360,6 +378,9 @@ private: void SetPropertyDefault(const char* property, const char* default_value); // Get the full path to the target output directory. + const char* GetAndCreateOutputDir(bool implib, bool create); + + // Get the full path to the target output directory. const char* GetOutputDir(bool implib); const char* ImportedGetLocation(const char* config); diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 930ac25..728f906 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -45,7 +45,6 @@ IF(BUILD_TESTING) ADD_TEST_MACRO(LoadCommand LoadedCommand) ADD_TEST_MACRO(LinkLine LinkLine) ADD_TEST_MACRO(MacroTest miniMacroTest) - ADD_TEST_MACRO(Framework bar) ADD_TEST_MACRO(Properties Properties) ADD_TEST_MACRO(Assembler HelloAsm) ADD_TEST_MACRO(SourceGroups SourceGroups) @@ -64,8 +63,20 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=CVS -P ${CMake_SOURCE_DIR}/Utilities/Rel ENDIF(COMMAND SET_TESTS_PROPERTIES AND COMMAND GET_TEST_PROPERTY) ENDIF(CMAKE_BUILD_NIGHTLY_WINDOWS_TEST) - + # add tests with more complex invocations + ADD_TEST(Framework ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/Framework" + "${CMake_BINARY_DIR}/Tests/Framework" + --build-two-config + --build-generator ${CMAKE_TEST_GENERATOR} + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --build-project Framework + --build-options + "-DCMAKE_INSTALL_PREFIX:PATH=${CMake_BINARY_DIR}/Tests/Framework/Install" + --test-command bar) + ADD_TEST(TargetName ${CMAKE_CTEST_COMMAND} --build-and-test "${CMake_SOURCE_DIR}/Tests/TargetName" diff --git a/Tests/Framework/CMakeLists.txt b/Tests/Framework/CMakeLists.txt index 57028d7..4f42b97 100644 --- a/Tests/Framework/CMakeLists.txt +++ b/Tests/Framework/CMakeLists.txt @@ -10,26 +10,34 @@ add_library(foo SHARED fooBoth.h test.lua ) + +set(foo_ver ver4) + set_target_properties(foo PROPERTIES FRAMEWORK TRUE - FRAMEWORK_VERSION ver3 -) -# fooNeither.h is marked neither public nor private... -# fooBoth.h is marked both public and private... (private wins...) -set_source_files_properties(foo.h foo2.h fooPublic.h fooBoth.h PROPERTIES - FRAMEWORK_PUBLIC_HEADER TRUE -) -set_source_files_properties(fooPrivate.h fooBoth.h PROPERTIES - FRAMEWORK_PRIVATE_HEADER TRUE -) -set_source_files_properties(test.lua PROPERTIES - FRAMEWORK_RESOURCE TRUE + FRAMEWORK_VERSION ${foo_ver} + PRIVATE_HEADER "fooPrivate.h;fooBoth.h" + PUBLIC_HEADER "foo.h;foo2.h;fooPublic.h;fooBoth.h" + RESOURCE "test.lua" ) +# fooBoth.h is listed as both public and private... (private wins...) +# fooNeither.h is listed as neither public nor private... + add_executable(bar bar.cxx) target_link_libraries(bar foo) install(TARGETS foo bar - RUNTIME DESTINATION /Applications/CMakeTestsFramework/bin - FRAMEWORK DESTINATION /Library/Frameworks + RUNTIME DESTINATION Applications/CMakeTestsFramework/bin + FRAMEWORK DESTINATION Library/Frameworks + + # These are ignored on the Mac... and things are automatically placed in + # their appropriate Framework sub-folder at build time. (And then the built + # framework is copied recursively when it is installed.) + PRIVATE_HEADER DESTINATION share/foo-${foo_ver}/PrivateHeaders + PUBLIC_HEADER DESTINATION include/foo-${foo_ver} + RESOURCE DESTINATION share/foo-${foo_ver}/Resources + # But they are required to be present so that installing a framework on other + # other platforms will install the pieces of the framework without having to + # duplicate install rules for the pieces of the framework. ) # Make a static library and apply the framework properties to it to verify @@ -53,3 +61,5 @@ set_target_properties(fooStatic PROPERTIES ) add_executable(barStatic bar.cxx) target_link_libraries(barStatic fooStatic) + +include(CPack) -- cgit v0.12