/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #ifndef cmLocalGenerator_h #define cmLocalGenerator_h #include "cmConfigure.h" // IWYU pragma: keep #include #include #include #include #include #include #include #include "cm_kwiml.h" #include "cmCustomCommandTypes.h" #include "cmListFileCache.h" #include "cmMessageType.h" #include "cmOutputConverter.h" #include "cmPolicies.h" #include "cmStateSnapshot.h" class cmComputeLinkInformation; class cmCustomCommandGenerator; class cmCustomCommandLines; class cmGeneratorTarget; class cmGlobalGenerator; class cmImplicitDependsList; class cmLinkLineComputer; class cmMakefile; class cmRulePlaceholderExpander; class cmSourceFile; class cmState; class cmTarget; class cmake; /** \class cmLocalGenerator * \brief Create required build files for a directory. * * Subclasses of this abstract class generate makefiles, DSP, etc for various * platforms. This class should never be constructed directly. A * GlobalGenerator will create it and invoke the appropriate commands on it. */ class cmLocalGenerator : public cmOutputConverter { public: cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile); virtual ~cmLocalGenerator(); /** * Generate the makefile for this directory. */ virtual void Generate() {} virtual void ComputeHomeRelativeOutputPath() {} /** * Calls TraceVSDependencies() on all targets of this generator. */ void TraceDependencies(); virtual void AddHelperCommands() {} /** * Generate the install rules files in this directory. */ void GenerateInstallRules(); /** * Generate the test files for tests. */ void GenerateTestFiles(); /** * Generate a manifest of target files that will be built. */ void ComputeTargetManifest(); bool ComputeTargetCompileFeatures(); bool IsRootMakefile() const; //! Get the makefile for this generator cmMakefile* GetMakefile() { return this->Makefile; } //! Get the makefile for this generator, const version const cmMakefile* GetMakefile() const { return this->Makefile; } //! Get the GlobalGenerator this is associated with cmGlobalGenerator* GetGlobalGenerator() { return this->GlobalGenerator; } const cmGlobalGenerator* GetGlobalGenerator() const { return this->GlobalGenerator; } virtual cmRulePlaceholderExpander* CreateRulePlaceholderExpander() const; std::string GetLinkLibsCMP0065(std::string const& linkLanguage, cmGeneratorTarget& tgt) const; cmState* GetState() const; cmStateSnapshot GetStateSnapshot() const; void AddArchitectureFlags(std::string& flags, cmGeneratorTarget const* target, const std::string& lang, const std::string& config, const std::string& filterArch = std::string()); void AddLanguageFlags(std::string& flags, cmGeneratorTarget const* target, const std::string& lang, const std::string& config); void AddLanguageFlagsForLinking(std::string& flags, cmGeneratorTarget const* target, const std::string& lang, const std::string& config); void AddCMP0018Flags(std::string& flags, cmGeneratorTarget const* target, std::string const& lang, const std::string& config); void AddVisibilityPresetFlags(std::string& flags, cmGeneratorTarget const* target, const std::string& lang); void AddConfigVariableFlags(std::string& flags, const std::string& var, const std::string& config); void AddCompilerRequirementFlag(std::string& flags, cmGeneratorTarget const* target, const std::string& lang); //! Append flags to a string. virtual void AppendFlags(std::string& flags, const std::string& newFlags) const; virtual void AppendFlags(std::string& flags, const std::vector>& newFlags) const; virtual void AppendFlagEscape(std::string& flags, const std::string& rawFlag) const; void AddPchDependencies(cmGeneratorTarget* target); void AddUnityBuild(cmGeneratorTarget* target); void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target, const std::string& config, const std::string& lang); void AppendPositionIndependentLinkerFlags(std::string& flags, cmGeneratorTarget* target, const std::string& config, const std::string& lang); //! Get the include flags for the current makefile and language std::string GetIncludeFlags(const std::vector& includes, cmGeneratorTarget* target, const std::string& lang, bool forceFullPaths = false, bool forResponseFile = false, const std::string& config = ""); using GeneratorTargetVector = std::vector>; const GeneratorTargetVector& GetGeneratorTargets() const { return this->GeneratorTargets; } void AddGeneratorTarget(std::unique_ptr gt); void AddImportedGeneratorTarget(cmGeneratorTarget* gt); void AddOwnedImportedGeneratorTarget(std::unique_ptr gt); cmGeneratorTarget* FindLocalNonAliasGeneratorTarget( const std::string& name) const; cmGeneratorTarget* FindGeneratorTargetToUse(const std::string& name) const; /** * Process a list of include directories */ void AppendIncludeDirectories(std::vector& includes, std::string const& includes_list, const cmSourceFile& sourceFile) const; void AppendIncludeDirectories(std::vector& includes, const std::vector& includes_vec, const cmSourceFile& sourceFile) const; /** * Encode a list of preprocessor definitions for the compiler * command line. */ void AppendDefines(std::set& defines, std::string const& defines_list) const; void AppendDefines(std::set>& defines, std::string const& defines_list) const; void AppendDefines(std::set>& defines, const std::vector>& defines_vec) const; /** * Encode a list of compile options for the compiler * command line. */ void AppendCompileOptions(std::string& options, std::string const& options_list, const char* regex = nullptr) const; void AppendCompileOptions(std::string& options, const std::vector& options_vec, const char* regex = nullptr) const; void AppendCompileOptions(std::vector>& options, const std::vector>& options_vec, const char* regex = nullptr) const; /** * Join a set of defines into a definesString with a space separator. */ void JoinDefines(const std::set& defines, std::string& definesString, const std::string& lang); /** Lookup and append options associated with a particular feature. */ void AppendFeatureOptions(std::string& flags, const std::string& lang, const char* feature); const char* GetFeature(const std::string& feature, const std::string& config); /** \brief Get absolute path to dependency \a name * * Translate a dependency as given in CMake code to the name to * appear in a generated build file. * - If \a name is a utility target, returns false. * - If \a name is a CMake target, it will be transformed to the real output * location of that target for the given configuration. * - If \a name is the full path to a file, it will be returned. * - Otherwise \a name is treated as a relative path with respect to * the source directory of this generator. This should only be * used for dependencies of custom commands. */ bool GetRealDependency(const std::string& name, const std::string& config, std::string& dep); virtual std::string ConvertToIncludeReference( std::string const& path, cmOutputConverter::OutputFormat format = cmOutputConverter::SHELL, bool forceFullPaths = false); /** Called from command-line hook to clear dependencies. */ virtual void ClearDependencies(cmMakefile* /* mf */, bool /* verbose */) {} /** Called from command-line hook to update dependencies. */ virtual bool UpdateDependencies(const std::string& /* tgtInfo */, bool /*verbose*/, bool /*color*/) { return true; } /** @brief Get the include directories for the current makefile and language * and optional the compiler implicit include directories. * * @arg stripImplicitDirs Strip all directories found in * CMAKE__IMPLICIT_INCLUDE_DIRECTORIES from the result. * @arg appendAllImplicitDirs Append all directories found in * CMAKE__IMPLICIT_INCLUDE_DIRECTORIES to the result. */ std::vector> GetIncludeDirectoriesImplicit( cmGeneratorTarget const* target, std::string const& lang = "C", std::string const& config = "", bool stripImplicitDirs = true, bool appendAllImplicitDirs = false) const; /** @brief Get the include directories for the current makefile and language * and optional the compiler implicit include directories. * * @arg dirs Directories are appended to this list */ void GetIncludeDirectoriesImplicit(std::vector& dirs, cmGeneratorTarget const* target, const std::string& lang = "C", const std::string& config = "", bool stripImplicitDirs = true, bool appendAllImplicitDirs = false) const; /** @brief Get the include directories for the current makefile and language. * @arg dirs Include directories are appended to this list */ void GetIncludeDirectories(std::vector& dirs, cmGeneratorTarget const* target, const std::string& lang = "C", const std::string& config = "") const; /** @brief Get the include directories for the current makefile and language. * @return The include directory list */ std::vector> GetIncludeDirectories( cmGeneratorTarget const* target, std::string const& lang = "C", std::string const& config = "") const; void AddCompileOptions(std::string& flags, cmGeneratorTarget* target, const std::string& lang, const std::string& config); void AddCompileOptions(std::vector>& flags, cmGeneratorTarget* target, const std::string& lang, const std::string& config); /** * Add a custom PRE_BUILD, PRE_LINK, or POST_BUILD command to a target. */ cmTarget* AddCustomCommandToTarget( const std::string& target, const std::vector& byproducts, const std::vector& depends, const cmCustomCommandLines& commandLines, cmCustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle = true, bool uses_terminal = false, const std::string& depfile = "", const std::string& job_pool = "", bool command_expand_lists = false, cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject, bool stdPipesUTF8 = false); /** * Add a custom command to a source file. */ cmSourceFile* AddCustomCommandToOutput( const std::string& output, const std::vector& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace = false, bool escapeOldStyle = true, bool uses_terminal = false, bool command_expand_lists = false, const std::string& depfile = "", const std::string& job_pool = "", bool stdPipesUTF8 = false); cmSourceFile* AddCustomCommandToOutput( const std::vector& outputs, const std::vector& byproducts, const std::vector& depends, const std::string& main_dependency, const cmImplicitDependsList& implicit_depends, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace = false, bool escapeOldStyle = true, bool uses_terminal = false, bool command_expand_lists = false, const std::string& depfile = "", const std::string& job_pool = "", bool stdPipesUTF8 = false); /** * Add a utility to the build. A utility target is a command that is run * every time the target is built. */ cmTarget* AddUtilityCommand( const std::string& utilityName, bool excludeFromAll, const char* workingDir, const std::vector& byproducts, const std::vector& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle = true, const char* comment = nullptr, bool uses_terminal = false, bool command_expand_lists = false, const std::string& job_pool = "", bool stdPipesUTF8 = false); std::string GetProjectName() const; /** Compute the language used to compile the given source file. */ std::string GetSourceFileLanguage(const cmSourceFile& source); // Fill the vector with the target names for the object files, // preprocessed files and assembly files. void GetIndividualFileTargets(std::vector&) {} /** * Get the relative path from the generator output directory to a * per-target support directory. */ virtual std::string GetTargetDirectory( cmGeneratorTarget const* target) const; /** * Get the level of backwards compatibility requested by the project * in this directory. This is the value of the CMake variable * CMAKE_BACKWARDS_COMPATIBILITY whose format is * "major.minor[.patch]". The returned integer is encoded as * * CMake_VERSION_ENCODE(major, minor, patch) * * and is monotonically increasing with the CMake version. */ KWIML_INT_uint64_t GetBackwardsCompatibility(); /** * Test whether compatibility is set to a given version or lower. */ bool NeedBackwardsCompatibility_2_4(); cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id) const; cmake* GetCMakeInstance() const; std::string const& GetSourceDirectory() const; std::string const& GetBinaryDirectory() const; std::string const& GetCurrentBinaryDirectory() const; std::string const& GetCurrentSourceDirectory() const; /** * Convert the given remote path to a relative path with respect to * the given local path. Both paths must use forward slashes and not * already be escaped or quoted. * The conversion is skipped if the paths are not both in the source * or both in the binary tree. */ std::string MaybeConvertToRelativePath(std::string const& local_path, std::string const& remote_path) const; /** * Generate a macOS application bundle Info.plist file. */ void GenerateAppleInfoPList(cmGeneratorTarget* target, const std::string& targetName, const std::string& fname); /** * Generate a macOS framework Info.plist file. */ void GenerateFrameworkInfoPList(cmGeneratorTarget* target, const std::string& targetName, const std::string& fname); /** Construct a comment for a custom command. */ std::string ConstructComment(cmCustomCommandGenerator const& ccg, const char* default_comment = ""); // Compute object file names. std::string GetObjectFileNameWithoutTarget( const cmSourceFile& source, std::string const& dir_max, bool* hasSourceExtension = nullptr, char const* customOutputExtension = nullptr); /** Fill out the static linker flags for the given target. */ void GetStaticLibraryFlags(std::string& flags, std::string const& config, std::string const& linkLanguage, cmGeneratorTarget* target); std::vector> GetStaticLibraryFlags( std::string const& config, std::string const& linkLanguage, cmGeneratorTarget* target); /** Fill out these strings for the given target. Libraries to link, * flags, and linkflags. */ void GetDeviceLinkFlags(cmLinkLineComputer* linkLineComputer, const std::string& config, std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget* target); void GetTargetFlags(cmLinkLineComputer* linkLineComputer, const std::string& config, std::string& linkLibs, std::string& flags, std::string& linkFlags, std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget* target); void GetTargetFlags( cmLinkLineComputer* linkLineComputer, const std::string& config, std::vector>& linkLibs, std::string& flags, std::vector>& linkFlags, std::string& frameworkPath, std::vector>& linkPath, cmGeneratorTarget* target); void GetTargetDefines(cmGeneratorTarget const* target, std::string const& config, std::string const& lang, std::set& defines) const; std::set> GetTargetDefines(cmGeneratorTarget const* target, std::string const& config, std::string const& lang) const; void GetTargetCompileFlags(cmGeneratorTarget* target, std::string const& config, std::string const& lang, std::string& flags, std::string const& arch = std::string()); std::vector> GetTargetCompileFlags( cmGeneratorTarget* target, std::string const& config, std::string const& lang, std::string const& arch = std::string()); std::string GetFrameworkFlags(std::string const& l, std::string const& config, cmGeneratorTarget* target); virtual std::string GetTargetFortranFlags(cmGeneratorTarget const* target, std::string const& config); virtual void ComputeObjectFilenames( std::map& mapping, cmGeneratorTarget const* gt = nullptr); bool IsWindowsShell() const; bool IsWatcomWMake() const; bool IsMinGWMake() const; bool IsNMake() const; bool IsNinjaMulti() const; void IssueMessage(MessageType t, std::string const& text) const; void CreateEvaluationFileOutputs(); void CreateEvaluationFileOutputs(const std::string& config); void ProcessEvaluationFiles(std::vector& generatedFiles); const char* GetRuleLauncher(cmGeneratorTarget* target, const std::string& prop); protected: //! put all the libraries for a target on into the given stream void OutputLinkLibraries(cmComputeLinkInformation* pcli, cmLinkLineComputer* linkLineComputer, std::string& linkLibraries, std::string& frameworkPath, std::string& linkPath); void OutputLinkLibraries(cmComputeLinkInformation* pcli, cmLinkLineComputer* linkLineComputer, std::vector>& linkLibraries, std::string& frameworkPath, std::vector>& linkPath); // Handle old-style install rules stored in the targets. void GenerateTargetInstallRules( std::ostream& os, const std::string& config, std::vector const& configurationTypes); std::string& CreateSafeUniqueObjectFileName(const std::string& sin, std::string const& dir_max); /** Check whether the native build system supports the given definition. Issues a warning. */ virtual bool CheckDefinition(std::string const& define) const; cmMakefile* Makefile; cmStateSnapshot StateSnapshot; cmListFileBacktrace DirectoryBacktrace; cmGlobalGenerator* GlobalGenerator; std::map UniqueObjectNamesMap; std::string::size_type ObjectPathMax; std::set ObjectMaxPathViolations; std::set EnvCPATH; using GeneratorTargetMap = std::unordered_map; GeneratorTargetMap GeneratorTargetSearchIndex; GeneratorTargetVector GeneratorTargets; std::set WarnCMP0063; GeneratorTargetMap ImportedGeneratorTargets; GeneratorTargetVector OwnedImportedGeneratorTargets; std::map AliasTargets; std::map Compilers; std::map VariableMappings; std::string CompilerSysroot; std::string LinkerSysroot; std::unordered_map AppleArchSysroots; bool EmitUniversalBinaryFlags; KWIML_INT_uint64_t BackwardsCompatibility; bool BackwardsCompatibilityFinal; private: void AddSharedFlags(std::string& flags, const std::string& lang, bool shared); bool GetShouldUseOldFlags(bool shared, const std::string& lang) const; void AddPositionIndependentFlags(std::string& flags, std::string const& l, int targetType); void ComputeObjectMaxPath(); }; #if !defined(CMAKE_BOOTSTRAP) bool cmLocalGeneratorCheckObjectName(std::string& objName, std::string::size_type dir_len, std::string::size_type max_total_len); #endif namespace detail { void AddCustomCommandToTarget(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, cmCommandOrigin origin, cmTarget* target, const std::vector& byproducts, const std::vector& depends, const cmCustomCommandLines& commandLines, cmCustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle, bool uses_terminal, const std::string& depfile, const std::string& job_pool, bool command_expand_lists, bool stdPipesUTF8); cmSourceFile* AddCustomCommandToOutput( cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, cmCommandOrigin origin, const std::vector& outputs, const std::vector& byproducts, const std::vector& depends, const std::string& main_dependency, const cmImplicitDependsList& implicit_depends, const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace, bool escapeOldStyle, bool uses_terminal, bool command_expand_lists, const std::string& depfile, const std::string& job_pool, bool stdPipesUTF8); void AppendCustomCommandToOutput(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, const std::string& output, const std::vector& depends, const cmImplicitDependsList& implicit_depends, const cmCustomCommandLines& commandLines); void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, cmCommandOrigin origin, cmTarget* target, const cmUtilityOutput& force, const char* workingDir, const std::vector& byproducts, const std::vector& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle, const char* comment, bool uses_terminal, bool command_expand_lists, const std::string& job_pool, bool stdPipesUTF8); } #endif