diff options
Diffstat (limited to 'Source/cmCMakeLanguageCommand.cxx')
-rw-r--r-- | Source/cmCMakeLanguageCommand.cxx | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx index 27d8cb8..7d05e88 100644 --- a/Source/cmCMakeLanguageCommand.cxx +++ b/Source/cmCMakeLanguageCommand.cxx @@ -13,11 +13,14 @@ #include <cm/string_view> #include <cmext/string_view> +#include "cmArgumentParser.h" +#include "cmDependencyProvider.h" #include "cmExecutionStatus.h" #include "cmGlobalGenerator.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmRange.h" +#include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -215,6 +218,91 @@ bool cmCMakeLanguageCommandEVAL(std::vector<cmListFileArgument> const& args, return makefile.ReadListFileAsString( code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL")); } + +bool cmCMakeLanguageCommandSET_DEPENDENCY_PROVIDER( + std::vector<std::string> const& args, cmExecutionStatus& status) +{ + cmState* state = status.GetMakefile().GetState(); + if (!state->InTopLevelIncludes()) { + return FatalError( + status, + "Dependency providers can only be set as part of the first call to " + "project(). More specifically, cmake_language(SET_DEPENDENCY_PROVIDER) " + "can only be called while the first project() command processes files " + "listed in CMAKE_PROJECT_TOP_LEVEL_INCLUDES."); + } + + struct SetProviderArgs + { + std::string Command; + std::vector<std::string> Methods; + }; + + auto const ArgsParser = + cmArgumentParser<SetProviderArgs>() + .Bind("SET_DEPENDENCY_PROVIDER"_s, &SetProviderArgs::Command) + .Bind("SUPPORTED_METHODS"_s, &SetProviderArgs::Methods); + + std::vector<std::string> unparsed; + auto parsedArgs = ArgsParser.Parse(args, &unparsed); + + if (!unparsed.empty()) { + return FatalError( + status, cmStrCat("Unrecognized keyword: \"", unparsed.front(), "\"")); + } + + // We store the command that FetchContent_MakeAvailable() can call in a + // global (but considered internal) property. If the provider doesn't + // support this method, we set this property to an empty string instead. + // This simplifies the logic in FetchContent_MakeAvailable() and doesn't + // require us to define a new internal command or sub-command. + std::string fcmasProperty = "__FETCHCONTENT_MAKEAVAILABLE_SERIAL_PROVIDER"; + + if (parsedArgs.Command.empty()) { + if (!parsedArgs.Methods.empty()) { + return FatalError(status, + "Must specify a non-empty command name when provider " + "methods are given"); + } + state->ClearDependencyProvider(); + state->SetGlobalProperty(fcmasProperty, ""); + return true; + } + + cmState::Command command = state->GetCommand(parsedArgs.Command); + if (!command) { + return FatalError(status, + cmStrCat("Command \"", parsedArgs.Command, + "\" is not a defined command")); + } + + if (parsedArgs.Methods.empty()) { + return FatalError(status, "Must specify at least one provider method"); + } + + bool supportsFetchContentMakeAvailableSerial = false; + std::vector<cmDependencyProvider::Method> methods; + for (auto const& method : parsedArgs.Methods) { + if (method == "FIND_PACKAGE") { + methods.emplace_back(cmDependencyProvider::Method::FindPackage); + } else if (method == "FETCHCONTENT_MAKEAVAILABLE_SERIAL") { + supportsFetchContentMakeAvailableSerial = true; + methods.emplace_back( + cmDependencyProvider::Method::FetchContentMakeAvailableSerial); + } else { + return FatalError( + status, + cmStrCat("Unknown dependency provider method \"", method, "\"")); + } + } + + state->SetDependencyProvider({ parsedArgs.Command, methods }); + state->SetGlobalProperty( + fcmasProperty, + supportsFetchContentMakeAvailableSerial ? parsedArgs.Command.c_str() : ""); + + return true; +} } bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args, @@ -246,6 +334,11 @@ bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args, return FatalError(status, "called with incorrect number of arguments"); } + if (expArgs[expArg] == "SET_DEPENDENCY_PROVIDER"_s) { + finishArgs(); + return cmCMakeLanguageCommandSET_DEPENDENCY_PROVIDER(expArgs, status); + } + cm::optional<Defer> maybeDefer; if (expArgs[expArg] == "DEFER"_s) { ++expArg; // Consume "DEFER". |