/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_MODULELOADER_H #define QBS_MODULELOADER_H #include "filetags.h" #include "forward_decls.h" #include "item.h" #include "itempool.h" #include "moduleproviderinfo.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { class CodeLocation; class Settings; namespace Internal { class Evaluator; class Item; class ItemReader; class ProgressObserver; class QualifiedId; using ModulePropertiesPerGroup = std::unordered_map; struct ModuleLoaderResult { ModuleLoaderResult() : itemPool(new ItemPool), root(nullptr) {} struct ProductInfo { struct Dependency { QString name; QString profile; // "*" <=> Match all profiles. QString multiplexConfigurationId; QVariantMap parameters; bool limitToSubProject = false; bool isRequired = true; QString uniqueName() const; }; std::vector probes; std::vector usedProducts; ModulePropertiesPerGroup modulePropertiesSetInGroups; ErrorInfo delayedError; }; std::shared_ptr itemPool; Item *root; std::unordered_map productInfos; std::vector projectProbes; ModuleProviderInfoList moduleProviderInfo; Set qbsFiles; QVariantMap profileConfigs; }; /* * Loader stage II. Responsible for * - loading modules and module dependencies, * - project references, * - Probe items. */ class ModuleLoader { public: ModuleLoader(Evaluator *evaluator, Logger &logger); ~ModuleLoader(); void setProgressObserver(ProgressObserver *progressObserver); void setSearchPaths(const QStringList &searchPaths); void setOldProjectProbes(const std::vector &oldProbes); void setOldProductProbes(const QHash> &oldProbes); void setLastResolveTime(const FileTime &time) { m_lastResolveTime = time; } void setStoredProfiles(const QVariantMap &profiles); void setStoredModuleProviderInfo(const ModuleProviderInfoList &moduleProviderInfo); Evaluator *evaluator() const { return m_evaluator; } ModuleLoaderResult load(const SetupProjectParameters ¶meters); private: class ProductSortByDependencies; class ContextBase { public: ContextBase() : item(nullptr), scope(nullptr) {} Item *item; Item *scope; QString name; }; class ProjectContext; using ProductDependencies = std::vector; // This is the data we need to store at the point where a dependency is deferred // in order to properly resolve the dependency in pass 2. struct DeferredDependsContext { DeferredDependsContext(Item *exportingProduct, Item *parent) : exportingProductItem(exportingProduct), parentItem(parent) {} Item *exportingProductItem = nullptr; Item *parentItem = nullptr; bool operator==(const DeferredDependsContext &other) const { return exportingProductItem == other.exportingProductItem && parentItem == other.parentItem; } bool operator<(const DeferredDependsContext &other) const { return parentItem < other.parentItem; } }; class ProductContext : public ContextBase { public: ProjectContext *project = nullptr; ModuleLoaderResult::ProductInfo info; QString profileName; QString multiplexConfigurationId; QVariantMap moduleProperties; std::map productModuleDependencies; std::unordered_map> unknownProfilePropertyErrors; QStringList searchPaths; std::vector newlyAddedModuleProviderSearchPaths; Set knownModuleProviders; std::optional theModuleProviderConfig; // The key corresponds to DeferredDependsContext.exportingProductItem, which is the // only value from that data structure that we still need here. std::unordered_map> deferredDependsItems; QString uniqueName() const; }; class TopLevelProjectContext; class ProjectContext : public ContextBase { public: TopLevelProjectContext *topLevelProject = nullptr; ModuleLoaderResult *result = nullptr; std::vector products; std::vector searchPathsStack; }; struct ProductModuleInfo { Item *exportItem = nullptr; QString multiplexId; QVariantMap defaultParameters; }; class TopLevelProjectContext { Q_DISABLE_COPY(TopLevelProjectContext) public: TopLevelProjectContext() = default; ~TopLevelProjectContext() { qDeleteAll(projects); } std::vector projects; QMultiHash productModules; std::vector probes; QString buildDirectory; }; class DependsContext { public: ProductContext *product = nullptr; Item *exportingProductItem = nullptr; ProductDependencies *productDependencies = nullptr; }; void handleTopLevelProject(ModuleLoaderResult *loadResult, Item *projectItem, const QString &buildDirectory, const Set &referencedFilePaths); void handleProject(ModuleLoaderResult *loadResult, TopLevelProjectContext *topLevelProjectContext, Item *projectItem, const Set &referencedFilePaths); using MultiplexRow = std::vector; using MultiplexTable = std::vector; struct MultiplexInfo { std::vector properties; MultiplexTable table; bool aggregate = false; VariantValuePtr multiplexedType; QString toIdString(size_t row) const; static QVariantMap multiplexIdToVariantMap(const QString &multiplexId); }; void dump(const MultiplexInfo &mpi); static MultiplexTable combine(const MultiplexTable &table, const MultiplexRow &values); MultiplexInfo extractMultiplexInfo(Item *productItem, Item *qbsModuleItem); QList multiplexProductItem(ProductContext *dummyContext, Item *productItem); void normalizeDependencies(ProductContext *product, const DeferredDependsContext &dependsContext); void adjustDependenciesForMultiplexing(const TopLevelProjectContext &tlp); void adjustDependenciesForMultiplexing(const ProductContext &product); void adjustDependenciesForMultiplexing(const ProductContext &product, Item *dependsItem); void prepareProduct(ProjectContext *projectContext, Item *productItem); void setupProductDependencies(ProductContext *productContext, const Set &deferredDependsContext); void handleProduct(ProductContext *productContext); void checkDependencyParameterDeclarations(const ProductContext *productContext) const; void handleModuleSetupError(ProductContext *productContext, const Item::Module &module, const ErrorInfo &error); void initProductProperties(const ProductContext &product); void handleSubProject(ProjectContext *projectContext, Item *projectItem, const Set &referencedFilePaths); QList loadReferencedFile(const QString &relativePath, const CodeLocation &referencingLocation, const Set &referencedFilePaths, ProductContext &dummyContext); void handleAllPropertyOptionsItems(Item *item); void handlePropertyOptions(Item *optionsItem); using ModuleDependencies = QHash; void setupReverseModuleDependencies(const Item::Module &module, ModuleDependencies &deps, QualifiedIdSet &seenModules); ModuleDependencies setupReverseModuleDependencies(const Item *product); void handleGroup(ProductContext *productContext, Item *groupItem, const ModuleDependencies &reverseDepencencies); void propagateModulesFromParent(ProductContext *productContext, Item *groupItem, const ModuleDependencies &reverseDepencencies); void adjustDefiningItemsInGroupModuleInstances(const Item::Module &module, const Item::Modules &dependentModules); bool mergeExportItems(const ProductContext &productContext); void resolveDependencies(DependsContext *dependsContext, Item *item, ProductContext *productContext = nullptr); class ItemModuleList; void resolveDependsItem(DependsContext *dependsContext, Item *parentItem, Item *dependsItem, ItemModuleList *moduleResults, ProductDependencies *productResults); void forwardParameterDeclarations(const Item *dependsItem, const ItemModuleList &modules); void forwardParameterDeclarations(const QualifiedId &moduleName, Item *item, const ItemModuleList &modules); void resolveParameterDeclarations(const Item *module); QVariantMap extractParameters(Item *dependsItem) const; Item *moduleInstanceItem(Item *containerItem, const QualifiedId &moduleName); static ProductModuleInfo *productModule(ProductContext *productContext, const QString &name, const QString &multiplexId, bool &productNameMatch); static ProductContext *product(ProjectContext *projectContext, const QString &name); static ProductContext *product(TopLevelProjectContext *tlpContext, const QString &name); enum class FallbackMode { Enabled, Disabled }; Item *loadModule(ProductContext *productContext, Item *exportingProductItem, Item *item, const CodeLocation &dependsItemLocation, const QString &moduleId, const QualifiedId &moduleName, const QString &multiplexId, FallbackMode fallbackMode, bool isRequired, bool *isProductDependency, QVariantMap *defaultParameters); Item *searchAndLoadModuleFile(ProductContext *productContext, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, FallbackMode fallbackMode, bool isRequired, Item *moduleInstance); QStringList &getModuleFileNames(const QString &dirPath); std::pair loadModuleFile( ProductContext *productContext, const QString &fullModuleName, const QString &filePath, Item *moduleInstance); std::pair getModulePrototype(ProductContext *productContext, const QString &fullModuleName, const QString &filePath); Item::Module loadBaseModule(ProductContext *productContext, Item *item); void setupBaseModulePrototype(Item *prototype); template T callWithTemporaryBaseModule(ProductContext *productContext, const F &func); void instantiateModule(ProductContext *productContext, Item *exportingProductItem, Item *instanceScope, Item *moduleInstance, Item *modulePrototype, const QualifiedId &moduleName, ProductModuleInfo *productModuleInfo); void createChildInstances(Item *instance, Item *prototype, QHash *prototypeInstanceMap) const; void resolveProbes(ProductContext *productContext, Item *item); void resolveProbe(ProductContext *productContext, Item *parent, Item *probe); void checkCancelation() const; bool checkItemCondition(Item *item, Item *itemToDisable = nullptr); QStringList readExtraSearchPaths(Item *item, bool *wasSet = nullptr); void copyProperties(const Item *sourceProject, Item *targetProject); Item *wrapInProjectIfNecessary(Item *item); QString findExistingModulePath(const QString &searchPath, const QualifiedId &moduleName); QStringList findExistingModulePaths( const QStringList &searchPaths, const QualifiedId &moduleName); enum class ModuleProviderLookup { Regular, Fallback }; struct ModuleProviderResult { ModuleProviderResult() = default; ModuleProviderResult(bool ran, bool added) : providerFound(ran), providerAddedSearchPaths(added) {} bool providerFound = false; bool providerAddedSearchPaths = false; }; ModuleProviderResult findModuleProvider(const QualifiedId &name, ProductContext &product, ModuleProviderLookup lookupType, const CodeLocation &dependsItemLocation); QVariantMap moduleProviderConfig(ProductContext &product); static void setScopeForDescendants(Item *item, Item *scope); void overrideItemProperties(Item *item, const QString &buildConfigKey, const QVariantMap &buildConfig); void addProductModuleDependencies(ProductContext *ctx, const QString &name); void addProductModuleDependencies(ProductContext *ctx); void addTransitiveDependencies(ProductContext *ctx); Item *createNonPresentModule(const QString &name, const QString &reason, Item *module); void copyGroupsFromModuleToProduct(const ProductContext &productContext, const Item::Module &module, const Item *modulePrototype); void copyGroupsFromModulesToProduct(const ProductContext &productContext); void markModuleTargetGroups(Item *group, const Item::Module &module); bool checkExportItemCondition(Item *exportItem, const ProductContext &productContext); ProbeConstPtr findOldProjectProbe(const QString &globalId, bool condition, const QVariantMap &initialProperties, const QString &sourceCode) const; ProbeConstPtr findOldProductProbe(const QString &productName, bool condition, const QVariantMap &initialProperties, const QString &sourceCode) const; ProbeConstPtr findCurrentProbe(const CodeLocation &location, bool condition, const QVariantMap &initialProperties) const; enum class CompareScript { No, Yes }; bool probeMatches(const ProbeConstPtr &probe, bool condition, const QVariantMap &initialProperties, const QString &configureScript, CompareScript compareScript) const; void printProfilingInfo(); void handleProductError(const ErrorInfo &error, ProductContext *productContext); QualifiedIdSet gatherModulePropertiesSetInGroup(const Item *group); Item *loadItemFromFile(const QString &filePath, const CodeLocation &referencingLocation); void collectProductsByName(const TopLevelProjectContext &topLevelProject); void collectProductsByType(const TopLevelProjectContext &topLevelProject); void handleProfileItems(Item *item, ProjectContext *projectContext); std::vector collectProfileItems(Item *item, ProjectContext *projectContext); void evaluateProfileValues(const QualifiedId &namePrefix, Item *item, Item *profileItem, QVariantMap &values); void handleProfile(Item *profileItem); void collectNameFromOverride(const QString &overrideString); void checkProjectNamesInOverrides(const TopLevelProjectContext &tlp); void checkProductNamesInOverrides(); void setSearchPathsForProduct(ProductContext *product); Item::Modules modulesSortedByDependency(const Item *productItem); void createSortedModuleList(const Item::Module &parentModule, Item::Modules &modules); void collectAllModules(Item *item, std::vector *modules); std::vector allModules(Item *item); bool moduleRepresentsDisabledProduct(const Item::Module &module); using ShadowProductInfo = std::pair; ShadowProductInfo getShadowProductInfo(const ProductContext &product) const; ItemPool *m_pool; Logger &m_logger; ProgressObserver *m_progressObserver; const std::unique_ptr m_reader; Evaluator *m_evaluator; QMap m_moduleDirListCache; QHash, std::optional> m_existingModulePathCache; // The keys are file paths, the values are module prototype items accompanied by a profile. std::unordered_map>> m_modulePrototypes; // The keys are module prototypes and products, the values specify whether the module's // condition is true for that product. QHash, bool> m_modulePrototypeEnabledInfo; QHash m_parameterDeclarations; Set m_disabledItems; std::vector m_requiredChain; struct DependsChainEntry { DependsChainEntry(QualifiedId name, const CodeLocation &location) : name(std::move(name)), location(location) { } QualifiedId name; CodeLocation location; bool isProduct = false; }; class DependsChainManager; std::vector m_dependsChain; QHash> m_oldProjectProbes; QHash> m_oldProductProbes; FileTime m_lastResolveTime; QHash> m_currentProbes; QVariantMap m_storedProfiles; QVariantMap m_localProfiles; std::multimap m_productsByName; std::multimap m_productsByType; std::unordered_map> m_productsWithDeferredDependsItems; Set m_exportsWithDeferredDependsItems; ModuleProviderInfoList m_moduleProviderInfo; Set m_tempQbsFiles; SetupProjectParameters m_parameters; std::unique_ptr m_settings; Version m_qbsVersion; Item *m_tempScopeItem = nullptr; qint64 m_elapsedTimeProbes = 0; qint64 m_elapsedTimePrepareProducts = 0; qint64 m_elapsedTimeProductDependencies = 0; qint64 m_elapsedTimeTransitiveDependencies = 0; qint64 m_elapsedTimeHandleProducts = 0; qint64 m_elapsedTimePropertyChecking = 0; quint64 m_probesEncountered = 0; quint64 m_probesRun = 0; quint64 m_probesCachedCurrent = 0; quint64 m_probesCachedOld = 0; Set m_projectNamesUsedInOverrides; Set m_productNamesUsedInOverrides; Set m_disabledProjects; Set m_erroneousProducts; int m_dependencyResolvingPass = 0; }; } // namespace Internal } // namespace qbs QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(qbs::Internal::ModuleLoaderResult::ProductInfo, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(qbs::Internal::ModuleLoaderResult::ProductInfo::Dependency, Q_MOVABLE_TYPE); QT_END_NAMESPACE #endif // QBS_MODULELOADER_H