cmCoreTryCompile: use the source type context for source files

Also add a test to `RunCMake/CXXModules` to test `try_compile` with C++
modules.

Fixes: #25097
This commit is contained in:
Ben Boeckel 2023-07-19 19:00:05 -04:00
parent 93993c7ad4
commit b768d293c5
11 changed files with 137 additions and 21 deletions

View File

@ -168,7 +168,8 @@ auto const TryCompileBaseArgParser =
auto const TryCompileBaseSourcesArgParser =
cmArgumentParser<Arguments>{ TryCompileBaseArgParser }
.Bind("SOURCES_TYPE"_s, &Arguments::SetSourceType)
.Bind("SOURCES"_s, &Arguments::Sources)
.BindWithContext("SOURCES"_s, &Arguments::Sources,
&Arguments::SourceTypeContext)
.Bind("COMPILE_DEFINITIONS"_s, TryCompileCompileDefs,
ArgumentParser::ExpectAtLeast{ 0 })
.Bind("LINK_LIBRARIES"_s, &Arguments::LinkLibraries)
@ -185,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 =
@ -524,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 =
@ -577,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
@ -585,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()) {
@ -885,7 +894,32 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
fprintf(fout, "add_library(%s STATIC)\n", targetName.c_str());
}
fprintf(fout, "target_sources(%s PRIVATE\n", targetName.c_str());
for (std::string const& si : sources) {
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.

View File

@ -6,6 +6,7 @@
#include <map>
#include <string>
#include <utility>
#include <vector>
#include <cm/optional>
@ -71,12 +72,17 @@ public:
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"

View File

@ -148,6 +148,8 @@ if ("named" IN_LIST CMake_TEST_MODULE_COMPILATION)
run_cxx_module_test(duplicate)
set(RunCMake_CXXModules_NO_TEST 1)
run_cxx_module_test(circular)
run_cxx_module_test(try-compile)
run_cxx_module_test(try-run)
unset(RunCMake_CXXModules_NO_TEST)
run_cxx_module_test(same-src-name)
run_cxx_module_test(scan_properties)

View File

@ -0,0 +1,4 @@
CMake Warning \(dev\) at CMakeLists.txt:[0-9]* \(try_compile\):
CMake's C\+\+ module support is experimental. It is meant only for
experimentation and feedback to CMake developers.
This warning is for project developers. Use -Wno-dev to suppress it.

View File

@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.24)
project(cxx_modules_try_compile CXX)
include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
try_compile(can_use_modules
SOURCES_TYPE CXX_MODULE
SOURCES
"${CMAKE_CURRENT_LIST_DIR}/importable.cxx"
SOURCES_TYPE NORMAL
SOURCE_FROM_FILE
use_importable.cxx "${CMAKE_CURRENT_LIST_DIR}/use_importable.cxx"
CXX_STANDARD 20)
if (NOT can_use_modules)
message(FATAL_ERROR
"`try_compile` could not compile sources using modules.")
endif ()

View File

@ -0,0 +1,6 @@
export module importable;
export int from_import()
{
return 0;
}

View File

@ -0,0 +1,6 @@
import importable;
int foo()
{
return from_import();
}

View File

@ -0,0 +1,4 @@
CMake Warning \(dev\) at CMakeLists.txt:[0-9]* \(try_run\):
CMake's C\+\+ module support is experimental. It is meant only for
experimentation and feedback to CMake developers.
This warning is for project developers. Use -Wno-dev to suppress it.

View File

@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.24)
project(cxx_modules_try_run CXX)
include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
try_run(can_run_modules_result can_compile_modules
SOURCES_TYPE CXX_MODULE
SOURCES
"${CMAKE_CURRENT_LIST_DIR}/importable.cxx"
SOURCES_TYPE NORMAL
SOURCE_FROM_FILE
main.cxx "${CMAKE_CURRENT_LIST_DIR}/main.cxx"
CXX_STANDARD 20)
if (NOT can_compile_modules)
message(FATAL_ERROR
"`try_run` could not compile sources using modules.")
endif ()
if (can_run_modules_result)
message(FATAL_ERROR
"`try_run` could not run sources using modules.")
endif ()

View File

@ -0,0 +1,6 @@
export module importable;
export int from_import()
{
return 0;
}

View File

@ -0,0 +1,6 @@
import importable;
int main(int argc, char* argv[])
{
return from_import() == 1;
}