diff options
author | Brad King <brad.king@kitware.com> | 2014-02-25 16:18:12 (GMT) |
---|---|---|
committer | CMake Topic Stage <kwrobot@kitware.com> | 2014-02-25 16:18:12 (GMT) |
commit | 049790c0eb7ba76975d3256c8cc66d59eed25a96 (patch) | |
tree | 6903e5a0aaa05149b64b56e52e76e2cba6f94450 /Source | |
parent | 602be01b3397175b9b94e76496220666b58106b0 (diff) | |
parent | f9d5b1fd0fe1e1c5a0083c6518c7da6c36776042 (diff) | |
download | CMake-049790c0eb7ba76975d3256c8cc66d59eed25a96.zip CMake-049790c0eb7ba76975d3256c8cc66d59eed25a96.tar.gz CMake-049790c0eb7ba76975d3256c8cc66d59eed25a96.tar.bz2 |
Merge topic 'target-SOURCES-refactor'
f9d5b1fd Handle Mac OSX source flags for individual files lazily.
64d39841 cmGeneratorTarget: Classify sources on demand, not up front.
d3682d86 cmGeneratorTarget: Use a method to access the definition file.
5771f81d cmTarget: Add GetTransitiveTargetClosure method.
a6dd4990 cmTarget: Create a temporary cmTarget in checkInterfacePropertyCompatibility
b8b99cc1 cmTarget: Avoid computing languages when computing transitive targets.
01bca553 cmTarget: Move ComputeLinkInterface to the internal class.
d93e1af2 cmTarget: Extract a ComputeLinkInterfaceLibraries method.
3bcb197c cmTarget: Re-arrange the ComputeLinkInterface method.
326d07d2 cmTarget: Extract a ComputeLinkImplementationLanguages method.
21e91350 cmTarget: Change GetTransitivePropertyLinkLibraries to output targets.
f81eb49e cmTarget: Find source files on request.
84e5f5a0 cmTarget: Move SourceFileFlags to cmGeneratorTarget.
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmGeneratorExpressionEvaluator.cxx | 57 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 482 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.h | 45 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.cxx | 36 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.h | 1 | ||||
-rw-r--r-- | Source/cmGlobalXCodeGenerator.cxx | 28 | ||||
-rw-r--r-- | Source/cmMakefileTargetGenerator.cxx | 11 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 6 | ||||
-rw-r--r-- | Source/cmOSXBundleGenerator.cxx | 32 | ||||
-rw-r--r-- | Source/cmOSXBundleGenerator.h | 2 | ||||
-rw-r--r-- | Source/cmTarget.cxx | 511 | ||||
-rw-r--r-- | Source/cmTarget.h | 53 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.cxx | 6 |
13 files changed, 775 insertions, 495 deletions
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 7036992..bdefcfb 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -800,7 +800,7 @@ static const char* targetPropertyTransitiveWhitelist[] = { #undef TRANSITIVE_PROPERTY_NAME -std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, +std::string getLinkedTargetsContent(const std::vector<cmTarget*> &targets, cmTarget const* target, cmTarget const* headTarget, cmGeneratorExpressionContext *context, @@ -811,23 +811,21 @@ std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, std::string sep; std::string depString; - for (std::vector<std::string>::const_iterator - it = libraries.begin(); - it != libraries.end(); ++it) + for (std::vector<cmTarget*>::const_iterator + it = targets.begin(); + it != targets.end(); ++it) { - if (*it == target->GetName()) + if (*it == target) { // Broken code can have a target in its own link interface. // Don't follow such link interface entries so as not to create a // self-referencing loop. continue; } - if (context->Makefile->FindTargetToUse(*it)) - { - depString += - sep + "$<TARGET_PROPERTY:" + *it + "," + interfacePropertyName + ">"; - sep = ";"; - } + depString += + sep + "$<TARGET_PROPERTY:" + + (*it)->GetName() + "," + interfacePropertyName + ">"; + sep = ";"; } cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depString); std::string linkedTargetsContent = cge->Evaluate(context->Makefile, @@ -843,6 +841,27 @@ std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, return linkedTargetsContent; } +std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, + cmTarget const* target, + cmTarget const* headTarget, + cmGeneratorExpressionContext *context, + cmGeneratorExpressionDAGChecker *dagChecker, + const std::string &interfacePropertyName) +{ + std::vector<cmTarget*> tgts; + for (std::vector<std::string>::const_iterator + it = libraries.begin(); + it != libraries.end(); ++it) + { + if (cmTarget *tgt = context->Makefile->FindTargetToUse(*it)) + { + tgts.push_back(tgt); + } + } + return getLinkedTargetsContent(tgts, target, headTarget, context, + dagChecker, interfacePropertyName); +} + //---------------------------------------------------------------------------- static const struct TargetPropertyNode : public cmGeneratorExpressionNode { @@ -1065,13 +1084,13 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode cmStrCmp(propertyName)) != transEnd) { - std::vector<std::string> libs; - target->GetTransitivePropertyLinkLibraries(context->Config, - headTarget, libs); - if (!libs.empty()) + std::vector<cmTarget*> tgts; + target->GetTransitivePropertyTargets(context->Config, + headTarget, tgts); + if (!tgts.empty()) { linkedTargetsContent = - getLinkedTargetsContent(libs, target, + getLinkedTargetsContent(tgts, target, headTarget, context, &dagChecker, interfacePropertyName); @@ -1080,9 +1099,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode else if (std::find_if(transBegin, transEnd, cmStrCmp(interfacePropertyName)) != transEnd) { - const cmTarget::LinkImplementation *impl = target->GetLinkImplementation( - context->Config, - headTarget); + const cmTarget::LinkImplementation *impl + = target->GetLinkImplementationLibraries(context->Config, + headTarget); if(impl) { linkedTargetsContent = diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 175bb0e..a7b2fb6 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -25,7 +25,196 @@ #include "assert.h" //---------------------------------------------------------------------------- -cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t) +void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib, + cmTarget *target, cmake *cm) +{ + if(!badObjLib.empty()) + { + cmOStringStream e; + e << "OBJECT library \"" << target->GetName() << "\" contains:\n"; + for(std::vector<cmSourceFile*>::const_iterator i = badObjLib.begin(); + i != badObjLib.end(); ++i) + { + e << " " << (*i)->GetLocation().GetName() << "\n"; + } + e << "but may contain only headers and sources that compile."; + cm->IssueMessage(cmake::FATAL_ERROR, e.str(), + target->GetBacktrace()); + } +} + +struct ObjectSourcesTag {}; +struct CustomCommandsTag {}; +struct ExtraSourcesTag {}; +struct HeaderSourcesTag {}; +struct ExternalObjectsTag {}; +struct IDLSourcesTag {}; +struct ResxTag {}; +struct ModuleDefinitionFileTag {}; + +#if !defined(_MSC_VER) || _MSC_VER >= 1310 +template<typename Tag, typename OtherTag> +struct IsSameTag +{ + enum { + Result = false + }; +}; + +template<typename Tag> +struct IsSameTag<Tag, Tag> +{ + enum { + Result = true + }; +}; +#else +struct IsSameTagBase +{ + typedef char (&no_type)[1]; + typedef char (&yes_type)[2]; + template<typename T> struct Check; + template<typename T> static yes_type check(Check<T>*, Check<T>*); + static no_type check(...); +}; +template<typename Tag1, typename Tag2> +struct IsSameTag: public IsSameTagBase +{ + enum { + Result = (sizeof(check(static_cast< Check<Tag1>* >(0), + static_cast< Check<Tag2>* >(0))) == + sizeof(yes_type)) + }; +}; +#endif + +template<bool> +struct DoAccept +{ + template <typename T> static void Do(T&, cmSourceFile*) {} +}; + +template<> +struct DoAccept<true> +{ + static void Do(std::vector<cmSourceFile*>& files, cmSourceFile* f) + { + files.push_back(f); + } + static void Do(cmGeneratorTarget::ResxData& data, cmSourceFile* f) + { + // Build and save the name of the corresponding .h file + // This relationship will be used later when building the project files. + // Both names would have been auto generated from Visual Studio + // where the user supplied the file name and Visual Studio + // appended the suffix. + std::string resx = f->GetFullPath(); + std::string hFileName = resx.substr(0, resx.find_last_of(".")) + ".h"; + data.ExpectedResxHeaders.insert(hFileName); + data.ResxSources.push_back(f); + } + static void Do(std::string& data, cmSourceFile* f) + { + data = f->GetFullPath(); + } +}; + +//---------------------------------------------------------------------------- +template<typename Tag, typename DataType = std::vector<cmSourceFile*> > +struct TagVisitor +{ + DataType& Data; + std::vector<cmSourceFile*> BadObjLibFiles; + cmTarget *Target; + cmGlobalGenerator *GlobalGenerator; + cmsys::RegularExpression Header; + bool IsObjLib; + + TagVisitor(cmTarget *target, DataType& data) + : Data(data), Target(target), + GlobalGenerator(target->GetMakefile() + ->GetLocalGenerator()->GetGlobalGenerator()), + Header(CM_HEADER_REGEX), + IsObjLib(target->GetType() == cmTarget::OBJECT_LIBRARY) + { + } + + ~TagVisitor() + { + reportBadObjLib(this->BadObjLibFiles, this->Target, + this->GlobalGenerator->GetCMakeInstance()); + } + + void Accept(cmSourceFile *sf) + { + std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); + if(sf->GetCustomCommand()) + { + DoAccept<IsSameTag<Tag, CustomCommandsTag>::Result>::Do(this->Data, sf); + } + else if(this->Target->GetType() == cmTarget::UTILITY) + { + DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf); + } + else if(sf->GetPropertyAsBool("HEADER_FILE_ONLY")) + { + DoAccept<IsSameTag<Tag, HeaderSourcesTag>::Result>::Do(this->Data, sf); + } + else if(sf->GetPropertyAsBool("EXTERNAL_OBJECT")) + { + DoAccept<IsSameTag<Tag, ExternalObjectsTag>::Result>::Do(this->Data, sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(sf->GetLanguage()) + { + DoAccept<IsSameTag<Tag, ObjectSourcesTag>::Result>::Do(this->Data, sf); + } + else if(ext == "def") + { + DoAccept<IsSameTag<Tag, ModuleDefinitionFileTag>::Result>::Do(this->Data, + sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(ext == "idl") + { + DoAccept<IsSameTag<Tag, IDLSourcesTag>::Result>::Do(this->Data, sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(ext == "resx") + { + DoAccept<IsSameTag<Tag, ResxTag>::Result>::Do(this->Data, sf); + } + else if(this->Header.find(sf->GetFullPath().c_str())) + { + DoAccept<IsSameTag<Tag, HeaderSourcesTag>::Result>::Do(this->Data, sf); + } + else if(this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str())) + { + DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf); + } + else + { + DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf); + if(this->IsObjLib && ext != "txt") + { + this->BadObjLibFiles.push_back(sf); + } + } + } +}; + +//---------------------------------------------------------------------------- +cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t), + SourceFileFlagsConstructed(false) { this->Makefile = this->Target->GetMakefile(); this->LocalGenerator = this->Makefile->GetLocalGenerator(); @@ -62,19 +251,12 @@ cmGeneratorTarget::GetSourceDepends(cmSourceFile* sf) const return 0; } -static void handleSystemIncludesDep(cmMakefile *mf, const std::string &name, +static void handleSystemIncludesDep(cmMakefile *mf, cmTarget* depTgt, const char *config, cmTarget *headTarget, cmGeneratorExpressionDAGChecker *dagChecker, std::vector<std::string>& result, bool excludeImported) { - cmTarget* depTgt = mf->FindTargetToUse(name); - - if (!depTgt) - { - return; - } - cmListFileBacktrace lfbt; if (const char* dirs = @@ -102,11 +284,34 @@ static void handleSystemIncludesDep(cmMakefile *mf, const std::string &name, } } +#define IMPLEMENT_VISIT_IMPL(DATA, DATATYPE) \ + { \ + std::vector<cmSourceFile*> sourceFiles; \ + this->Target->GetSourceFiles(sourceFiles); \ + TagVisitor<DATA ## Tag DATATYPE> visitor(this->Target, data); \ + for(std::vector<cmSourceFile*>::const_iterator si = sourceFiles.begin(); \ + si != sourceFiles.end(); ++si) \ + { \ + visitor.Accept(*si); \ + } \ + } \ + + +#define IMPLEMENT_VISIT(DATA) \ + IMPLEMENT_VISIT_IMPL(DATA, EMPTY) \ + +#define EMPTY +#define COMMA , + //---------------------------------------------------------------------------- void -cmGeneratorTarget::GetObjectSources(std::vector<cmSourceFile*> &objs) const +cmGeneratorTarget::GetObjectSources(std::vector<cmSourceFile*> &data) const { - objs = this->ObjectSources; + IMPLEMENT_VISIT(ObjectSources); + if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY) + { + this->ObjectSources = data; + } } //---------------------------------------------------------------------------- @@ -135,49 +340,53 @@ bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const } //---------------------------------------------------------------------------- -void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile*>& srcs) const +void cmGeneratorTarget::GetIDLSources(std::vector<cmSourceFile*>& data) const { - srcs = this->ResxSources; + IMPLEMENT_VISIT(IDLSources); } //---------------------------------------------------------------------------- -void cmGeneratorTarget::GetIDLSources(std::vector<cmSourceFile*>& srcs) const +void +cmGeneratorTarget::GetHeaderSources(std::vector<cmSourceFile*>& data) const { - srcs = this->IDLSources; + IMPLEMENT_VISIT(HeaderSources); } //---------------------------------------------------------------------------- -void -cmGeneratorTarget::GetHeaderSources(std::vector<cmSourceFile*>& srcs) const +void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile*>& data) const { - srcs = this->HeaderSources; + IMPLEMENT_VISIT(ExtraSources); } //---------------------------------------------------------------------------- -void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile*>& srcs) const +void +cmGeneratorTarget::GetCustomCommands(std::vector<cmSourceFile*>& data) const { - srcs = this->ExtraSources; + IMPLEMENT_VISIT(CustomCommands); } //---------------------------------------------------------------------------- void -cmGeneratorTarget::GetCustomCommands(std::vector<cmSourceFile*>& srcs) const +cmGeneratorTarget::GetExternalObjects(std::vector<cmSourceFile*>& data) const { - srcs = this->CustomCommands; + IMPLEMENT_VISIT(ExternalObjects); } //---------------------------------------------------------------------------- void cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& srcs) const { - srcs = this->ExpectedResxHeaders; + ResxData data; + IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData) + srcs = data.ExpectedResxHeaders; } //---------------------------------------------------------------------------- -void -cmGeneratorTarget::GetExternalObjects(std::vector<cmSourceFile*>& srcs) const +void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile*>& srcs) const { - srcs = this->ExternalObjects; + ResxData data; + IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData) + srcs = data.ResxSources; } //---------------------------------------------------------------------------- @@ -224,26 +433,25 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir, &dagChecker), result); } - std::set<cmStdString> uniqueDeps; + std::set<cmTarget*> uniqueDeps; for(std::vector<std::string>::const_iterator li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) { - if (uniqueDeps.insert(*li).second) + cmTarget* tgt = this->Makefile->FindTargetToUse(*li); + if (!tgt) { - cmTarget* tgt = this->Makefile->FindTargetToUse(*li); - - if (!tgt) - { - continue; - } + continue; + } - handleSystemIncludesDep(this->Makefile, *li, config, this->Target, + if (uniqueDeps.insert(tgt).second) + { + handleSystemIncludesDep(this->Makefile, tgt, config, this->Target, &dagChecker, result, excludeImported); - std::vector<std::string> deps; - tgt->GetTransitivePropertyLinkLibraries(config, this->Target, deps); + std::vector<cmTarget*> deps; + tgt->GetTransitivePropertyTargets(config, this->Target, deps); - for(std::vector<std::string>::const_iterator di = deps.begin(); + for(std::vector<cmTarget*>::const_iterator di = deps.begin(); di != deps.end(); ++di) { if (uniqueDeps.insert(*di).second) @@ -290,102 +498,6 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const } //---------------------------------------------------------------------------- -void cmGeneratorTarget::ClassifySources() -{ - cmsys::RegularExpression header(CM_HEADER_REGEX); - - cmTarget::TargetType targetType = this->Target->GetType(); - bool isObjLib = targetType == cmTarget::OBJECT_LIBRARY; - - std::vector<cmSourceFile*> badObjLib; - std::vector<cmSourceFile*> sources; - this->Target->GetSourceFiles(sources); - for(std::vector<cmSourceFile*>::const_iterator si = sources.begin(); - si != sources.end(); ++si) - { - cmSourceFile* sf = *si; - std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); - if(sf->GetCustomCommand()) - { - this->CustomCommands.push_back(sf); - } - else if(targetType == cmTarget::UTILITY) - { - this->ExtraSources.push_back(sf); - } - else if(sf->GetPropertyAsBool("HEADER_FILE_ONLY")) - { - this->HeaderSources.push_back(sf); - } - else if(sf->GetPropertyAsBool("EXTERNAL_OBJECT")) - { - this->ExternalObjects.push_back(sf); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(sf->GetLanguage()) - { - this->ObjectSources.push_back(sf); - } - else if(ext == "def") - { - this->ModuleDefinitionFile = sf->GetFullPath(); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(ext == "idl") - { - this->IDLSources.push_back(sf); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(ext == "resx") - { - // Build and save the name of the corresponding .h file - // This relationship will be used later when building the project files. - // Both names would have been auto generated from Visual Studio - // where the user supplied the file name and Visual Studio - // appended the suffix. - std::string resx = sf->GetFullPath(); - std::string hFileName = resx.substr(0, resx.find_last_of(".")) + ".h"; - this->ExpectedResxHeaders.insert(hFileName); - this->ResxSources.push_back(sf); - } - else if(header.find(sf->GetFullPath().c_str())) - { - this->HeaderSources.push_back(sf); - } - else if(this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str())) - { - // We only get here if a source file is not an external object - // and has an extension that is listed as an ignored file type. - // No message or diagnosis should be given. - this->ExtraSources.push_back(sf); - } - else - { - this->ExtraSources.push_back(sf); - if(isObjLib && ext != "txt") - { - badObjLib.push_back(sf); - } - } - } - - if(!badObjLib.empty()) - { - cmOStringStream e; - e << "OBJECT library \"" << this->Target->GetName() << "\" contains:\n"; - for(std::vector<cmSourceFile*>::iterator i = badObjLib.begin(); - i != badObjLib.end(); ++i) - { - e << " " << (*i)->GetLocation().GetName() << "\n"; - } - e << "but may contain only headers and sources that compile."; - this->GlobalGenerator->GetCMakeInstance() - ->IssueMessage(cmake::FATAL_ERROR, e.str(), - this->Target->GetBacktrace()); - } -} - -//---------------------------------------------------------------------------- void cmGeneratorTarget::LookupObjectLibraries() { std::vector<std::string> const& objLibs = @@ -438,6 +550,14 @@ void cmGeneratorTarget::LookupObjectLibraries() } //---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetModuleDefinitionFile() const +{ + std::string data; + IMPLEMENT_VISIT_IMPL(ModuleDefinitionFile, COMMA std::string) + return data; +} + +//---------------------------------------------------------------------------- void cmGeneratorTarget::UseObjectLibraries(std::vector<std::string>& objs) const { @@ -876,3 +996,97 @@ bool cmStrictTargetComparison::operator()(cmTarget const* t1, } return nameResult < 0; } + +//---------------------------------------------------------------------------- +struct cmGeneratorTarget::SourceFileFlags +cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const +{ + struct SourceFileFlags flags; + this->ConstructSourceFileFlags(); + std::map<cmSourceFile const*, SourceFileFlags>::iterator si = + this->SourceFlagsMap.find(sf); + if(si != this->SourceFlagsMap.end()) + { + flags = si->second; + } + else + { + // Handle the MACOSX_PACKAGE_LOCATION property on source files that + // were not listed in one of the other lists. + if(const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) + { + flags.MacFolder = location; + if(strcmp(location, "Resources") == 0) + { + flags.Type = cmGeneratorTarget::SourceFileTypeResource; + } + else + { + flags.Type = cmGeneratorTarget::SourceFileTypeMacContent; + } + } + } + return flags; +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::ConstructSourceFileFlags() const +{ + if(this->SourceFileFlagsConstructed) + { + return; + } + this->SourceFileFlagsConstructed = true; + + // Process public headers to mark the source files. + if(const char* files = this->Target->GetProperty("PUBLIC_HEADER")) + { + std::vector<std::string> relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(std::vector<std::string>::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) + { + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) + { + SourceFileFlags& flags = this->SourceFlagsMap[sf]; + flags.MacFolder = "Headers"; + flags.Type = cmGeneratorTarget::SourceFileTypePublicHeader; + } + } + } + + // Process private headers after public headers so that they take + // precedence if a file is listed in both. + if(const char* files = this->Target->GetProperty("PRIVATE_HEADER")) + { + std::vector<std::string> relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(std::vector<std::string>::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) + { + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) + { + SourceFileFlags& flags = this->SourceFlagsMap[sf]; + flags.MacFolder = "PrivateHeaders"; + flags.Type = cmGeneratorTarget::SourceFileTypePrivateHeader; + } + } + } + + // Mark sources listed as resources. + if(const char* files = this->Target->GetProperty("RESOURCE")) + { + std::vector<std::string> relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(std::vector<std::string>::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) + { + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) + { + SourceFileFlags& flags = this->SourceFlagsMap[sf]; + flags.MacFolder = "Resources"; + flags.Type = cmGeneratorTarget::SourceFileTypeResource; + } + } + } +} diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index a4caba1..1e6ce64 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -52,7 +52,7 @@ public: cmLocalGenerator* LocalGenerator; cmGlobalGenerator const* GlobalGenerator; - std::string ModuleDefinitionFile; + std::string GetModuleDefinitionFile() const; /** Full path with trailing slash to the top-level directory holding object files for this target. Includes the build @@ -82,31 +82,56 @@ public: */ void TraceDependencies(); - void ClassifySources(); void LookupObjectLibraries(); /** Get sources that must be built before the given source. */ std::vector<cmSourceFile*> const* GetSourceDepends(cmSourceFile* sf) const; + /** + * 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 + { + 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 + }; + + struct SourceFileFlags + GetTargetSourceFileFlags(const cmSourceFile* sf) const; + + struct ResxData { + mutable std::set<std::string> ExpectedResxHeaders; + mutable std::vector<cmSourceFile*> ResxSources; + }; private: friend class cmTargetTraceDependencies; struct SourceEntry { std::vector<cmSourceFile*> Depends; }; typedef std::map<cmSourceFile*, SourceEntry> SourceEntriesType; SourceEntriesType SourceEntries; - std::vector<cmSourceFile*> CustomCommands; - std::vector<cmSourceFile*> ExtraSources; - std::vector<cmSourceFile*> HeaderSources; - std::vector<cmSourceFile*> ExternalObjects; - std::vector<cmSourceFile*> IDLSources; - std::vector<cmSourceFile*> ResxSources; std::map<cmSourceFile const*, std::string> Objects; std::set<cmSourceFile const*> ExplicitObjectName; - std::set<std::string> ExpectedResxHeaders; - std::vector<cmSourceFile*> ObjectSources; + mutable std::vector<cmSourceFile*> ObjectSources; std::vector<cmTarget*> ObjectLibraries; mutable std::map<std::string, std::vector<std::string> > SystemIncludesCache; + void ConstructSourceFileFlags() const; + mutable bool SourceFileFlagsConstructed; + mutable std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap; + cmGeneratorTarget(cmGeneratorTarget const&); void operator=(cmGeneratorTarget const&); }; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 4f3328d..f76c6d1 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1148,12 +1148,6 @@ void cmGlobalGenerator::Generate() return; } - // Check that all targets are valid. - if(!this->CheckTargets()) - { - return; - } - this->FinalizeTargetCompileInfo(); #ifdef CMAKE_BUILD_WITH_CMAKE @@ -1306,35 +1300,6 @@ bool cmGlobalGenerator::ComputeTargetDepends() } //---------------------------------------------------------------------------- -bool cmGlobalGenerator::CheckTargets() -{ - // Make sure all targets can find their source files. - for(unsigned int i=0; i < this->LocalGenerators.size(); ++i) - { - cmTargets& targets = - this->LocalGenerators[i]->GetMakefile()->GetTargets(); - for(cmTargets::iterator ti = targets.begin(); - ti != targets.end(); ++ti) - { - cmTarget& target = ti->second; - if(target.GetType() == cmTarget::EXECUTABLE || - target.GetType() == cmTarget::STATIC_LIBRARY || - target.GetType() == cmTarget::SHARED_LIBRARY || - target.GetType() == cmTarget::MODULE_LIBRARY || - target.GetType() == cmTarget::OBJECT_LIBRARY || - target.GetType() == cmTarget::UTILITY) - { - if(!target.FindSourceFiles()) - { - return false; - } - } - } - } - return true; -} - -//---------------------------------------------------------------------------- void cmGlobalGenerator::CreateQtAutoGeneratorsTargets(AutogensType &autogens) { #ifdef CMAKE_BUILD_WITH_CMAKE @@ -1474,7 +1439,6 @@ void cmGlobalGenerator::ComputeGeneratorTargetObjects() continue; } cmGeneratorTarget* gt = ti->second; - gt->ClassifySources(); gt->LookupObjectLibraries(); this->ComputeTargetObjects(gt); } diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 753eebf..b66f01e 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -340,7 +340,6 @@ protected: virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const; - bool CheckTargets(); typedef std::vector<std::pair<cmQtAutoGenerators, cmTarget const*> > AutogensType; void CreateQtAutoGeneratorsTargets(AutogensType& autogens); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 484b28f..004f7ac 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -713,22 +713,23 @@ 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.Type == cmTarget::SourceFileTypeResource); + cmGeneratorTarget::SourceFileFlags tsFlags = + this->GetGeneratorTarget(&cmtarget)->GetTargetSourceFileFlags(sf); + bool isResource = tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource; // Is this a "private" or "public" framework header file? // Set the ATTRIBUTES attribute appropriately... // if(cmtarget.IsFrameworkOnApple()) { - if(tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) + if(tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) { cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); attrs->AddObject(this->CreateString("Private")); settings->AddAttribute("ATTRIBUTES", attrs); isResource = true; } - else if(tsFlags.Type == cmTarget::SourceFileTypePublicHeader) + else if(tsFlags.Type == cmGeneratorTarget::SourceFileTypePublicHeader) { cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); attrs->AddObject(this->CreateString("Public")); @@ -973,6 +974,7 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) { cmTarget& cmtarget = l->second; + cmGeneratorTarget* gtgt = this->GetGeneratorTarget(&cmtarget); // make sure ALL_BUILD, INSTALL, etc are only done once if(this->SpecialTargetEmitted(l->first.c_str())) @@ -1011,8 +1013,8 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, cmXCodeObject* filetype = fr->GetObject()->GetObject("explicitFileType"); - cmTarget::SourceFileFlags tsFlags = - cmtarget.GetTargetSourceFileFlags(*i); + cmGeneratorTarget::SourceFileFlags tsFlags = + gtgt->GetTargetSourceFileFlags(*i); if(filetype && strcmp(filetype->GetString(), "compiled.mach-o.objfile") == 0) @@ -1020,12 +1022,12 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, externalObjFiles.push_back(xsf); } else if(this->IsHeaderFile(*i) || - (tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) || - (tsFlags.Type == cmTarget::SourceFileTypePublicHeader)) + (tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) || + (tsFlags.Type == cmGeneratorTarget::SourceFileTypePublicHeader)) { headerFiles.push_back(xsf); } - else if(tsFlags.Type == cmTarget::SourceFileTypeResource) + else if(tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource) { resourceFiles.push_back(xsf); } @@ -1048,7 +1050,7 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, // the externalObjFiles above, except each one is not a cmSourceFile // within the target.) std::vector<std::string> objs; - this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs); + gtgt->UseObjectLibraries(objs); for(std::vector<std::string>::const_iterator oi = objs.begin(); oi != objs.end(); ++oi) { @@ -1138,9 +1140,9 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, for(std::vector<cmSourceFile*>::const_iterator i = classes.begin(); i != classes.end(); ++i) { - cmTarget::SourceFileFlags tsFlags = - cmtarget.GetTargetSourceFileFlags(*i); - if(tsFlags.Type == cmTarget::SourceFileTypeMacContent) + cmGeneratorTarget::SourceFileFlags tsFlags = + gtgt->GetTargetSourceFileFlags(*i); + if(tsFlags.Type == cmGeneratorTarget::SourceFileTypeMacContent) { bundleFiles[tsFlags.MacFolder].push_back(*i); } diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index c3ca85d..5a841ed 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1650,9 +1650,10 @@ void cmMakefileTargetGenerator this->AppendTargetDepends(depends); // Add a dependency on the link definitions file, if any. - if(!this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(!def.empty()) { - depends.push_back(this->GeneratorTarget->ModuleDefinitionFile); + depends.push_back(def); } // Add user-specified dependencies. @@ -2019,7 +2020,8 @@ void cmMakefileTargetGenerator::AddFortranFlags(std::string& flags) //---------------------------------------------------------------------------- void cmMakefileTargetGenerator::AddModuleDefinitionFlag(std::string& flags) { - if(this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(def.empty()) { return; } @@ -2035,8 +2037,7 @@ void cmMakefileTargetGenerator::AddModuleDefinitionFlag(std::string& flags) // Append the flag and value. Use ConvertToLinkReference to help // vs6's "cl -link" pass it to the linker. std::string flag = defFileFlag; - flag += (this->LocalGenerator->ConvertToLinkReference( - this->GeneratorTarget->ModuleDefinitionFile.c_str())); + flag += (this->LocalGenerator->ConvertToLinkReference(def.c_str())); this->LocalGenerator->AppendFlags(flags, flag.c_str()); } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 900af8d..5f6fc2d 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -498,10 +498,10 @@ cmNinjaTargetGenerator { this->WriteObjectBuildStatement(*si); } - if(!this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(!def.empty()) { - this->ModuleDefinitionFile = this->ConvertToNinjaPath( - this->GeneratorTarget->ModuleDefinitionFile.c_str()); + this->ModuleDefinitionFile = this->ConvertToNinjaPath(def.c_str()); } { diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx index 9a340dc..78b59b3 100644 --- a/Source/cmOSXBundleGenerator.cxx +++ b/Source/cmOSXBundleGenerator.cxx @@ -20,7 +20,7 @@ cmOSXBundleGenerator:: cmOSXBundleGenerator(cmGeneratorTarget* target, const char* configName) - : Target(target->Target) + : GT(target) , Makefile(target->Target->GetMakefile()) , LocalGenerator(Makefile->GetLocalGenerator()) , ConfigName(configName) @@ -34,7 +34,7 @@ cmOSXBundleGenerator(cmGeneratorTarget* target, //---------------------------------------------------------------------------- bool cmOSXBundleGenerator::MustSkip() { - return !this->Target->HaveWellDefinedOutputFiles(); + return !this->GT->Target->HaveWellDefinedOutputFiles(); } //---------------------------------------------------------------------------- @@ -47,7 +47,7 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, // Compute bundle directory names. std::string out = outpath; out += "/"; - out += this->Target->GetAppBundleDirectory(this->ConfigName, false); + out += this->GT->Target->GetAppBundleDirectory(this->ConfigName, false); cmSystemTools::MakeDirectory(out.c_str()); this->Makefile->AddCMakeOutputFile(out); @@ -57,9 +57,9 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, // to be set. std::string plist = outpath; plist += "/"; - plist += this->Target->GetAppBundleDirectory(this->ConfigName, true); + plist += this->GT->Target->GetAppBundleDirectory(this->ConfigName, true); plist += "/Info.plist"; - this->LocalGenerator->GenerateAppleInfoPList(this->Target, + this->LocalGenerator->GenerateAppleInfoPList(this->GT->Target, targetName.c_str(), plist.c_str()); this->Makefile->AddCMakeOutputFile(plist); @@ -77,20 +77,20 @@ void cmOSXBundleGenerator::CreateFramework( // Compute the location of the top-level foo.framework directory. std::string contentdir = outpath + "/" + - this->Target->GetFrameworkDirectory(this->ConfigName, true); + this->GT->Target->GetFrameworkDirectory(this->ConfigName, true); contentdir += "/"; std::string newoutpath = outpath + "/" + - this->Target->GetFrameworkDirectory(this->ConfigName, false); + this->GT->Target->GetFrameworkDirectory(this->ConfigName, false); - std::string frameworkVersion = this->Target->GetFrameworkVersion(); + std::string frameworkVersion = this->GT->Target->GetFrameworkVersion(); // Configure the Info.plist file into the Resources directory. this->MacContentFolders->insert("Resources"); std::string plist = newoutpath; plist += "/Resources/Info.plist"; std::string name = cmSystemTools::GetFilenameName(targetName); - this->LocalGenerator->GenerateFrameworkInfoPList(this->Target, + this->LocalGenerator->GenerateFrameworkInfoPList(this->GT->Target, name.c_str(), plist.c_str()); @@ -172,16 +172,16 @@ void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName, // Compute bundle directory names. std::string out = root; out += "/"; - out += this->Target->GetCFBundleDirectory(this->ConfigName, false); + out += this->GT->Target->GetCFBundleDirectory(this->ConfigName, false); cmSystemTools::MakeDirectory(out.c_str()); this->Makefile->AddCMakeOutputFile(out); // Configure the Info.plist file. Note that it needs the executable name // to be set. std::string plist = - this->Target->GetCFBundleDirectory(this->ConfigName, true); + this->GT->Target->GetCFBundleDirectory(this->ConfigName, true); plist += "/Info.plist"; - this->LocalGenerator->GenerateAppleInfoPList(this->Target, + this->LocalGenerator->GenerateAppleInfoPList(this->GT->Target, targetName.c_str(), plist.c_str()); this->Makefile->AddCMakeOutputFile(plist); @@ -199,9 +199,9 @@ GenerateMacOSXContentStatements(std::vector<cmSourceFile*> const& sources, for(std::vector<cmSourceFile*>::const_iterator si = sources.begin(); si != sources.end(); ++si) { - cmTarget::SourceFileFlags tsFlags = - this->Target->GetTargetSourceFileFlags(*si); - if(tsFlags.Type != cmTarget::SourceFileTypeNormal) + cmGeneratorTarget::SourceFileFlags tsFlags = + this->GT->GetTargetSourceFileFlags(*si); + if(tsFlags.Type != cmGeneratorTarget::SourceFileTypeNormal) { (*generator)(**si, tsFlags.MacFolder); } @@ -215,7 +215,7 @@ cmOSXBundleGenerator::InitMacOSXContentDirectory(const char* pkgloc) // Construct the full path to the content subdirectory. std::string macdir = - this->Target->GetMacContentDirectory(this->ConfigName, + this->GT->Target->GetMacContentDirectory(this->ConfigName, /*implib*/ false); macdir += "/"; macdir += pkgloc; diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h index 29b7611..2f36394 100644 --- a/Source/cmOSXBundleGenerator.h +++ b/Source/cmOSXBundleGenerator.h @@ -59,7 +59,7 @@ private: bool MustSkip(); private: - cmTarget* Target; + cmGeneratorTarget* GT; cmMakefile* Makefile; cmLocalGenerator* LocalGenerator; const char* ConfigName; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index db34bd8..7df2928 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -83,17 +83,12 @@ public: cmTargetInternals() { this->PolicyWarnedCMP0022 = false; - this->SourceFileFlagsConstructed = false; } cmTargetInternals(cmTargetInternals const&) { this->PolicyWarnedCMP0022 = false; - this->SourceFileFlagsConstructed = false; } ~cmTargetInternals(); - typedef cmTarget::SourceFileFlags SourceFileFlags; - mutable std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap; - mutable bool SourceFileFlagsConstructed; // The backtrace when the target was created. cmListFileBacktrace Backtrace; @@ -101,9 +96,17 @@ public: // Cache link interface computation from each configuration. struct OptionalLinkInterface: public cmTarget::LinkInterface { - OptionalLinkInterface(): Exists(false) {} + OptionalLinkInterface(): + Exists(false), Complete(false), ExplicitLibraries(0) {} bool Exists; + bool Complete; + const char* ExplicitLibraries; }; + void ComputeLinkInterface(cmTarget const* thisTarget, + const char* config, OptionalLinkInterface& iface, + cmTarget const* head, + const char *explicitLibraries) const; + typedef std::map<TargetConfigPair, OptionalLinkInterface> LinkInterfaceMapType; LinkInterfaceMapType LinkInterfaceMap; @@ -527,10 +530,11 @@ bool cmTarget::IsBundleOnApple() const } //---------------------------------------------------------------------------- -bool cmTarget::FindSourceFiles() +void cmTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const { + assert(this->GetType() != INTERFACE_LIBRARY); for(std::vector<cmSourceFile*>::const_iterator - si = this->SourceFiles.begin(); + si = this->SourceFiles.begin(); si != this->SourceFiles.end(); ++si) { std::string e; @@ -542,16 +546,9 @@ bool cmTarget::FindSourceFiles() cm->IssueMessage(cmake::FATAL_ERROR, e, this->GetBacktrace()); } - return false; + return; } } - return true; -} - -//---------------------------------------------------------------------------- -void cmTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const -{ - assert(this->GetType() != INTERFACE_LIBRARY); files = this->SourceFiles; } @@ -648,109 +645,6 @@ void cmTarget::ProcessSourceExpression(std::string const& expr) } //---------------------------------------------------------------------------- -struct cmTarget::SourceFileFlags -cmTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const -{ - struct SourceFileFlags flags; - this->ConstructSourceFileFlags(); - std::map<cmSourceFile const*, SourceFileFlags>::iterator si = - this->Internal->SourceFlagsMap.find(sf); - if(si != this->Internal->SourceFlagsMap.end()) - { - flags = si->second; - } - return flags; -} - -//---------------------------------------------------------------------------- -void cmTarget::ConstructSourceFileFlags() const -{ - if(this->Internal->SourceFileFlagsConstructed) - { - return; - } - this->Internal->SourceFileFlagsConstructed = true; - - // Process public headers to mark the source files. - if(const char* files = this->GetProperty("PUBLIC_HEADER")) - { - std::vector<std::string> relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - for(std::vector<std::string>::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 = "Headers"; - flags.Type = cmTarget::SourceFileTypePublicHeader; - } - } - } - - // 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")) - { - std::vector<std::string> relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - for(std::vector<std::string>::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 = "PrivateHeaders"; - flags.Type = cmTarget::SourceFileTypePrivateHeader; - } - } - } - - // Mark sources listed as resources. - if(const char* files = this->GetProperty("RESOURCE")) - { - std::vector<std::string> relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - for(std::vector<std::string>::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<cmSourceFile*> sources; - this->GetSourceFiles(sources); - for(std::vector<cmSourceFile*>::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.Type = cmTarget::SourceFileTypeResource; - } - else - { - flags.Type = cmTarget::SourceFileTypeMacContent; - } - } - } - } -} - -//---------------------------------------------------------------------------- void cmTarget::MergeLinkLibraries( cmMakefile& mf, const char *selfname, const LinkLibraryVectorType& libs ) @@ -4530,12 +4424,13 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet)); - cmComputeLinkInformation *info = tgt->GetLinkInformation(config); - if(!info) + std::vector<cmTarget*> deps; + tgt->GetTransitiveTargetClosure(config, tgt, deps); + + if(deps.empty()) { return propContent; } - const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); bool propInitialized = explicitlySet; std::string report = " * Target \""; @@ -4555,7 +4450,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, report += "\" property not set.\n"; } - for(cmComputeLinkInformation::ItemVector::const_iterator li = + for(std::vector<cmTarget*>::const_iterator li = deps.begin(); li != deps.end(); ++li) { @@ -4565,23 +4460,20 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, // target itself has a POSITION_INDEPENDENT_CODE which disagrees // with a dependency. - if (!li->Target) - { - continue; - } + cmTarget const* theTarget = *li; - const bool ifaceIsSet = li->Target->GetProperties() + const bool ifaceIsSet = theTarget->GetProperties() .find("INTERFACE_" + p) - != li->Target->GetProperties().end(); + != theTarget->GetProperties().end(); PropertyType ifacePropContent = - getTypedProperty<PropertyType>(li->Target, + getTypedProperty<PropertyType>(theTarget, ("INTERFACE_" + p).c_str(), 0); std::string reportEntry; if (ifaceIsSet) { reportEntry += " * Target \""; - reportEntry += li->Target->GetName(); + reportEntry += theTarget->GetName(); reportEntry += "\" property value \""; reportEntry += valueAsString<PropertyType>(ifacePropContent); reportEntry += "\" "; @@ -4602,7 +4494,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, e << "Property " << p << " on target \"" << tgt->GetName() << "\" does\nnot match the " "INTERFACE_" << p << " property requirement\nof " - "dependency \"" << li->Target->GetName() << "\".\n"; + "dependency \"" << theTarget->GetName() << "\".\n"; cmSystemTools::Error(e.str().c_str()); break; } @@ -4636,7 +4528,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, << tgt->GetName() << "\" is\nimplied to be " << defaultValue << " because it was used to determine the link libraries\n" "already. The INTERFACE_" << p << " property on\ndependency \"" - << li->Target->GetName() << "\" is in conflict.\n"; + << theTarget->GetName() << "\" is in conflict.\n"; cmSystemTools::Error(e.str().c_str()); break; } @@ -4667,7 +4559,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, { cmOStringStream e; e << "The INTERFACE_" << p << " property of \"" - << li->Target->GetName() << "\" does\nnot agree with the value " + << theTarget->GetName() << "\" does\nnot agree with the value " "of " << p << " already determined\nfor \"" << tgt->GetName() << "\".\n"; cmSystemTools::Error(e.str().c_str()); @@ -4748,23 +4640,19 @@ bool isLinkDependentProperty(cmTarget const* tgt, const std::string &p, const char *interfaceProperty, const char *config) { - cmComputeLinkInformation *info = tgt->GetLinkInformation(config); - if(!info) + std::vector<cmTarget*> deps; + tgt->GetTransitiveTargetClosure(config, tgt, deps); + + if(deps.empty()) { return false; } - const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); - - for(cmComputeLinkInformation::ItemVector::const_iterator li = + for(std::vector<cmTarget*>::const_iterator li = deps.begin(); li != deps.end(); ++li) { - if (!li->Target) - { - continue; - } - const char *prop = li->Target->GetProperty(interfaceProperty); + const char *prop = (*li)->GetProperty(interfaceProperty); if (!prop) { continue; @@ -5316,24 +5204,124 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config, { // Compute the link interface for this configuration. cmTargetInternals::OptionalLinkInterface iface; - iface.Exists = this->ComputeLinkInterface(config, iface, head); + iface.ExplicitLibraries = + this->ComputeLinkInterfaceLibraries(config, iface, head, iface.Exists); + if (iface.Exists) + { + this->Internal->ComputeLinkInterface(this, config, iface, + head, iface.ExplicitLibraries); + } + + // Store the information for this configuration. + cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface); + i = this->Internal->LinkInterfaceMap.insert(entry).first; + } + else if(!i->second.Complete && i->second.Exists) + { + this->Internal->ComputeLinkInterface(this, config, i->second, head, + i->second.ExplicitLibraries); + } + + return i->second.Exists ? &i->second : 0; +} + +//---------------------------------------------------------------------------- +cmTarget::LinkInterface const* +cmTarget::GetLinkInterfaceLibraries(const char* config, + cmTarget const* head) const +{ + // Imported targets have their own link interface. + if(this->IsImported()) + { + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, head)) + { + return &info->LinkInterface; + } + return 0; + } + + // Link interfaces are not supported for executables that do not + // export symbols. + if(this->GetType() == cmTarget::EXECUTABLE && + !this->IsExecutableWithExports()) + { + return 0; + } + + // Lookup any existing link interface for this configuration. + TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : "")); + + cmTargetInternals::LinkInterfaceMapType::iterator + i = this->Internal->LinkInterfaceMap.find(key); + if(i == this->Internal->LinkInterfaceMap.end()) + { + // Compute the link interface for this configuration. + cmTargetInternals::OptionalLinkInterface iface; + iface.ExplicitLibraries = this->ComputeLinkInterfaceLibraries(config, + iface, + head, + iface.Exists); // Store the information for this configuration. cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface); i = this->Internal->LinkInterfaceMap.insert(entry).first; } - return i->second.Exists? &i->second : 0; + return i->second.Exists ? &i->second : 0; +} + +//---------------------------------------------------------------------------- +void processILibs(const char* config, + cmTarget const* headTarget, + std::string const& name, + std::vector<cmTarget*>& tgts, std::set<cmTarget*>& emitted) +{ + if (cmTarget* tgt = headTarget->GetMakefile() + ->FindTargetToUse(name.c_str())) + { + if (emitted.insert(tgt).second) + { + tgts.push_back(tgt); + std::vector<std::string> ilibs; + cmTarget::LinkInterface const* iface = + tgt->GetLinkInterfaceLibraries(config, headTarget); + if (iface) + { + for(std::vector<std::string>::const_iterator + it = iface->Libraries.begin(); + it != iface->Libraries.end(); ++it) + { + processILibs(config, headTarget, *it, tgts, emitted); + } + } + } + } +} + +//---------------------------------------------------------------------------- +void cmTarget::GetTransitiveTargetClosure(const char* config, + cmTarget const* headTarget, + std::vector<cmTarget*> &tgts) const +{ + std::set<cmTarget*> emitted; + + cmTarget::LinkImplementation const* impl + = this->GetLinkImplementationLibraries(config, headTarget); + + for(std::vector<std::string>::const_iterator it = impl->Libraries.begin(); + it != impl->Libraries.end(); ++it) + { + processILibs(config, headTarget, *it, tgts, emitted); + } } //---------------------------------------------------------------------------- -void cmTarget::GetTransitivePropertyLinkLibraries( - const char* config, +void cmTarget::GetTransitivePropertyTargets(const char* config, cmTarget const* headTarget, - std::vector<std::string> &libs) const + std::vector<cmTarget*> &tgts) const { - cmTarget::LinkInterface const* iface = this->GetLinkInterface(config, - headTarget); + cmTarget::LinkInterface const* iface + = this->GetLinkInterfaceLibraries(config, headTarget); if (!iface) { return; @@ -5342,7 +5330,15 @@ void cmTarget::GetTransitivePropertyLinkLibraries( || this->GetPolicyStatusCMP0022() == cmPolicies::WARN || this->GetPolicyStatusCMP0022() == cmPolicies::OLD) { - libs = iface->Libraries; + for(std::vector<std::string>::const_iterator it = iface->Libraries.begin(); + it != iface->Libraries.end(); ++it) + { + if (cmTarget* tgt = headTarget->GetMakefile() + ->FindTargetToUse(it->c_str())) + { + tgts.push_back(tgt); + } + } return; } @@ -5360,17 +5356,30 @@ void cmTarget::GetTransitivePropertyLinkLibraries( cmGeneratorExpressionDAGChecker dagChecker(lfbt, this->GetName(), linkIfaceProp, 0, 0); dagChecker.SetTransitivePropertiesOnly(); + std::vector<std::string> libs; cmSystemTools::ExpandListArgument(ge.Parse(interfaceLibs)->Evaluate( this->Makefile, config, false, headTarget, this, &dagChecker), libs); + + for(std::vector<std::string>::const_iterator it = libs.begin(); + it != libs.end(); ++it) + { + if (cmTarget* tgt = headTarget->GetMakefile() + ->FindTargetToUse(it->c_str())) + { + tgts.push_back(tgt); + } + } } //---------------------------------------------------------------------------- -bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, - cmTarget const* headTarget) const +const char* cmTarget::ComputeLinkInterfaceLibraries(const char* config, + LinkInterface& iface, + cmTarget const* headTarget, + bool &exists) const { // Construct the property name suffix for this configuration. std::string suffix = "_"; @@ -5446,8 +5455,10 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, (this->GetType() == cmTarget::EXECUTABLE || (this->GetType() == cmTarget::MODULE_LIBRARY))) { - return false; + exists = false; + return 0; } + exists = true; if(explicitLibraries) { @@ -5462,52 +5473,6 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, false, headTarget, this, &dagChecker), iface.Libraries); - - if(this->GetType() == cmTarget::SHARED_LIBRARY - || this->GetType() == cmTarget::STATIC_LIBRARY - || this->GetType() == cmTarget::INTERFACE_LIBRARY) - { - // Shared libraries may have runtime implementation dependencies - // on other shared libraries that are not in the interface. - std::set<cmStdString> emitted; - for(std::vector<std::string>::const_iterator - li = iface.Libraries.begin(); li != iface.Libraries.end(); ++li) - { - emitted.insert(*li); - } - if (this->GetType() != cmTarget::INTERFACE_LIBRARY) - { - LinkImplementation const* impl = this->GetLinkImplementation(config, - headTarget); - for(std::vector<std::string>::const_iterator - li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) - { - if(emitted.insert(*li).second) - { - if(cmTarget* tgt = this->Makefile->FindTargetToUse(*li)) - { - // This is a runtime dependency on another shared library. - if(tgt->GetType() == cmTarget::SHARED_LIBRARY) - { - iface.SharedDeps.push_back(*li); - } - } - else - { - // TODO: Recognize shared library file names. Perhaps this - // should be moved to cmComputeLinkInformation, but that creates - // a chicken-and-egg problem since this list is needed for its - // construction. - } - } - } - if(this->LinkLanguagePropagatesToDependents()) - { - // Targets using this archive need its language runtime libraries. - iface.Languages = impl->Languages; - } - } - } } else if (this->PolicyStatusCMP0022 == cmPolicies::WARN || this->PolicyStatusCMP0022 == cmPolicies::OLD) @@ -5517,17 +5482,9 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, // to the link implementation. { // The link implementation is the default link interface. - LinkImplementation const* impl = this->GetLinkImplementation(config, - headTarget); - iface.ImplementationIsInterface = true; + LinkImplementation const* impl = + this->GetLinkImplementationLibraries(config, headTarget); iface.Libraries = impl->Libraries; - iface.WrongConfigLibraries = impl->WrongConfigLibraries; - if(this->LinkLanguagePropagatesToDependents()) - { - // Targets using this archive need its language runtime libraries. - iface.Languages = impl->Languages; - } - if(this->PolicyStatusCMP0022 == cmPolicies::WARN && !this->Internal->PolicyWarnedCMP0022) { @@ -5592,25 +5549,107 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, } } } + return explicitLibraries; +} - if(this->GetType() == cmTarget::STATIC_LIBRARY) +//---------------------------------------------------------------------------- +void cmTargetInternals::ComputeLinkInterface(cmTarget const* thisTarget, + const char* config, + OptionalLinkInterface& iface, + cmTarget const* headTarget, + const char* explicitLibraries) const +{ + if(explicitLibraries) + { + if(thisTarget->GetType() == cmTarget::SHARED_LIBRARY + || thisTarget->GetType() == cmTarget::STATIC_LIBRARY + || thisTarget->GetType() == cmTarget::INTERFACE_LIBRARY) + { + // Shared libraries may have runtime implementation dependencies + // on other shared libraries that are not in the interface. + std::set<cmStdString> emitted; + for(std::vector<std::string>::const_iterator + li = iface.Libraries.begin(); li != iface.Libraries.end(); ++li) + { + emitted.insert(*li); + } + if (thisTarget->GetType() != cmTarget::INTERFACE_LIBRARY) + { + cmTarget::LinkImplementation const* impl = + thisTarget->GetLinkImplementation(config, headTarget); + for(std::vector<std::string>::const_iterator + li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) + { + if(emitted.insert(*li).second) + { + if(cmTarget* tgt = thisTarget->Makefile->FindTargetToUse(*li)) + { + // This is a runtime dependency on another shared library. + if(tgt->GetType() == cmTarget::SHARED_LIBRARY) + { + iface.SharedDeps.push_back(*li); + } + } + else + { + // TODO: Recognize shared library file names. Perhaps this + // should be moved to cmComputeLinkInformation, but that creates + // a chicken-and-egg problem since this list is needed for its + // construction. + } + } + } + if(thisTarget->LinkLanguagePropagatesToDependents()) + { + // Targets using this archive need its language runtime libraries. + iface.Languages = impl->Languages; + } + } + } + } + else if (thisTarget->PolicyStatusCMP0022 == cmPolicies::WARN + || thisTarget->PolicyStatusCMP0022 == cmPolicies::OLD) + { + // The link implementation is the default link interface. + cmTarget::LinkImplementation const* + impl = thisTarget->GetLinkImplementation(config, headTarget); + iface.ImplementationIsInterface = true; + iface.WrongConfigLibraries = impl->WrongConfigLibraries; + if(thisTarget->LinkLanguagePropagatesToDependents()) + { + // Targets using this archive need its language runtime libraries. + iface.Languages = impl->Languages; + } + } + + if(thisTarget->GetType() == cmTarget::STATIC_LIBRARY) { + // Construct the property name suffix for this configuration. + std::string suffix = "_"; + if(config && *config) + { + suffix += cmSystemTools::UpperCase(config); + } + else + { + suffix += "NOCONFIG"; + } + // How many repetitions are needed if this library has cyclic // dependencies? std::string propName = "LINK_INTERFACE_MULTIPLICITY"; propName += suffix; - if(const char* config_reps = this->GetProperty(propName.c_str())) + if(const char* config_reps = thisTarget->GetProperty(propName.c_str())) { sscanf(config_reps, "%u", &iface.Multiplicity); } else if(const char* reps = - this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) + thisTarget->GetProperty("LINK_INTERFACE_MULTIPLICITY")) { sscanf(reps, "%u", &iface.Multiplicity); } } - - return true; + iface.Complete = true; } //---------------------------------------------------------------------------- @@ -5633,6 +5672,41 @@ cmTarget::GetLinkImplementation(const char* config, cmTarget const* head) const // Compute the link implementation for this configuration. LinkImplementation impl; this->ComputeLinkImplementation(config, impl, head); + this->ComputeLinkImplementationLanguages(impl); + + // Store the information for this configuration. + cmTargetInternals::LinkImplMapType::value_type entry(key, impl); + i = this->Internal->LinkImplMap.insert(entry).first; + } + else if (i->second.Languages.empty()) + { + this->ComputeLinkImplementationLanguages(i->second); + } + + return &i->second; +} + +//---------------------------------------------------------------------------- +cmTarget::LinkImplementation const* +cmTarget::GetLinkImplementationLibraries(const char* config, + cmTarget const* head) const +{ + // There is no link implementation for imported targets. + if(this->IsImported()) + { + return 0; + } + + // Lookup any existing link implementation for this configuration. + TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : "")); + + cmTargetInternals::LinkImplMapType::iterator + i = this->Internal->LinkImplMap.find(key); + if(i == this->Internal->LinkImplMap.end()) + { + // Compute the link implementation for this configuration. + LinkImplementation impl; + this->ComputeLinkImplementation(config, impl, head); // Store the information for this configuration. cmTargetInternals::LinkImplMapType::value_type entry(key, impl); @@ -5715,7 +5789,12 @@ void cmTarget::ComputeLinkImplementation(const char* config, impl.WrongConfigLibraries.push_back(item); } } +} +//---------------------------------------------------------------------------- +void +cmTarget::ComputeLinkImplementationLanguages(LinkImplementation& impl) const +{ // This target needs runtime libraries for its source languages. std::set<cmStdString> languages; // Get languages used in our source files. diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 271824b..5dec9e2 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -140,34 +140,6 @@ 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 - { - 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 - }; - - /** - * Get the flags for a given source file as used in this target - */ - struct SourceFileFlags - GetTargetSourceFileFlags(const cmSourceFile* sf) const; - - /** * Add sources to the target. */ void AddSources(std::vector<std::string> const& srcs); @@ -292,9 +264,14 @@ public: if the target cannot be linked. */ LinkInterface const* GetLinkInterface(const char* config, cmTarget const* headTarget) const; - void GetTransitivePropertyLinkLibraries(const char* config, + LinkInterface const* GetLinkInterfaceLibraries(const char* config, + cmTarget const* headTarget) const; + void GetTransitivePropertyTargets(const char* config, + cmTarget const* headTarget, + std::vector<cmTarget*> &libs) const; + void GetTransitiveTargetClosure(const char* config, cmTarget const* headTarget, - std::vector<std::string> &libs) const; + std::vector<cmTarget*> &libs) const; /** The link implementation specifies the direct library dependencies needed by the object files of the target. */ @@ -313,6 +290,9 @@ public: LinkImplementation const* GetLinkImplementation(const char* config, cmTarget const* head) const; + LinkImplementation const* GetLinkImplementationLibraries(const char* config, + cmTarget const* head) const; + /** Link information from the transitive closure of the link implementation and the interfaces of its dependencies. */ struct LinkClosure @@ -358,11 +338,6 @@ public: void GetTargetVersion(bool soversion, int& major, int& minor, int& patch) const; - /** - * Make sure the full path to all source files is known. - */ - bool FindSourceFiles(); - ///! Return the preferred linker language for this target const char* GetLinkerLanguage(const char* config = 0, cmTarget const* head = 0) const; @@ -723,12 +698,15 @@ private: void CheckPropertyCompatibility(cmComputeLinkInformation *info, const char* config) const; - bool ComputeLinkInterface(const char* config, LinkInterface& iface, - cmTarget const* head) const; + const char* ComputeLinkInterfaceLibraries(const char* config, + LinkInterface& iface, + cmTarget const* head, + bool &exists) const; void ComputeLinkImplementation(const char* config, LinkImplementation& impl, cmTarget const* head) const; + void ComputeLinkImplementationLanguages(LinkImplementation& impl) const; void ComputeLinkClosure(const char* config, LinkClosure& lc, cmTarget const* head) const; @@ -756,7 +734,6 @@ private: friend class cmTargetTraceDependencies; cmTargetInternalPointer Internal; - void ConstructSourceFileFlags() const; void ComputeVersionedName(std::string& vName, std::string const& prefix, std::string const& base, diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index ed7e243..d760b3f 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1666,10 +1666,10 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) linkOptions.AddFlag("ImportLibrary", imLib.c_str()); linkOptions.AddFlag("ProgramDataBaseFile", pdb.c_str()); linkOptions.Parse(flags.c_str()); - if(!this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(!def.empty()) { - linkOptions.AddFlag("ModuleDefinitionFile", - this->GeneratorTarget->ModuleDefinitionFile.c_str()); + linkOptions.AddFlag("ModuleDefinitionFile", def.c_str()); } this->LinkOptions[config] = pOptions.release(); |