diff options
author | Brad King <brad.king@kitware.com> | 2023-08-07 15:56:46 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2023-08-07 15:57:00 (GMT) |
commit | efb21962fbb64a4a8b415c26ab50d60ef0af3ad3 (patch) | |
tree | 7559df765b57b8ac9252bb78f06d46d2a02489a2 /Source | |
parent | e468a6dd407b5cc44c504de521b8c8b94c3f5525 (diff) | |
parent | be53c7585281e67ba06969e2f83aa487579d1daa (diff) | |
download | CMake-efb21962fbb64a4a8b415c26ab50d60ef0af3ad3.zip CMake-efb21962fbb64a4a8b415c26ab50d60ef0af3ad3.tar.gz CMake-efb21962fbb64a4a8b415c26ab50d60ef0af3ad3.tar.bz2 |
Merge topic 'cxxmodules-try-compile'
be53c75852 cmExperimental: recycle the C++ modules API UUID
deb1c3cbd5 cmCoreTryCompile: forward module-related binutils variables
b768d293c5 cmCoreTryCompile: use the source type context for source files
93993c7ad4 cmArgumentParser: support storing a context value with parsing
c9ca5f6326 cmCoreTryCompile: parse `SOURCES_TYPE` argument
07551f35de cmCoreTryCompile: use `target_sources` for `try_compile` targets
aad9033b56 cmExperimental: support forwarding associated variables to `try_compile`
f6cf433256 cmExperimental: only forward C++ module support to non-ABI checks
...
Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Merge-request: !8639
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmArgumentParser.h | 32 | ||||
-rw-r--r-- | Source/cmCoreTryCompile.cxx | 126 | ||||
-rw-r--r-- | Source/cmCoreTryCompile.h | 33 | ||||
-rw-r--r-- | Source/cmExperimental.cxx | 15 | ||||
-rw-r--r-- | Source/cmExperimental.h | 11 |
5 files changed, 186 insertions, 31 deletions
diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index fdf54fb..b35d7f3 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -7,6 +7,7 @@ #include <cassert> #include <cstddef> #include <functional> +#include <iterator> #include <map> #include <string> #include <utility> @@ -176,6 +177,17 @@ public: void Bind(MaybeEmpty<std::vector<std::string>>& val); void Bind(NonEmpty<std::vector<std::string>>& val); void Bind(std::vector<std::vector<std::string>>& val); + template <typename U> + void Bind(NonEmpty<std::vector<std::pair<std::string, U>>>& val, + U const& context) + { + this->Bind( + [&val, &context](cm::string_view arg) -> Continue { + val.emplace_back(std::string(arg), context); + return Continue::Yes; + }, + ExpectAtLeast{ 1 }); + } // cm::optional<> records the presence the keyword to which it binds. template <typename T> @@ -187,6 +199,15 @@ public: this->Bind(*optVal); } + template <typename T, typename U> + void Bind(cm::optional<T>& optVal, U const& context) + { + if (!optVal) { + optVal.emplace(); + } + this->Bind(*optVal, context); + } + template <typename Range> void Parse(Range const& args, std::size_t pos = 0) { @@ -232,6 +253,17 @@ public: return *this; } + template <typename T, typename U> + cmArgumentParser& BindWithContext(cm::static_string_view name, + T Result::*member, U Result::*context) + { + this->Base::Bind(name, [member, context](Instance& instance) { + auto* result = static_cast<Result*>(instance.Result); + instance.Bind(result->*member, result->*context); + }); + return *this; + } + cmArgumentParser& Bind(cm::static_string_view name, Continue (Result::*member)(cm::string_view), ExpectAtLeast expect = { 1 }) diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index cddbb9b..2ec62d9 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -167,7 +167,9 @@ auto const TryCompileBaseArgParser = auto const TryCompileBaseSourcesArgParser = cmArgumentParser<Arguments>{ TryCompileBaseArgParser } - .Bind("SOURCES"_s, &Arguments::Sources) + .Bind("SOURCES_TYPE"_s, &Arguments::SetSourceType) + .BindWithContext("SOURCES"_s, &Arguments::Sources, + &Arguments::SourceTypeContext) .Bind("COMPILE_DEFINITIONS"_s, TryCompileCompileDefs, ArgumentParser::ExpectAtLeast{ 0 }) .Bind("LINK_LIBRARIES"_s, &Arguments::LinkLibraries) @@ -184,9 +186,12 @@ auto const TryCompileBaseSourcesArgParser = auto const TryCompileBaseNewSourcesArgParser = cmArgumentParser<Arguments>{ TryCompileBaseSourcesArgParser } - .Bind("SOURCE_FROM_CONTENT"_s, &Arguments::SourceFromContent) - .Bind("SOURCE_FROM_VAR"_s, &Arguments::SourceFromVar) - .Bind("SOURCE_FROM_FILE"_s, &Arguments::SourceFromFile) + .BindWithContext("SOURCE_FROM_CONTENT"_s, &Arguments::SourceFromContent, + &Arguments::SourceTypeContext) + .BindWithContext("SOURCE_FROM_VAR"_s, &Arguments::SourceFromVar, + &Arguments::SourceTypeContext) + .BindWithContext("SOURCE_FROM_FILE"_s, &Arguments::SourceFromFile, + &Arguments::SourceTypeContext) /* keep semicolon on own line */; auto const TryCompileBaseProjectArgParser = @@ -221,12 +226,44 @@ auto const TryRunOldArgParser = makeTryRunParser(TryCompileOldArgParser); std::string const TryCompileDefaultConfig = "DEBUG"; } +ArgumentParser::Continue cmCoreTryCompile::Arguments::SetSourceType( + cm::string_view sourceType) +{ + bool matched = false; + if (sourceType == "NORMAL"_s) { + this->SourceTypeContext = SourceType::Normal; + matched = true; + } else if (sourceType == "CXX_MODULE"_s) { + bool const supportCxxModuleSources = cmExperimental::HasSupportEnabled( + *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi); + if (supportCxxModuleSources) { + this->SourceTypeContext = SourceType::CxxModule; + matched = true; + } + } + + if (!matched && this->SourceTypeError.empty()) { + bool const supportCxxModuleSources = cmExperimental::HasSupportEnabled( + *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi); + auto const* message = "'SOURCE'"; + if (supportCxxModuleSources) { + message = "one of 'SOURCE' or 'CXX_MODULE'"; + } + // Only remember one error at a time; all other errors related to argument + // parsing are "indicate one error and return" anyways. + this->SourceTypeError = + cmStrCat("Invalid 'SOURCE_TYPE' '", sourceType, "'; must be ", message); + } + return ArgumentParser::Continue::Yes; +} + Arguments cmCoreTryCompile::ParseArgs( const cmRange<std::vector<std::string>::const_iterator>& args, const cmArgumentParser<Arguments>& parser, std::vector<std::string>& unparsedArguments) { - auto arguments = parser.Parse(args, &unparsedArguments, 0); + Arguments arguments{ this->Makefile }; + parser.Parse(arguments, args, &unparsedArguments, 0); if (!arguments.MaybeReportError(*(this->Makefile)) && !unparsedArguments.empty()) { std::string m = "Unknown arguments:"; @@ -434,6 +471,11 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( "SOURCE_FROM_FILE requires exactly two arguments"); return cm::nullopt; } + if (!arguments.SourceTypeError.empty()) { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, + arguments.SourceTypeError); + return cm::nullopt; + } } else { // only valid for srcfile signatures if (!arguments.LangProps.empty()) { @@ -486,42 +528,45 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( cmSystemTools::RemoveFile(ccFile); // Choose sources. - std::vector<std::string> sources; + std::vector<std::pair<std::string, Arguments::SourceType>> sources; if (arguments.Sources) { sources = std::move(*arguments.Sources); } else if (arguments.SourceDirectoryOrFile) { - sources.emplace_back(*arguments.SourceDirectoryOrFile); + sources.emplace_back(*arguments.SourceDirectoryOrFile, + Arguments::SourceType::Directory); } if (arguments.SourceFromContent) { auto const k = arguments.SourceFromContent->size(); for (auto i = decltype(k){ 0 }; i < k; i += 2) { - const auto& name = (*arguments.SourceFromContent)[i + 0]; - const auto& content = (*arguments.SourceFromContent)[i + 1]; + const auto& name = (*arguments.SourceFromContent)[i + 0].first; + const auto& content = (*arguments.SourceFromContent)[i + 1].first; auto out = this->WriteSource(name, content, "SOURCE_FROM_CONTENT"); if (out.empty()) { return cm::nullopt; } - sources.emplace_back(std::move(out)); + sources.emplace_back(std::move(out), + (*arguments.SourceFromContent)[i + 0].second); } } if (arguments.SourceFromVar) { auto const k = arguments.SourceFromVar->size(); for (auto i = decltype(k){ 0 }; i < k; i += 2) { - const auto& name = (*arguments.SourceFromVar)[i + 0]; - const auto& var = (*arguments.SourceFromVar)[i + 1]; + const auto& name = (*arguments.SourceFromVar)[i + 0].first; + const auto& var = (*arguments.SourceFromVar)[i + 1].first; const auto& content = this->Makefile->GetDefinition(var); auto out = this->WriteSource(name, content, "SOURCE_FROM_VAR"); if (out.empty()) { return cm::nullopt; } - sources.emplace_back(std::move(out)); + sources.emplace_back(std::move(out), + (*arguments.SourceFromVar)[i + 0].second); } } if (arguments.SourceFromFile) { auto const k = arguments.SourceFromFile->size(); for (auto i = decltype(k){ 0 }; i < k; i += 2) { - const auto& dst = (*arguments.SourceFromFile)[i + 0]; - const auto& src = (*arguments.SourceFromFile)[i + 1]; + const auto& dst = (*arguments.SourceFromFile)[i + 0].first; + const auto& src = (*arguments.SourceFromFile)[i + 1].first; if (!cmSystemTools::GetFilenamePath(dst).empty()) { const auto& msg = @@ -539,7 +584,8 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( return cm::nullopt; } - sources.emplace_back(std::move(dstPath)); + sources.emplace_back(std::move(dstPath), + (*arguments.SourceFromFile)[i + 0].second); } } // TODO: ensure sources is not empty @@ -547,7 +593,8 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( // Detect languages to enable. cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator(); std::set<std::string> testLangs; - for (std::string const& si : sources) { + for (auto const& source : sources) { + auto const& si = source.first; std::string ext = cmSystemTools::GetFilenameLastExtension(si); std::string lang = gg->GetLanguageFromExtension(ext.c_str()); if (!lang.empty()) { @@ -837,17 +884,43 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( fprintf(fout, "set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n", this->BinaryDirectory.c_str()); /* Create the actual executable. */ - fprintf(fout, "add_executable(%s", targetName.c_str()); + fprintf(fout, "add_executable(%s)\n", targetName.c_str()); } else // if (targetType == cmStateEnums::STATIC_LIBRARY) { /* Put the static library at a known location (for COPY_FILE). */ fprintf(fout, "set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY \"%s\")\n", this->BinaryDirectory.c_str()); /* Create the actual static library. */ - fprintf(fout, "add_library(%s STATIC", targetName.c_str()); + fprintf(fout, "add_library(%s STATIC)\n", targetName.c_str()); } - for (std::string const& si : sources) { - fprintf(fout, " \"%s\"", si.c_str()); + fprintf(fout, "target_sources(%s PRIVATE\n", targetName.c_str()); + std::string file_set_name; + bool in_file_set = false; + for (auto const& source : sources) { + auto const& si = source.first; + switch (source.second) { + case Arguments::SourceType::Normal: { + if (in_file_set) { + fprintf(fout, " PRIVATE\n"); + in_file_set = false; + } + } break; + case Arguments::SourceType::CxxModule: { + if (!in_file_set) { + file_set_name += 'a'; + fprintf(fout, + " PRIVATE FILE_SET %s TYPE CXX_MODULES BASE_DIRS \"%s\" " + "FILES\n", + file_set_name.c_str(), + this->Makefile->GetCurrentSourceDirectory().c_str()); + in_file_set = true; + } + } break; + case Arguments::SourceType::Directory: + /* Handled elsewhere. */ + break; + } + fprintf(fout, " \"%s\"\n", si.c_str()); // Add dependencies on any non-temporary sources. if (!IsTemporary(si)) { @@ -1025,6 +1098,7 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s); vars.emplace("CMAKE_WATCOM_RUNTIME_LIBRARY"_s); vars.emplace("CMAKE_MSVC_DEBUG_INFORMATION_FORMAT"_s); + vars.emplace("CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS"_s); if (cmValue varListStr = this->Makefile->GetDefinition( kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) { @@ -1077,8 +1151,16 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( i++) { auto const& data = cmExperimental::DataForFeature( static_cast<cmExperimental::Feature>(i)); - if (data.ForwardThroughTryCompile) { + if (data.ForwardThroughTryCompile == + cmExperimental::TryCompileCondition::Always || + (data.ForwardThroughTryCompile == + cmExperimental::TryCompileCondition::SkipCompilerChecks && + arguments.CMakeInternal != "ABI"_s && + arguments.CMakeInternal != "FEATURE_TESTING"_s)) { vars.insert(data.Variable); + for (auto const& var : data.TryCompileVariables) { + vars.insert(var); + } } } diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h index c185c68..3217a1b 100644 --- a/Source/cmCoreTryCompile.h +++ b/Source/cmCoreTryCompile.h @@ -6,9 +6,11 @@ #include <map> #include <string> +#include <utility> #include <vector> #include <cm/optional> +#include <cm/string_view> #include "cmArgumentParser.h" #include "cmArgumentParserTypes.h" @@ -51,17 +53,36 @@ public: struct Arguments : public ArgumentParser::ParseResult { + Arguments(cmMakefile const* mf) + : Makefile(mf) + { + } + + cmMakefile const* Makefile; + + enum class SourceType + { + Normal, + CxxModule, + Directory, + }; + cm::optional<std::string> CompileResultVariable; cm::optional<std::string> BinaryDirectory; cm::optional<std::string> SourceDirectoryOrFile; cm::optional<std::string> ProjectName; cm::optional<std::string> TargetName; - cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> Sources; - cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> + cm::optional<ArgumentParser::NonEmpty< + std::vector<std::pair<std::string, SourceType>>>> + Sources; + cm::optional<ArgumentParser::NonEmpty< + std::vector<std::pair<std::string, SourceType>>>> SourceFromContent; - cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> + cm::optional<ArgumentParser::NonEmpty< + std::vector<std::pair<std::string, SourceType>>>> SourceFromVar; - cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> + cm::optional<ArgumentParser::NonEmpty< + std::vector<std::pair<std::string, SourceType>>>> SourceFromFile; ArgumentParser::MaybeEmpty<std::vector<std::string>> CMakeFlags{ 1, "CMAKE_FLAGS" @@ -79,6 +100,10 @@ public: bool NoCache = false; bool NoLog = false; + ArgumentParser::Continue SetSourceType(cm::string_view sourceType); + SourceType SourceTypeContext = SourceType::Normal; + std::string SourceTypeError; + // Argument for try_run only. // Keep in sync with warnings in cmCoreTryCompile::ParseArgs. cm::optional<std::string> CompileOutputVariable; diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx index 51c174e..dd8f16e 100644 --- a/Source/cmExperimental.cxx +++ b/Source/cmExperimental.cxx @@ -20,18 +20,25 @@ namespace { */ cmExperimental::FeatureData LookupTable[] = { // CxxModuleCMakeApi - { "CxxModuleCMakeApi", "bf70d4b0-9fb7-465c-9803-34014e70d112", + { "CxxModuleCMakeApi", + "a816ed09-43d1-40e5-bc8c-1a2824ee194e", "CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API", "CMake's C++ module support is experimental. It is meant only for " "experimentation and feedback to CMake developers.", - false, // https://gitlab.kitware.com/cmake/cmake/-/issues/25097 + { "CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE", + "CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT", + "CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG" }, + cmExperimental::TryCompileCondition::SkipCompilerChecks, false }, // WindowsKernelModeDriver - { "WindowsKernelModeDriver", "5c2d848d-4efa-4529-a768-efd57171bf68", + { "WindowsKernelModeDriver", + "5c2d848d-4efa-4529-a768-efd57171bf68", "CMAKE_EXPERIMENTAL_WINDOWS_KERNEL_MODE_DRIVER", "CMake's Windows kernel-mode driver support is experimental. It is meant " "only for experimentation and feedback to CMake developers.", - true, false }, + {}, + cmExperimental::TryCompileCondition::Always, + false }, }; static_assert(sizeof(LookupTable) / sizeof(LookupTable[0]) == static_cast<size_t>(cmExperimental::Feature::Sentinel), diff --git a/Source/cmExperimental.h b/Source/cmExperimental.h index 3374ba8..c958ab6 100644 --- a/Source/cmExperimental.h +++ b/Source/cmExperimental.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <string> +#include <vector> class cmMakefile; @@ -20,13 +21,21 @@ public: Sentinel, }; + enum class TryCompileCondition + { + Always, + SkipCompilerChecks, + Never, + }; + struct FeatureData { std::string const Name; std::string const Uuid; std::string const Variable; std::string const Description; - bool const ForwardThroughTryCompile; + std::vector<std::string> const TryCompileVariables; + TryCompileCondition const ForwardThroughTryCompile; bool Warned; }; |