From 9ed42663068bc8f5bc2510a2fb19b574c06f3a1f Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 18 Feb 2008 16:38:34 -0500 Subject: [PATCH] ENH: Cleanup impl of PUBLIC_HEADER, PRIVATE_HEADER, and RESOURCE properties --- Source/cmGlobalXCodeGenerator.cxx | 16 +- Source/cmLocalUnixMakefileGenerator3.cxx | 6 +- .../cmMakefileExecutableTargetGenerator.cxx | 50 +++-- Source/cmMakefileExecutableTargetGenerator.h | 4 +- Source/cmMakefileLibraryTargetGenerator.cxx | 145 +++----------- Source/cmMakefileLibraryTargetGenerator.h | 13 +- Source/cmMakefileTargetGenerator.cxx | 56 +++--- Source/cmMakefileTargetGenerator.h | 18 +- Source/cmMakefileUtilityTargetGenerator.cxx | 4 +- Source/cmMakefileUtilityTargetGenerator.h | 2 +- Source/cmSourceFile.cxx | 19 +- Source/cmTarget.cxx | 177 +++++++++++++----- Source/cmTarget.h | 37 +++- 13 files changed, 293 insertions(+), 254 deletions(-) diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index de62e8f86..32323e58c 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -493,21 +493,21 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg, // Is this a resource file in this target? Add it to the resources group... // cmTarget::SourceFileFlags tsFlags = cmtarget.GetTargetSourceFileFlags(sf); - bool isResource = tsFlags.Resource; + bool isResource = (tsFlags.Type == cmTarget::SourceFileTypeResource); // Is this a "private" or "public" framework header file? // Set the ATTRIBUTES attribute appropriately... // if(cmtarget.IsFrameworkOnApple()) { - if(tsFlags.PrivateHeader) + if(tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) { cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); attrs->AddObject(this->CreateString("Private")); settings->AddAttribute("ATTRIBUTES", attrs); isResource = true; } - else if(tsFlags.PublicHeader) + else if(tsFlags.Type == cmTarget::SourceFileTypePublicHeader) { cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); attrs->AddObject(this->CreateString("Public")); @@ -698,7 +698,7 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, { headerFiles.push_back(xsf); } - else if(tsFlags.Resource) + else if(tsFlags.Type == cmTarget::SourceFileTypeResource) { resourceFiles.push_back(xsf); } @@ -785,12 +785,12 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, for(std::vector::const_iterator i = classes.begin(); i != classes.end(); ++i) { - const char* contentLoc = (*i)->GetProperty("MACOSX_PACKAGE_LOCATION"); - if ( !contentLoc || cmStdString(contentLoc) == "Resources" ) + cmTarget::SourceFileFlags tsFlags = + cmtarget.GetTargetSourceFileFlags(*i); + if(tsFlags.Type == cmTarget::SourceFileTypeMacContent) { - continue; + bundleFiles[tsFlags.MacFolder].push_back(*i); } - bundleFiles[contentLoc].push_back(*i); } mapOfVectorOfSourceFiles::iterator mit; for ( mit = bundleFiles.begin(); mit != bundleFiles.end(); ++ mit ) diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index dda95740a..396dd75cd 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -128,8 +128,8 @@ void cmLocalUnixMakefileGenerator3::Generate() std::string empty; for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t) { - cmMakefileTargetGenerator *tg = - cmMakefileTargetGenerator::New(this, t->first, &(t->second)); + cmMakefileTargetGenerator *tg = + cmMakefileTargetGenerator::New(&(t->second)); if (tg) { this->TargetGenerators.push_back(tg); @@ -168,7 +168,7 @@ unsigned long cmLocalUnixMakefileGenerator3 this->TargetGenerators.begin(); mtgIter != this->TargetGenerators.end(); ++mtgIter) { - if (!strcmp(name,(*mtgIter)->GetTargetName())) + if (!strcmp(name,(*mtgIter)->GetTarget()->GetName())) { return (*mtgIter)->GetNumberOfProgressActions(); } diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index d13895aea..c1c3b6349 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -25,9 +25,22 @@ #include "cmake.h" //---------------------------------------------------------------------------- -cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator() +cmMakefileExecutableTargetGenerator +::cmMakefileExecutableTargetGenerator(cmTarget* target): + cmMakefileTargetGenerator(target) { this->CustomCommandDriver = OnDepends; + this->Target->GetExecutableNames( + this->TargetNameOut, this->TargetNameReal, this->TargetNameImport, + this->TargetNamePDB, this->LocalGenerator->ConfigurationName.c_str()); + + if(this->Target->IsAppBundleOnApple()) + { + this->MacContentDirectory = this->Target->GetDirectory(); + this->MacContentDirectory += "/"; + this->MacContentDirectory += this->TargetNameOut; + this->MacContentDirectory += ".app/Contents/"; + } } //---------------------------------------------------------------------------- @@ -117,21 +130,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) outpath += "/"; if(this->Target->IsAppBundleOnApple()) { - // Compute bundle directory names. - std::string macdir = outpath; - macdir += targetName; - macdir += ".app/Contents/"; - outpath = macdir; - outpath += "MacOS"; - cmSystemTools::MakeDirectory(outpath.c_str()); - outpath += "/"; - - // Configure the Info.plist file. Note that it needs the executable name - // to be set. - std::string plist = macdir + "Info.plist"; - this->LocalGenerator->GenerateAppleInfoPList(this->Target, - targetName.c_str(), - plist.c_str()); + this->CreateAppBundle(targetName, outpath); } std::string outpathImp; if(relink) @@ -469,3 +468,22 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) exeCleanFiles.begin(), exeCleanFiles.end()); } + +//---------------------------------------------------------------------------- +void +cmMakefileExecutableTargetGenerator::CreateAppBundle(std::string& targetName, + std::string& outpath) +{ + // Compute bundle directory names. + outpath = this->MacContentDirectory; + outpath += "MacOS"; + cmSystemTools::MakeDirectory(outpath.c_str()); + outpath += "/"; + + // Configure the Info.plist file. Note that it needs the executable name + // to be set. + std::string plist = this->MacContentDirectory + "Info.plist"; + this->LocalGenerator->GenerateAppleInfoPList(this->Target, + targetName.c_str(), + plist.c_str()); +} diff --git a/Source/cmMakefileExecutableTargetGenerator.h b/Source/cmMakefileExecutableTargetGenerator.h index 269fd5f6a..3111c5c05 100644 --- a/Source/cmMakefileExecutableTargetGenerator.h +++ b/Source/cmMakefileExecutableTargetGenerator.h @@ -22,7 +22,7 @@ class cmMakefileExecutableTargetGenerator: public cmMakefileTargetGenerator { public: - cmMakefileExecutableTargetGenerator(); + cmMakefileExecutableTargetGenerator(cmTarget* target); /* the main entry point for this class. Writes the Makefiles associated with this target */ @@ -30,7 +30,7 @@ public: protected: virtual void WriteExecutableRule(bool relink); - + void CreateAppBundle(std::string& targetName, std::string& outpath); }; #endif diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index f6115622b..bb68d3671 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -27,9 +27,35 @@ #include // auto_ptr //---------------------------------------------------------------------------- -cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator() +cmMakefileLibraryTargetGenerator +::cmMakefileLibraryTargetGenerator(cmTarget* target): + cmMakefileTargetGenerator(target) { this->CustomCommandDriver = OnDepends; + this->Target->GetLibraryNames( + this->TargetNameOut, this->TargetNameSO, this->TargetNameReal, + this->TargetNameImport, this->TargetNamePDB, + this->LocalGenerator->ConfigurationName.c_str()); + + if(this->Target->IsFrameworkOnApple()) + { + if(const char* fversion = this->Target->GetProperty("FRAMEWORK_VERSION")) + { + this->FrameworkVersion = fversion; + } + else if(const char* tversion = this->Target->GetProperty("VERSION")) + { + this->FrameworkVersion = tversion; + } + else + { + this->FrameworkVersion = "A"; + } + this->MacContentDirectory = this->Target->GetDirectory(); + this->MacContentDirectory += "/Versions/"; + this->MacContentDirectory += this->FrameworkVersion; + this->MacContentDirectory += "/"; + } } //---------------------------------------------------------------------------- @@ -218,10 +244,9 @@ void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink) } //---------------------------------------------------------------------------- -void cmMakefileLibraryTargetGenerator::CreateFrameworkLinksAndDirs( +void cmMakefileLibraryTargetGenerator::CreateFramework( std::string& targetName, - std::string& outpath, - const char* version) + std::string& outpath) { std::string symlink; std::string symlink2; @@ -233,7 +258,7 @@ void cmMakefileLibraryTargetGenerator::CreateFrameworkLinksAndDirs( // cd foo.framework to setup symlinks with relative paths cmSystemTools::ChangeDirectory((outpath+"Versions").c_str()); // Current -> version - symlink = version; + symlink = this->FrameworkVersion; symlink2 = "Current"; cmSystemTools::RemoveFile("Current"); cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str()); @@ -265,116 +290,6 @@ void cmMakefileLibraryTargetGenerator::CreateFrameworkLinksAndDirs( cmSystemTools::ChangeDirectory(cwd.c_str()); } -//---------------------------------------------------------------------------- -void cmMakefileLibraryTargetGenerator::CopyFrameworkSources( - std::string& targetName, - std::string& outpath, - const char* /*version*/ , - const char* propertyName, - const char* subdir) -{ - 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) - { - cmSourceFile* sf = *i; - - if(!sf) - { - cmSystemTools::Error( - "could not find framework source file", ""); - continue; - } - - cmTarget::SourceFileFlags tsFlags = - this->Target->GetTargetSourceFileFlags(sf); - - // If processing public headers, skip headers also marked with the private - // property. Private wins. - // - if(tsFlags.PrivateHeader && (propName == "PUBLIC_HEADER")) - { - continue; - } - - if(tsFlags.PrivateHeader && (propName == "PRIVATE_HEADER") || - tsFlags.PublicHeader && (propName == "PUBLIC_HEADER") || - tsFlags.Resource && (propName == "RESOURCE")) - { - cmCustomCommandLine line; - std::string dest = outpath + subdir + "/"; - dest += cmSystemTools::GetFilenameName(sf->GetFullPath()); - line.push_back("$(CMAKE_COMMAND)"); - line.push_back("-E"); - line.push_back("copy_if_different"); - line.push_back(sf->GetFullPath()); - depends.push_back(sf->GetFullPath()); - 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()); - } - } - - // add a set of prebuild commands to run on the target - if(!commandLines.empty()) - { - this->Makefile-> - AddCustomCommandToTarget(this->Target->GetName(), - depends, - commandLines, - cmTarget::PRE_BUILD, - "copy files", - this->Makefile->GetCurrentOutputDirectory()); - } -} - -//---------------------------------------------------------------------------- -void cmMakefileLibraryTargetGenerator::CreateFramework( - std::string& targetName, - std::string& outpath) -{ - std::string macdir = outpath; - const char* version = this->Target->GetProperty("FRAMEWORK_VERSION"); - if(!version) - { - version = this->Target->GetProperty("VERSION"); - } - if(!version) - { - version = "A"; - } - // create the symbolic links and directories - this->CreateFrameworkLinksAndDirs(targetName, - outpath, - version); - macdir += "Versions/"; - macdir += version; - macdir += "/"; - outpath += "Versions/"; - outpath += version; - outpath += "/"; - - //cmSystemTools::MakeDirectory((macdir + "Libraries").c_str()); - cmSystemTools::MakeDirectory((macdir + "Headers").c_str()); - - this->CopyFrameworkSources(targetName, outpath, version, - "PRIVATE_HEADER", "PrivateHeaders"); - - this->CopyFrameworkSources(targetName, outpath, version, - "PUBLIC_HEADER", "Headers"); - - this->CopyFrameworkSources(targetName, outpath, version, - "RESOURCE", "Resources"); -} - //---------------------------------------------------------------------------- void cmMakefileLibraryTargetGenerator::WriteLibraryRules (const char* linkRuleVar, const char* extraFlags, bool relink) diff --git a/Source/cmMakefileLibraryTargetGenerator.h b/Source/cmMakefileLibraryTargetGenerator.h index 22741af83..a1a4bf79d 100644 --- a/Source/cmMakefileLibraryTargetGenerator.h +++ b/Source/cmMakefileLibraryTargetGenerator.h @@ -23,7 +23,7 @@ class cmMakefileLibraryTargetGenerator: public cmMakefileTargetGenerator { public: - cmMakefileLibraryTargetGenerator(); + cmMakefileLibraryTargetGenerator(cmTarget* target); /* the main entry point for this class. Writes the Makefiles associated with this target */ @@ -39,14 +39,9 @@ protected: void WriteFrameworkRules(bool relink); void CreateFramework(std::string& targetName, std::string& outpath); - void CreateFrameworkLinksAndDirs(std::string& targetName, - std::string& outpath, - const char* version); - void CopyFrameworkSources(std::string& targetName, - std::string& outpath, - const char* version, - const char* propertyName, - const char* subdir); + + // Store the computd framework version for OS X Frameworks. + std::string FrameworkVersion; }; #endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 38868637b..135b199e2 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -30,45 +30,45 @@ #include "cmMakefileUtilityTargetGenerator.h" -cmMakefileTargetGenerator::cmMakefileTargetGenerator() +cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmTarget* target) { this->BuildFileStream = 0; this->InfoFileStream = 0; this->FlagFileStream = 0; this->CustomCommandDriver = OnBuild; this->FortranModuleDirectoryComputed = false; + this->Target = target; + this->Makefile = this->Target->GetMakefile(); + this->LocalGenerator = + static_cast( + this->Makefile->GetLocalGenerator()); + this->GlobalGenerator = + static_cast( + this->LocalGenerator->GetGlobalGenerator()); } cmMakefileTargetGenerator * -cmMakefileTargetGenerator::New(cmLocalUnixMakefileGenerator3 *lg, - cmStdString tgtName, cmTarget *tgt) +cmMakefileTargetGenerator::New(cmTarget *tgt) { cmMakefileTargetGenerator *result = 0; switch (tgt->GetType()) { case cmTarget::EXECUTABLE: - result = new cmMakefileExecutableTargetGenerator; + result = new cmMakefileExecutableTargetGenerator(tgt); break; case cmTarget::STATIC_LIBRARY: case cmTarget::SHARED_LIBRARY: case cmTarget::MODULE_LIBRARY: - result = new cmMakefileLibraryTargetGenerator; + result = new cmMakefileLibraryTargetGenerator(tgt); break; case cmTarget::UTILITY: - result = new cmMakefileUtilityTargetGenerator; + result = new cmMakefileUtilityTargetGenerator(tgt); break; default: return result; // break; /* unreachable */ } - - result->TargetName = tgtName; - result->Target = tgt; - result->LocalGenerator = lg; - result->GlobalGenerator = - static_cast(lg->GetGlobalGenerator()); - result->Makefile = lg->GetMakefile(); return result; } @@ -134,6 +134,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() for(std::vector::const_iterator source = sources.begin(); source != sources.end(); ++source) { + cmTarget::SourceFileFlags tsFlags = + this->Target->GetTargetSourceFileFlags(*source); if(cmCustomCommand* cc = (*source)->GetCustomCommand()) { this->GenerateCustomRuleFile(*cc); @@ -150,10 +152,9 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() } } } - else if(const char* pkgloc = - (*source)->GetProperty("MACOSX_PACKAGE_LOCATION")) + else if(tsFlags.Type != cmTarget::SourceFileTypeNormal) { - this->WriteMacOSXContentRules(*(*source), pkgloc); + this->WriteMacOSXContentRules(*(*source), tsFlags.MacFolder); } else if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY")) { @@ -322,21 +323,14 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() void cmMakefileTargetGenerator::WriteMacOSXContentRules(cmSourceFile& source, const char* pkgloc) { - // Skip OS X bundle content when not building a bundle. - if(!this->Target->IsAppBundleOnApple()) { return; } + // Skip OS X content when not building a Framework or Bundle. + if(this->MacContentDirectory.empty()) + { + return; + } - // Create the directory in which the content is to be placed. - std::string targetName; - std::string targetNameReal; - std::string targetNameImport; - std::string targetNamePDB; - this->Target->GetExecutableNames - (targetName, targetNameReal, targetNameImport, targetNamePDB, - this->LocalGenerator->ConfigurationName.c_str()); - std::string macdir = this->Target->GetDirectory(); - macdir += "/"; - macdir += targetName; - macdir += ".app/Contents/"; + // Construct the full path to the content subdirectory. + std::string macdir = this->MacContentDirectory; macdir += pkgloc; cmSystemTools::MakeDirectory(macdir.c_str()); @@ -355,7 +349,7 @@ void cmMakefileTargetGenerator::WriteMacOSXContentRules(cmSourceFile& source, std::vector depends; std::vector commands; depends.push_back(input); - std::string copyEcho = "Copying Bundle content "; + std::string copyEcho = "Copying OS X content "; copyEcho += output; this->LocalGenerator->AppendEcho(commands, copyEcho.c_str(), cmLocalUnixMakefileGenerator3::EchoBuild); diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 44f57c7c9..34a736a45 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -37,13 +37,11 @@ class cmMakefileTargetGenerator { public: // constructor to set the ivars - cmMakefileTargetGenerator(); + cmMakefileTargetGenerator(cmTarget* target); virtual ~cmMakefileTargetGenerator() {}; // construct using this factory call - static cmMakefileTargetGenerator *New(cmLocalUnixMakefileGenerator3 *lg, - cmStdString tgtName, - cmTarget *tgt); + static cmMakefileTargetGenerator *New(cmTarget *tgt); /* the main entry point for this class. Writes the Makefiles associated with this target */ @@ -58,7 +56,6 @@ public: virtual unsigned long GetNumberOfProgressActions() { return this->NumberOfProgressActions;} - const char *GetTargetName() { return this->TargetName.c_str(); } cmTarget* GetTarget() { return this->Target;} protected: @@ -142,7 +139,6 @@ protected: virtual void CloseFileStreams(); void RemoveForbiddenFlags(const char* flagVar, const char* linkLang, std::string& linkFlags); - cmStdString TargetName; cmTarget *Target; cmLocalUnixMakefileGenerator3 *LocalGenerator; cmGlobalUnixMakefileGenerator3 *GlobalGenerator; @@ -191,6 +187,16 @@ protected: typedef std::map MultipleOutputPairsType; MultipleOutputPairsType MultipleOutputPairs; + // Target name info. + std::string TargetNameOut; + std::string TargetNameSO; + std::string TargetNameReal; + std::string TargetNameImport; + std::string TargetNamePDB; + + // Mac OS X content info. + std::string MacContentDirectory; + // Target-wide Fortran module output directory. bool FortranModuleDirectoryComputed; std::string FortranModuleDirectory; diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx index 90650f9c5..da9ca0dce 100644 --- a/Source/cmMakefileUtilityTargetGenerator.cxx +++ b/Source/cmMakefileUtilityTargetGenerator.cxx @@ -24,7 +24,9 @@ #include "cmTarget.h" //---------------------------------------------------------------------------- -cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator() +cmMakefileUtilityTargetGenerator +::cmMakefileUtilityTargetGenerator(cmTarget* target): + cmMakefileTargetGenerator(target) { this->CustomCommandDriver = OnUtility; } diff --git a/Source/cmMakefileUtilityTargetGenerator.h b/Source/cmMakefileUtilityTargetGenerator.h index 17572a89c..519a4d005 100644 --- a/Source/cmMakefileUtilityTargetGenerator.h +++ b/Source/cmMakefileUtilityTargetGenerator.h @@ -23,7 +23,7 @@ class cmMakefileUtilityTargetGenerator: public cmMakefileTargetGenerator { public: - cmMakefileUtilityTargetGenerator(); + cmMakefileUtilityTargetGenerator(cmTarget* target); /* the main entry point for this class. Writes the Makefiles associated with this target */ diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index 4aaba43de..a9eb66850 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -460,15 +460,20 @@ void cmSourceFile::DefineProperties(cmake *cm) cm->DefineProperty ("MACOSX_PACKAGE_LOCATION", cmProperty::SOURCE_FILE, - "Place a source file inside a Mac OS X application bundle.", + "Place a source file inside a Mac OS X bundle or framework.", "Executable targets with the MACOSX_BUNDLE property set are built " "as Mac OS X application bundles on Apple platforms. " - "Source files specified for the target with the " - "MACOSX_PACKAGE_LOCATION property set will be placed in the " - "application bundle Contents folder under the directory specified " - "by the value of the property. " - "Typically this is set to \"Resources\" for icon files and other " - "bundle resources."); + "Shared library targets with the FRAMEWORK property set are built " + "as Mac OS X frameworks on Apple platforms. " + "Source files listed in the target with this property set will " + "be copied to a directory inside the bundle or framework content " + "folder specified by the property value. " + "For bundles the content folder is \".app/Contents\". " + "For frameworks the content folder is " + "\".framework/Versions/\". " + "See the PUBLIC_HEADER, PRIVATE_HEADER, and RESOURCE target " + "properties for specifying files meant for Headers, PrivateHeadres, " + "or Resources directories."); cm->DefineProperty ("OBJECT_DEPENDS", cmProperty::SOURCE_FILE, diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 0422ffc3f..d534a0426 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -32,6 +32,19 @@ const char* cmTarget::TargetTypeNames[] = { "INSTALL_FILES", "INSTALL_PROGRAMS", "INSTALL_DIRECTORY" }; +//---------------------------------------------------------------------------- +class cmTargetInternals +{ +public: + cmTargetInternals() + { + this->SourceFileFlagsConstructed = false; + } + typedef cmTarget::SourceFileFlags SourceFileFlags; + std::map SourceFlagsMap; + bool SourceFileFlagsConstructed; +}; + //---------------------------------------------------------------------------- cmTarget::cmTarget() { @@ -994,76 +1007,101 @@ struct cmTarget::SourceFileFlags cmTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) { struct SourceFileFlags flags; - const char* files; - std::vector::iterator it; + this->ConstructSourceFileFlags(); + std::map::iterator si = + this->Internal->SourceFlagsMap.find(sf); + if(si != this->Internal->SourceFlagsMap.end()) + { + flags = si->second; + } + return flags; +} - flags.PrivateHeader = false; - flags.PublicHeader = false; - flags.Resource = false; +//---------------------------------------------------------------------------- +void cmTarget::ConstructSourceFileFlags() +{ + if(this->Internal->SourceFileFlagsConstructed) + { + return; + } + this->Internal->SourceFileFlagsConstructed = true; - files = this->GetProperty("PRIVATE_HEADER"); - if ((files) && (*files)) + // Process public headers to mark the source files. + if(const char* files = this->GetProperty("PUBLIC_HEADER")) { std::vector relFiles; cmSystemTools::ExpandListArgument(files, relFiles); - for(it = relFiles.begin(); it != relFiles.end(); ++it) + for(std::vector::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) { - if(sf == this->GetMakefile()->GetSource(it->c_str())) + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) { - flags.PrivateHeader = true; - break; + SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; + flags.MacFolder = "Headers"; + flags.Type = cmTarget::SourceFileTypePublicHeader; } } } - // Only consider marking it as a public header if it is *NOT* already marked - // as a private header: - // - if(!flags.PrivateHeader) + // Process private headers after public headers so that they take + // precedence if a file is listed in both. + if(const char* files = this->GetProperty("PRIVATE_HEADER")) { - files = this->GetProperty("PUBLIC_HEADER"); - if ((files) && (*files)) + std::vector relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(std::vector::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) { - std::vector relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - for(it = relFiles.begin(); it != relFiles.end(); ++it) + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) { - if(sf == this->GetMakefile()->GetSource(it->c_str())) + SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; + flags.MacFolder = "PrivateHeaders"; + flags.Type = cmTarget::SourceFileTypePrivateHeader; + } + } + } + + // Mark sources listed as resources. + if(const char* files = this->GetProperty("RESOURCE")) + { + std::vector relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(std::vector::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) + { + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) + { + SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; + flags.MacFolder = "Resources"; + flags.Type = cmTarget::SourceFileTypeResource; + } + } + } + + // Handle the MACOSX_PACKAGE_LOCATION property on source files that + // were not listed in one of the other lists. + std::vector const& sources = this->GetSourceFiles(); + for(std::vector::const_iterator si = sources.begin(); + si != sources.end(); ++si) + { + cmSourceFile* sf = *si; + if(const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) + { + SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; + if(flags.Type == cmTarget::SourceFileTypeNormal) + { + flags.MacFolder = location; + if(strcmp(location, "Resources") == 0) { - flags.PublicHeader = true; - break; + flags.Type = cmTarget::SourceFileTypeResource; + } + else + { + flags.Type = cmTarget::SourceFileTypeMacContent; } } } } - - 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; } //---------------------------------------------------------------------------- @@ -2872,6 +2910,10 @@ const char* cmTarget::GetAndCreateOutputDir(bool implib, bool create) cmSystemTools::CollapseFullPath (out.c_str(), this->Makefile->GetStartOutputDirectory()); + // TODO: Make AppBundle and Framework directory computation in + // target consistent. Why do we add the .framework part here for + // frameworks but not the .app part for bundles? We should + // probably not add it for either. if(this->IsFrameworkOnApple()) { out += "/"; @@ -3392,3 +3434,36 @@ cmTargetLinkInterfaceMap::~cmTargetLinkInterfaceMap() delete i->second; } } + +//---------------------------------------------------------------------------- +cmTargetInternalPointer::cmTargetInternalPointer() +{ + this->Pointer = new cmTargetInternals; +} + +//---------------------------------------------------------------------------- +cmTargetInternalPointer +::cmTargetInternalPointer(cmTargetInternalPointer const&) +{ + // Ideally cmTarget instances should never be copied. However until + // we can make a sweep to remove that, this copy constructor avoids + // allowing the resources (Internals) to be copied. + this->Pointer = new cmTargetInternals; +} + +//---------------------------------------------------------------------------- +cmTargetInternalPointer::~cmTargetInternalPointer() +{ + delete this->Pointer; +} + +//---------------------------------------------------------------------------- +cmTargetInternalPointer& +cmTargetInternalPointer::operator=(cmTargetInternalPointer const&) +{ + // Ideally cmTarget instances should never be copied. However until + // we can make a sweep to remove that, this copy constructor avoids + // allowing the resources (Internals) to be copied. + this->Pointer = new cmTargetInternals; + return *this; +} diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 11b7671b8..ad5a81534 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -53,6 +53,19 @@ struct cmTargetLinkInterfaceMap: ~cmTargetLinkInterfaceMap(); }; +class cmTargetInternals; +class cmTargetInternalPointer +{ +public: + cmTargetInternalPointer(); + cmTargetInternalPointer(cmTargetInternalPointer const& r); + ~cmTargetInternalPointer(); + cmTargetInternalPointer& operator=(cmTargetInternalPointer const& r); + cmTargetInternals* operator->() const { return this->Pointer; } +private: + cmTargetInternals* Pointer; +}; + /** \class cmTarget * \brief Represent a library or executable target loaded from a makefile. * @@ -115,12 +128,22 @@ public: * 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. */ + enum SourceFileType + { + SourceFileTypeNormal, + SourceFileTypePrivateHeader, // is in "PRIVATE_HEADER" target property + SourceFileTypePublicHeader, // is in "PUBLIC_HEADER" target property + SourceFileTypeResource, // is in "RESOURCE" target property *or* + // has MACOSX_PACKAGE_LOCATION=="Resources" + SourceFileTypeMacContent // has MACOSX_PACKAGE_LOCATION!="Resources" + }; 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" + SourceFileFlags(): Type(SourceFileTypeNormal), MacFolder(0) {} + SourceFileFlags(SourceFileFlags const& r): + Type(r.Type), MacFolder(r.MacFolder) {} + SourceFileType Type; + const char* MacFolder; // location inside Mac content folders }; /** @@ -497,6 +520,12 @@ private: // The cmMakefile instance that owns this target. This should // always be set. cmMakefile* Makefile; + + // Internal representation details. + friend class cmTargetInternals; + cmTargetInternalPointer Internal; + + void ConstructSourceFileFlags(); }; typedef std::map cmTargets;