mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-12 00:58:59 -05:00
Merge topic 'imported-cxxmodules'
48ee946fdccmExperimental: recycle the C++ modules API UUID1a1806a71bgitlab-ci: declare `bmionly` support for modules where possible457a12f3f9Tests/RunCMake/CXXModules: add tests which use modules from imported targets9b9ec70b54Ninja: generate scanning and build rules for C++20 module synthetic targets80ef50a191CXXModules: add a variable for BMI-only compilation80d6544398cxxmodules: generate synthetic targets as an initial pass3dc6676ecccmSyntheticTargetCache: add a struct for synthetic target cachingcb356b540ccmCxxModuleUsageEffects: add a class to capture module usage effects ... Acked-by: Kitware Robot <kwrobot@kitware.com> Tested-by: buildbot <buildbot@kitware.com> Merge-request: !8535
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_clang.cmake" CACHE STRING "")
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora38_common_clang.cmake")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_clang.cmake" CACHE STRING "")
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora38_common_clang.cmake")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,bmionly" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_gcc.cmake" CACHE STRING "")
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,bmionly" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_gcc.cmake" CACHE STRING "")
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
if("$ENV{CMAKE_CI_BUILD_NAME}" MATCHES "(^|_)gnu(_|$)")
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_clang.cmake" CACHE STRING "")
|
||||
endif()
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_clang_common.cmake")
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,shared,export_bmi,install_bmi" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,shared,export_bmi,install_bmi,bmionly" CACHE STRING "")
|
||||
set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_msvc.cmake" CACHE STRING "")
|
||||
|
||||
@@ -17,3 +17,4 @@ string(CONCAT CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG
|
||||
" -fdeps-format=p1689r5"
|
||||
# Force C++ as a language.
|
||||
" -x c++")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_BMI_ONLY_FLAG "-fmodule-only")
|
||||
|
||||
@@ -18,7 +18,7 @@ C++20 Module APIs
|
||||
=================
|
||||
|
||||
Variable: ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
|
||||
Value: ``a816ed09-43d1-40e5-bc8c-1a2824ee194e``
|
||||
Value: ``ac01f462-0f5f-432a-86aa-acef252918a6``
|
||||
|
||||
In order to support C++20 modules, there are a number of behaviors that have
|
||||
CMake APIs to provide the required features to build and export them from a
|
||||
@@ -99,6 +99,10 @@ dependencies to the file specified by the ``<DYNDEP_FILE>`` placeholder. The
|
||||
``CMAKE_EXPERIMENTAL_CXX_SCANDEP_DEPFILE_FORMAT`` file may be set to ``msvc``
|
||||
for scandep rules which use ``msvc``-style dependency reporting.
|
||||
|
||||
In order to support ``IMPORTED`` targets with associated C++20 module sources,
|
||||
the ``CMAKE_EXPERIMENTAL_CXX_MODULE_BMI_ONLY_FLAG`` variable must be provided
|
||||
to have the compiler only output a BMI instead of a BMI and an object file.
|
||||
|
||||
The module dependencies should be written in the format described
|
||||
by the `P1689r5`_ paper.
|
||||
|
||||
@@ -113,6 +117,8 @@ For compilers that generate module maps, tell CMake as follows:
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "gcc")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG
|
||||
"${compiler_flags_for_module_map} -fmodule-mapper=<MODULE_MAP_FILE>")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_BMI_ONLY_FLAG
|
||||
"-fmodule-only")
|
||||
|
||||
Currently, the only supported formats are, ``clang``, ``gcc``, and ``msvc``.
|
||||
The ``gcc`` format is described in the GCC documentation, but the relevant
|
||||
|
||||
@@ -240,6 +240,11 @@ Properties on Targets
|
||||
/prop_tgt/IMPORTED
|
||||
/prop_tgt/IMPORTED_COMMON_LANGUAGE_RUNTIME
|
||||
/prop_tgt/IMPORTED_CONFIGURATIONS
|
||||
/prop_tgt/IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS
|
||||
/prop_tgt/IMPORTED_CXX_MODULES_COMPILE_FEATURES
|
||||
/prop_tgt/IMPORTED_CXX_MODULES_COMPILE_OPTIONS
|
||||
/prop_tgt/IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES
|
||||
/prop_tgt/IMPORTED_CXX_MODULES_LINK_LIBRARIES
|
||||
/prop_tgt/IMPORTED_GLOBAL
|
||||
/prop_tgt/IMPORTED_IMPLIB
|
||||
/prop_tgt/IMPORTED_IMPLIB_CONFIG
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS
|
||||
----------------------------------------
|
||||
|
||||
.. versionadded:: 3.28
|
||||
|
||||
.. note ::
|
||||
|
||||
Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
|
||||
|
||||
Preprocessor definitions for compiling an ``IMPORTED`` target's C++ module
|
||||
sources.
|
||||
|
||||
CMake will automatically drop some definitions that are not supported
|
||||
by the native build tool.
|
||||
@@ -0,0 +1,13 @@
|
||||
IMPORTED_CXX_MODULES_COMPILE_FEATURES
|
||||
-------------------------------------
|
||||
|
||||
.. versionadded:: 3.28
|
||||
|
||||
.. note ::
|
||||
|
||||
Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
|
||||
|
||||
Compiler features enabled for this ``IMPORTED`` target's C++ modules.
|
||||
|
||||
The value of this property is used by the generators to set the include
|
||||
paths for the compiler.
|
||||
@@ -0,0 +1,13 @@
|
||||
IMPORTED_CXX_MODULES_COMPILE_OPTIONS
|
||||
------------------------------------
|
||||
|
||||
.. versionadded:: 3.28
|
||||
|
||||
.. note ::
|
||||
|
||||
Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
|
||||
|
||||
List of options to pass to the compiler for this ``IMPORTED`` target's C++
|
||||
modules.
|
||||
|
||||
.. include:: ../command/OPTIONS_SHELL.txt
|
||||
@@ -0,0 +1,14 @@
|
||||
IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES
|
||||
----------------------------------------
|
||||
|
||||
.. versionadded:: 3.28
|
||||
|
||||
.. note ::
|
||||
|
||||
Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
|
||||
|
||||
List of preprocessor include file search directories when compiling C++
|
||||
modules for ``IMPORTED`` targets.
|
||||
|
||||
The value of this property is used by the generators to set the include
|
||||
paths for the compiler.
|
||||
@@ -0,0 +1,11 @@
|
||||
IMPORTED_CXX_MODULES_LINK_LIBRARIES
|
||||
-----------------------------------
|
||||
|
||||
.. versionadded:: 3.28
|
||||
|
||||
.. note ::
|
||||
|
||||
Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
|
||||
|
||||
List of direct dependencies to use for usage requirements for C++ modules in
|
||||
the target's C++ modules.
|
||||
@@ -43,5 +43,6 @@ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
|
||||
" > <DYNDEP_FILE>")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "clang")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "@<MODULE_MAP_FILE>")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_BMI_ONLY_FLAG "--precompile")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -87,4 +87,5 @@ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "19.34")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_DEPFILE_FORMAT "msvc")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "msvc")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "@<MODULE_MAP_FILE>")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_BMI_ONLY_FLAG "-ifcOnly;-ifcOutput;<OBJECT>")
|
||||
endif ()
|
||||
|
||||
@@ -171,6 +171,8 @@ add_library(
|
||||
cmCustomCommandTypes.h
|
||||
cmCxxModuleMapper.cxx
|
||||
cmCxxModuleMapper.h
|
||||
cmCxxModuleUsageEffects.cxx
|
||||
cmCxxModuleUsageEffects.h
|
||||
cmDefinitions.cxx
|
||||
cmDefinitions.h
|
||||
cmDependencyProvider.h
|
||||
@@ -299,6 +301,8 @@ add_library(
|
||||
cmGraphAdjacencyList.h
|
||||
cmGraphVizWriter.cxx
|
||||
cmGraphVizWriter.h
|
||||
cmImportedCxxModuleInfo.cxx
|
||||
cmImportedCxxModuleInfo.h
|
||||
cmInstallGenerator.h
|
||||
cmInstallGenerator.cxx
|
||||
cmInstallGetRuntimeDependenciesGenerator.h
|
||||
@@ -424,6 +428,7 @@ add_library(
|
||||
cmStateTypes.h
|
||||
cmStringAlgorithms.cxx
|
||||
cmStringAlgorithms.h
|
||||
cmSyntheticTargetCache.h
|
||||
cmSystemTools.cxx
|
||||
cmSystemTools.h
|
||||
cmTarget.cxx
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#include "cmCxxModuleUsageEffects.h"
|
||||
|
||||
cmCxxModuleUsageEffects::cmCxxModuleUsageEffects(
|
||||
cmGeneratorTarget const* /*gt*/)
|
||||
: Hash("0000000000000000000000000000000000000000")
|
||||
{
|
||||
// TODO: collect information from the generator target as to what might
|
||||
// affect module consumption.
|
||||
}
|
||||
|
||||
void cmCxxModuleUsageEffects::ApplyToTarget(cmTarget* /*tgt*/)
|
||||
{
|
||||
// TODO: apply the information collected in the constructor
|
||||
}
|
||||
|
||||
std::string const& cmCxxModuleUsageEffects::GetHash() const
|
||||
{
|
||||
return this->Hash;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <string>
|
||||
|
||||
class cmGeneratorTarget;
|
||||
class cmTarget;
|
||||
|
||||
class cmCxxModuleUsageEffects
|
||||
{
|
||||
public:
|
||||
cmCxxModuleUsageEffects(cmGeneratorTarget const* gt);
|
||||
|
||||
void ApplyToTarget(cmTarget* tgt);
|
||||
std::string const& GetHash() const;
|
||||
|
||||
private:
|
||||
std::string Hash;
|
||||
};
|
||||
@@ -73,20 +73,36 @@ Json::Value CollationInformationCxxModules(
|
||||
gt->LocalGenerator, config, gt);
|
||||
}
|
||||
|
||||
std::map<std::string, cmSourceFile const*> sf_map;
|
||||
enum class CompileType
|
||||
{
|
||||
std::vector<cmSourceFile const*> objectSources;
|
||||
gt->GetObjectSources(objectSources, config);
|
||||
for (auto const* sf : objectSources) {
|
||||
ObjectAndBmi,
|
||||
BmiOnly,
|
||||
};
|
||||
std::map<std::string, std::pair<cmSourceFile const*, CompileType>> sf_map;
|
||||
{
|
||||
auto fill_sf_map = [gt, tgt, &sf_map](cmSourceFile const* sf,
|
||||
CompileType type) {
|
||||
auto full_path = sf->GetFullPath();
|
||||
if (full_path.empty()) {
|
||||
gt->Makefile->IssueMessage(
|
||||
MessageType::INTERNAL_ERROR,
|
||||
cmStrCat("Target \"", tgt->GetName(),
|
||||
"\" has a full path-less source file."));
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
sf_map[full_path] = sf;
|
||||
sf_map[full_path] = std::make_pair(sf, type);
|
||||
};
|
||||
|
||||
std::vector<cmSourceFile const*> objectSources;
|
||||
gt->GetObjectSources(objectSources, config);
|
||||
for (auto const* sf : objectSources) {
|
||||
fill_sf_map(sf, CompileType::ObjectAndBmi);
|
||||
}
|
||||
|
||||
std::vector<cmSourceFile const*> cxxModuleSources;
|
||||
gt->GetCxxModuleSources(cxxModuleSources, config);
|
||||
for (auto const* sf : cxxModuleSources) {
|
||||
fill_sf_map(sf, CompileType::BmiOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +129,8 @@ Json::Value CollationInformationCxxModules(
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const* sf = lookup->second;
|
||||
auto const* sf = lookup->second.first;
|
||||
CompileType const ct = lookup->second.second;
|
||||
|
||||
if (!sf) {
|
||||
gt->Makefile->IssueMessage(
|
||||
@@ -123,11 +140,14 @@ Json::Value CollationInformationCxxModules(
|
||||
continue;
|
||||
}
|
||||
|
||||
auto obj_path = cb.ObjectFilePath(sf, config);
|
||||
auto obj_path = ct == CompileType::ObjectAndBmi
|
||||
? cb.ObjectFilePath(sf, config)
|
||||
: cb.BmiFilePath(sf, config);
|
||||
Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] =
|
||||
Json::objectValue;
|
||||
|
||||
tdi_module_info["source"] = file;
|
||||
tdi_module_info["bmi-only"] = ct == CompileType::BmiOnly;
|
||||
tdi_module_info["relative-directory"] = files_per_dir.first;
|
||||
tdi_module_info["name"] = file_set->GetName();
|
||||
tdi_module_info["type"] = file_set->GetType();
|
||||
@@ -269,10 +289,11 @@ void cmDyndepCollation::AddCollationInformation(
|
||||
struct CxxModuleFileSet
|
||||
{
|
||||
std::string Name;
|
||||
bool BmiOnly = false;
|
||||
std::string RelativeDirectory;
|
||||
std::string SourcePath;
|
||||
std::string Type;
|
||||
cmFileSetVisibility Visibility;
|
||||
cmFileSetVisibility Visibility = cmFileSetVisibility::Private;
|
||||
cm::optional<std::string> Destination;
|
||||
};
|
||||
|
||||
@@ -356,6 +377,7 @@ cmDyndepCollation::ParseExportInfo(Json::Value const& tdi)
|
||||
CxxModuleFileSet& fsi = export_info->ObjectToFileSet[i.key().asString()];
|
||||
auto const& tdi_cxx_module_info = *i;
|
||||
fsi.Name = tdi_cxx_module_info["name"].asString();
|
||||
fsi.BmiOnly = tdi_cxx_module_info["bmi-only"].asBool();
|
||||
fsi.RelativeDirectory =
|
||||
tdi_cxx_module_info["relative-directory"].asString();
|
||||
if (!fsi.RelativeDirectory.empty() &&
|
||||
@@ -644,3 +666,16 @@ bool cmDyndepCollation::IsObjectPrivate(
|
||||
auto const& file_set = fileset_info_itr->second;
|
||||
return !cmFileSetVisibilityIsForInterface(file_set.Visibility);
|
||||
}
|
||||
|
||||
bool cmDyndepCollation::IsBmiOnly(cmCxxModuleExportInfo const& exportInfo,
|
||||
std::string const& object)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
auto object_path = object;
|
||||
cmSystemTools::ConvertToUnixSlashes(object_path);
|
||||
#else
|
||||
auto const& object_path = object;
|
||||
#endif
|
||||
auto fs = exportInfo.ObjectToFileSet.find(object_path);
|
||||
return (fs != exportInfo.ObjectToFileSet.end()) && fs->second.BmiOnly;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ struct cmDyndepGeneratorCallbacks
|
||||
{
|
||||
std::function<std::string(cmSourceFile const* sf, std::string const& config)>
|
||||
ObjectFilePath;
|
||||
std::function<std::string(cmSourceFile const* sf, std::string const& config)>
|
||||
BmiFilePath;
|
||||
};
|
||||
|
||||
struct cmDyndepMetadataCallbacks
|
||||
@@ -51,4 +53,7 @@ struct cmDyndepCollation
|
||||
cmDyndepMetadataCallbacks const& cb);
|
||||
static bool IsObjectPrivate(std::string const& object,
|
||||
cmCxxModuleExportInfo const& export_info);
|
||||
|
||||
static bool IsBmiOnly(cmCxxModuleExportInfo const& exportInfo,
|
||||
std::string const& object);
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace {
|
||||
cmExperimental::FeatureData LookupTable[] = {
|
||||
// CxxModuleCMakeApi
|
||||
{ "CxxModuleCMakeApi",
|
||||
"a816ed09-43d1-40e5-bc8c-1a2824ee194e",
|
||||
"ac01f462-0f5f-432a-86aa-acef252918a6",
|
||||
"CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API",
|
||||
"CMake's C++ module support is experimental. It is meant only for "
|
||||
"experimentation and feedback to CMake developers.",
|
||||
|
||||
@@ -126,6 +126,15 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
|
||||
properties);
|
||||
|
||||
std::string errorMessage;
|
||||
if (!this->PopulateCxxModuleExportProperties(
|
||||
gte, properties, cmGeneratorExpression::BuildInterface,
|
||||
errorMessage)) {
|
||||
this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
|
||||
MessageType::FATAL_ERROR, errorMessage,
|
||||
this->LG->GetMakefile()->GetBacktrace());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->PopulateExportProperties(gte, properties, errorMessage)) {
|
||||
this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
|
||||
MessageType::FATAL_ERROR, errorMessage,
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include <cm/memory>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmsys/FStream.hxx"
|
||||
|
||||
@@ -1255,6 +1256,77 @@ void cmExportFileGenerator::GenerateImportedFileChecksCode(
|
||||
os << ")\n\n";
|
||||
}
|
||||
|
||||
bool cmExportFileGenerator::PopulateCxxModuleExportProperties(
|
||||
cmGeneratorTarget const* gte, ImportPropertyMap& properties,
|
||||
cmGeneratorExpression::PreprocessContext ctx, std::string& errorMessage)
|
||||
{
|
||||
if (!gte->HaveCxx20ModuleSources(&errorMessage)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const cm::static_string_view exportedDirectModuleProperties[] = {
|
||||
"CXX_EXTENSIONS"_s,
|
||||
};
|
||||
for (auto const& propName : exportedDirectModuleProperties) {
|
||||
auto const propNameStr = std::string(propName);
|
||||
cmValue prop = gte->Target->GetComputedProperty(
|
||||
propNameStr, *gte->Target->GetMakefile());
|
||||
if (!prop) {
|
||||
prop = gte->Target->GetProperty(propNameStr);
|
||||
}
|
||||
if (prop) {
|
||||
properties[propNameStr] = cmGeneratorExpression::Preprocess(*prop, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
const cm::static_string_view exportedModuleProperties[] = {
|
||||
"INCLUDE_DIRECTORIES"_s,
|
||||
"COMPILE_DEFINITIONS"_s,
|
||||
"COMPILE_OPTIONS"_s,
|
||||
"COMPILE_FEATURES"_s,
|
||||
};
|
||||
for (auto const& propName : exportedModuleProperties) {
|
||||
auto const propNameStr = std::string(propName);
|
||||
cmValue prop = gte->Target->GetComputedProperty(
|
||||
propNameStr, *gte->Target->GetMakefile());
|
||||
if (!prop) {
|
||||
prop = gte->Target->GetProperty(propNameStr);
|
||||
}
|
||||
if (prop) {
|
||||
auto const exportedPropName =
|
||||
cmStrCat("IMPORTED_CXX_MODULES_", propName);
|
||||
properties[exportedPropName] =
|
||||
cmGeneratorExpression::Preprocess(*prop, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
const cm::static_string_view exportedLinkModuleProperties[] = {
|
||||
"LINK_LIBRARIES"_s,
|
||||
};
|
||||
for (auto const& propName : exportedLinkModuleProperties) {
|
||||
auto const propNameStr = std::string(propName);
|
||||
cmValue prop = gte->Target->GetComputedProperty(
|
||||
propNameStr, *gte->Target->GetMakefile());
|
||||
if (!prop) {
|
||||
prop = gte->Target->GetProperty(propNameStr);
|
||||
}
|
||||
if (prop) {
|
||||
auto const exportedPropName =
|
||||
cmStrCat("IMPORTED_CXX_MODULES_", propName);
|
||||
auto value = cmGeneratorExpression::Preprocess(*prop, ctx);
|
||||
this->ResolveTargetsInGeneratorExpressions(
|
||||
value, gte, cmExportFileGenerator::ReplaceFreeTargets);
|
||||
std::vector<std::string> wrappedValues;
|
||||
for (auto& item : cmList{ value }) {
|
||||
wrappedValues.push_back(cmStrCat("$<COMPILE_ONLY:", item, '>'));
|
||||
}
|
||||
properties[exportedPropName] = cmJoin(wrappedValues, ";");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmExportFileGenerator::PopulateExportProperties(
|
||||
cmGeneratorTarget const* gte, ImportPropertyMap& properties,
|
||||
std::string& errorMessage)
|
||||
|
||||
@@ -175,6 +175,9 @@ protected:
|
||||
virtual void GenerateRequiredCMakeVersion(std::ostream& os,
|
||||
const char* versionString);
|
||||
|
||||
bool PopulateCxxModuleExportProperties(
|
||||
cmGeneratorTarget const* gte, ImportPropertyMap& properties,
|
||||
cmGeneratorExpression::PreprocessContext ctx, std::string& errorMessage);
|
||||
bool PopulateExportProperties(cmGeneratorTarget const* gte,
|
||||
ImportPropertyMap& properties,
|
||||
std::string& errorMessage);
|
||||
|
||||
@@ -126,6 +126,13 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
|
||||
gt, cmGeneratorExpression::InstallInterface, properties);
|
||||
|
||||
std::string errorMessage;
|
||||
if (!this->PopulateCxxModuleExportProperties(
|
||||
gt, properties, cmGeneratorExpression::InstallInterface,
|
||||
errorMessage)) {
|
||||
cmSystemTools::Error(errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->PopulateExportProperties(gt, properties, errorMessage)) {
|
||||
cmSystemTools::Error(errorMessage);
|
||||
return false;
|
||||
|
||||
@@ -1678,6 +1678,7 @@ Json::Value Target::DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
|
||||
}
|
||||
|
||||
switch (sk.Kind) {
|
||||
case cmGeneratorTarget::SourceKindCxxModuleSource:
|
||||
case cmGeneratorTarget::SourceKindObjectSource: {
|
||||
source["compileGroupIndex"] =
|
||||
this->AddSourceCompileGroup(sk.Source.Value, si);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <cmext/algorithm>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmsys/RegularExpression.hxx"
|
||||
@@ -88,6 +89,12 @@ cmFileSet::cmFileSet(cmake& cmakeInstance, std::string name, std::string type,
|
||||
{
|
||||
}
|
||||
|
||||
void cmFileSet::CopyEntries(cmFileSet const* fs)
|
||||
{
|
||||
cm::append(this->DirectoryEntries, fs->DirectoryEntries);
|
||||
cm::append(this->FileEntries, fs->FileEntries);
|
||||
}
|
||||
|
||||
void cmFileSet::ClearDirectoryEntries()
|
||||
{
|
||||
this->DirectoryEntries.clear();
|
||||
|
||||
@@ -41,6 +41,8 @@ public:
|
||||
const std::string& GetType() const { return this->Type; }
|
||||
cmFileSetVisibility GetVisibility() const { return this->Visibility; }
|
||||
|
||||
void CopyEntries(cmFileSet const* fs);
|
||||
|
||||
void ClearDirectoryEntries();
|
||||
void AddDirectoryEntry(BT<std::string> directories);
|
||||
const std::vector<BT<std::string>>& GetDirectoryEntries() const
|
||||
|
||||
+132
-16
@@ -27,7 +27,9 @@
|
||||
|
||||
#include "cmAlgorithms.h"
|
||||
#include "cmComputeLinkInformation.h"
|
||||
#include "cmCryptoHash.h"
|
||||
#include "cmCustomCommandGenerator.h"
|
||||
#include "cmCxxModuleUsageEffects.h"
|
||||
#include "cmEvaluatedTargetProperty.h"
|
||||
#include "cmExperimental.h"
|
||||
#include "cmFileSet.h"
|
||||
@@ -52,6 +54,7 @@
|
||||
#include "cmStandardLevelResolver.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSyntheticTargetCache.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmTarget.h"
|
||||
#include "cmTargetLinkLibraryType.h"
|
||||
@@ -1071,6 +1074,12 @@ void cmGeneratorTarget::GetHeaderSources(
|
||||
IMPLEMENT_VISIT(SourceKindHeader);
|
||||
}
|
||||
|
||||
void cmGeneratorTarget::GetCxxModuleSources(
|
||||
std::vector<cmSourceFile const*>& data, const std::string& config) const
|
||||
{
|
||||
IMPLEMENT_VISIT(SourceKindCxxModuleSource);
|
||||
}
|
||||
|
||||
void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile const*>& data,
|
||||
const std::string& config) const
|
||||
{
|
||||
@@ -1953,8 +1962,12 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
|
||||
// Compute the kind (classification) of this source file.
|
||||
SourceKind kind;
|
||||
std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
|
||||
cmFileSet const* fs = this->GetFileSetForSource(config, sf);
|
||||
if (sf->GetCustomCommand()) {
|
||||
kind = SourceKindCustomCommand;
|
||||
} else if (!this->Target->IsNormal() && !this->Target->IsImported() &&
|
||||
fs && (fs->GetType() == "CXX_MODULES"_s)) {
|
||||
kind = SourceKindCxxModuleSource;
|
||||
} else if (this->Target->GetType() == cmStateEnums::UTILITY ||
|
||||
this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY
|
||||
// XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
|
||||
@@ -8220,6 +8233,96 @@ void ComputeLinkImplTransitive(cmGeneratorTarget const* self,
|
||||
}
|
||||
}
|
||||
|
||||
bool cmGeneratorTarget::DiscoverSyntheticTargets(cmSyntheticTargetCache& cache,
|
||||
std::string const& config)
|
||||
{
|
||||
cmOptionalLinkImplementation impl;
|
||||
this->ComputeLinkImplementationLibraries(config, impl, this,
|
||||
LinkInterfaceFor::Link);
|
||||
|
||||
cmCxxModuleUsageEffects usage(this);
|
||||
|
||||
auto& SyntheticDeps = this->Configs[config].SyntheticDeps;
|
||||
|
||||
for (auto const& entry : impl.Libraries) {
|
||||
auto const* gt = entry.Target;
|
||||
if (!gt || !gt->IsImported()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gt->HaveCxx20ModuleSources()) {
|
||||
auto hasher = cmCryptoHash::New("SHA3_512");
|
||||
constexpr size_t HASH_TRUNCATION = 12;
|
||||
auto dirhash = hasher->HashString(
|
||||
gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
|
||||
std::string safeName = gt->GetName();
|
||||
cmSystemTools::ReplaceString(safeName, ":", "_");
|
||||
auto targetIdent =
|
||||
hasher->HashString(cmStrCat("@d_", dirhash, "@u_", usage.GetHash()));
|
||||
std::string targetName =
|
||||
cmStrCat(safeName, "@synth_", targetIdent.substr(0, HASH_TRUNCATION));
|
||||
|
||||
// Check the cache to see if this instance of the imported target has
|
||||
// already been created.
|
||||
auto cached = cache.CxxModuleTargets.find(targetName);
|
||||
cmGeneratorTarget const* synthDep = nullptr;
|
||||
if (cached == cache.CxxModuleTargets.end()) {
|
||||
auto const* model = gt->Target;
|
||||
auto* mf = gt->Makefile;
|
||||
auto* lg = gt->GetLocalGenerator();
|
||||
auto* tgt = mf->AddSynthesizedTarget(cmStateEnums::INTERFACE_LIBRARY,
|
||||
targetName);
|
||||
|
||||
// Copy relevant information from the existing IMPORTED target.
|
||||
|
||||
// Copy policies to the target.
|
||||
tgt->CopyPolicyStatuses(model);
|
||||
|
||||
// Copy file sets.
|
||||
{
|
||||
auto fsNames = model->GetAllFileSetNames();
|
||||
for (auto const& fsName : fsNames) {
|
||||
auto const* fs = model->GetFileSet(fsName);
|
||||
if (!fs) {
|
||||
mf->IssueMessage(MessageType::INTERNAL_ERROR,
|
||||
cmStrCat("Failed to find file set named '",
|
||||
fsName, "' on target '",
|
||||
tgt->GetName(), '\''));
|
||||
continue;
|
||||
}
|
||||
auto* newFs = tgt
|
||||
->GetOrCreateFileSet(fs->GetName(), fs->GetType(),
|
||||
fs->GetVisibility())
|
||||
.first;
|
||||
newFs->CopyEntries(fs);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy imported C++ module properties.
|
||||
tgt->CopyImportedCxxModulesEntries(model);
|
||||
|
||||
// Copy other properties which may affect the C++ module BMI
|
||||
// generation.
|
||||
tgt->CopyImportedCxxModulesProperties(model);
|
||||
|
||||
// Apply usage requirements to the target.
|
||||
usage.ApplyToTarget(tgt);
|
||||
|
||||
// Create the generator target and attach it to the local generator.
|
||||
auto gtp = cm::make_unique<cmGeneratorTarget>(tgt, lg);
|
||||
synthDep = gtp.get();
|
||||
lg->AddGeneratorTarget(std::move(gtp));
|
||||
} else {
|
||||
synthDep = cached->second;
|
||||
}
|
||||
|
||||
SyntheticDeps[gt].push_back(synthDep);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cmGeneratorTarget::ComputeLinkImplementationLibraries(
|
||||
const std::string& config, cmOptionalLinkImplementation& impl,
|
||||
cmGeneratorTarget const* head, LinkInterfaceFor implFor) const
|
||||
@@ -8227,6 +8330,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
|
||||
cmLocalGenerator const* lg = this->LocalGenerator;
|
||||
cmMakefile const* mf = lg->GetMakefile();
|
||||
cmBTStringRange entryRange = this->Target->GetLinkImplementationEntries();
|
||||
auto const& synthTargetsForConfig = this->Configs[config].SyntheticDeps;
|
||||
// Collect libraries directly linked in this configuration.
|
||||
for (auto const& entry : entryRange) {
|
||||
// Keep this logic in sync with ExpandLinkItems.
|
||||
@@ -8316,7 +8420,15 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
|
||||
// The entry is meant for this configuration.
|
||||
cmLinkItem item =
|
||||
this->ResolveLinkItem(BT<std::string>(name, entry.Backtrace), lg);
|
||||
if (!item.Target) {
|
||||
if (item.Target) {
|
||||
auto depsForTarget = synthTargetsForConfig.find(item.Target);
|
||||
if (depsForTarget != synthTargetsForConfig.end()) {
|
||||
for (auto const* depForTarget : depsForTarget->second) {
|
||||
cmLinkItem synthItem(depForTarget, item.Cross, item.Backtrace);
|
||||
impl.Libraries.emplace_back(std::move(synthItem), false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Report explicitly linked object files separately.
|
||||
std::string const& maybeObj = item.AsStr();
|
||||
if (cmSystemTools::FileIsFullPath(maybeObj)) {
|
||||
@@ -8930,24 +9042,28 @@ bool cmGeneratorTarget::HaveFortranSources(std::string const& config) const
|
||||
});
|
||||
}
|
||||
|
||||
bool cmGeneratorTarget::HaveCxx20ModuleSources() const
|
||||
bool cmGeneratorTarget::HaveCxx20ModuleSources(std::string* errorMessage) const
|
||||
{
|
||||
auto const& fs_names = this->Target->GetAllFileSetNames();
|
||||
return std::any_of(fs_names.begin(), fs_names.end(),
|
||||
[this](std::string const& name) -> bool {
|
||||
auto const* file_set = this->Target->GetFileSet(name);
|
||||
if (!file_set) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::INTERNAL_ERROR,
|
||||
cmStrCat("Target \"", this->Target->GetName(),
|
||||
"\" is tracked to have file set \"", name,
|
||||
"\", but it was not found."));
|
||||
return false;
|
||||
}
|
||||
return std::any_of(
|
||||
fs_names.begin(), fs_names.end(),
|
||||
[this, errorMessage](std::string const& name) -> bool {
|
||||
auto const* file_set = this->Target->GetFileSet(name);
|
||||
if (!file_set) {
|
||||
auto message = cmStrCat("Target \"", this->Target->GetName(),
|
||||
"\" is tracked to have file set \"", name,
|
||||
"\", but it was not found.");
|
||||
if (errorMessage) {
|
||||
*errorMessage = std::move(message);
|
||||
} else {
|
||||
this->Makefile->IssueMessage(MessageType::INTERNAL_ERROR, message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const& fs_type = file_set->GetType();
|
||||
return fs_type == "CXX_MODULES"_s;
|
||||
});
|
||||
auto const& fs_type = file_set->GetType();
|
||||
return fs_type == "CXX_MODULES"_s;
|
||||
});
|
||||
}
|
||||
|
||||
cmGeneratorTarget::Cxx20SupportLevel cmGeneratorTarget::HaveCxxModuleSupport(
|
||||
|
||||
@@ -31,6 +31,7 @@ class cmGlobalGenerator;
|
||||
class cmLocalGenerator;
|
||||
class cmMakefile;
|
||||
class cmSourceFile;
|
||||
struct cmSyntheticTargetCache;
|
||||
class cmTarget;
|
||||
|
||||
struct cmGeneratorExpressionContext;
|
||||
@@ -116,6 +117,7 @@ public:
|
||||
SourceKindCertificate,
|
||||
SourceKindCustomCommand,
|
||||
SourceKindExternalObject,
|
||||
SourceKindCxxModuleSource,
|
||||
SourceKindExtra,
|
||||
SourceKindHeader,
|
||||
SourceKindIDL,
|
||||
@@ -186,6 +188,8 @@ public:
|
||||
const std::string& config) const;
|
||||
void GetHeaderSources(std::vector<cmSourceFile const*>&,
|
||||
const std::string& config) const;
|
||||
void GetCxxModuleSources(std::vector<cmSourceFile const*>&,
|
||||
const std::string& config) const;
|
||||
void GetExtraSources(std::vector<cmSourceFile const*>&,
|
||||
const std::string& config) const;
|
||||
void GetCustomCommands(std::vector<cmSourceFile const*>&,
|
||||
@@ -929,6 +933,9 @@ public:
|
||||
|
||||
std::string GetImportedXcFrameworkPath(const std::string& config) const;
|
||||
|
||||
bool DiscoverSyntheticTargets(cmSyntheticTargetCache& cache,
|
||||
std::string const& config);
|
||||
|
||||
private:
|
||||
void AddSourceCommon(const std::string& src, bool before = false);
|
||||
|
||||
@@ -1264,8 +1271,11 @@ public:
|
||||
*
|
||||
* This will inspect the target itself to see if C++20 module
|
||||
* support is expected to work based on its sources.
|
||||
*
|
||||
* If `errorMessage` is given a non-`nullptr`, any error message will be
|
||||
* stored in it, otherwise the error will be reported directly.
|
||||
*/
|
||||
bool HaveCxx20ModuleSources() const;
|
||||
bool HaveCxx20ModuleSources(std::string* errorMessage = nullptr) const;
|
||||
|
||||
enum class Cxx20SupportLevel
|
||||
{
|
||||
@@ -1301,6 +1311,8 @@ private:
|
||||
{
|
||||
bool BuiltFileSetCache = false;
|
||||
std::map<std::string, cmFileSet const*> FileSetCache;
|
||||
std::map<cmGeneratorTarget const*, std::vector<cmGeneratorTarget const*>>
|
||||
SyntheticDeps;
|
||||
};
|
||||
mutable std::map<std::string, InfoByConfig> Configs;
|
||||
};
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#include "cmStateDirectory.h"
|
||||
#include "cmStateTypes.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSyntheticTargetCache.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmValue.h"
|
||||
#include "cmVersion.h"
|
||||
@@ -1560,6 +1561,17 @@ bool cmGlobalGenerator::Compute()
|
||||
}
|
||||
#endif
|
||||
|
||||
// Iterate through all targets and set up C++20 module targets.
|
||||
// Create target templates for each imported target with C++20 modules.
|
||||
// INTERFACE library with BMI-generating rules and a collation step?
|
||||
// Maybe INTERFACE libraries with modules files should just do BMI-only?
|
||||
// Make `add_dependencies(imported_target
|
||||
// $<$<TARGET_NAME_IF_EXISTS:uses_imported>:synth1>
|
||||
// $<$<TARGET_NAME_IF_EXISTS:other_uses_imported>:synth2>)`
|
||||
if (!this->DiscoverSyntheticTargets()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add generator specific helper commands
|
||||
for (const auto& localGen : this->LocalGenerators) {
|
||||
localGen->AddHelperCommands();
|
||||
@@ -1784,6 +1796,34 @@ void cmGlobalGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt,
|
||||
entry->second = index++;
|
||||
}
|
||||
|
||||
bool cmGlobalGenerator::DiscoverSyntheticTargets()
|
||||
{
|
||||
cmSyntheticTargetCache cache;
|
||||
|
||||
for (auto const& gen : this->LocalGenerators) {
|
||||
// Because DiscoverSyntheticTargets() adds generator targets, we need to
|
||||
// cache the existing list of generator targets before starting.
|
||||
std::vector<cmGeneratorTarget*> genTargets;
|
||||
genTargets.reserve(gen->GetGeneratorTargets().size());
|
||||
for (auto const& tgt : gen->GetGeneratorTargets()) {
|
||||
genTargets.push_back(tgt.get());
|
||||
}
|
||||
|
||||
for (auto* tgt : genTargets) {
|
||||
std::vector<std::string> const& configs =
|
||||
tgt->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
|
||||
|
||||
for (auto const& config : configs) {
|
||||
if (!tgt->DiscoverSyntheticTargets(cache, config)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmGlobalGenerator::AddHeaderSetVerification()
|
||||
{
|
||||
for (auto const& gen : this->LocalGenerators) {
|
||||
|
||||
@@ -662,6 +662,8 @@ protected:
|
||||
|
||||
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
|
||||
|
||||
bool DiscoverSyntheticTargets();
|
||||
|
||||
bool AddHeaderSetVerification();
|
||||
|
||||
bool AddAutomaticSources();
|
||||
|
||||
@@ -2643,7 +2643,9 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
|
||||
for (cmScanDepInfo const& object : objects) {
|
||||
for (auto const& p : object.Provides) {
|
||||
std::string mod;
|
||||
if (!p.CompiledModulePath.empty()) {
|
||||
if (cmDyndepCollation::IsBmiOnly(export_info, object.PrimaryOutput)) {
|
||||
mod = object.PrimaryOutput;
|
||||
} else if (!p.CompiledModulePath.empty()) {
|
||||
// The scanner provided the path to the module file.
|
||||
mod = p.CompiledModulePath;
|
||||
if (!cmSystemTools::FileIsFullPath(mod)) {
|
||||
@@ -2714,8 +2716,12 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
|
||||
build.Outputs[0] = this->ConvertToNinjaPath(object.PrimaryOutput);
|
||||
build.ImplicitOuts.clear();
|
||||
for (auto const& p : object.Provides) {
|
||||
build.ImplicitOuts.push_back(
|
||||
this->ConvertToNinjaPath(mod_files[p.LogicalName].BmiPath));
|
||||
auto const implicitOut =
|
||||
this->ConvertToNinjaPath(mod_files[p.LogicalName].BmiPath);
|
||||
// Ignore the `provides` when the BMI is the output.
|
||||
if (implicitOut != build.Outputs[0]) {
|
||||
build.ImplicitOuts.emplace_back(implicitOut);
|
||||
}
|
||||
}
|
||||
build.ImplicitDeps.clear();
|
||||
for (auto const& r : object.Requires) {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#include "cmImportedCxxModuleInfo.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "cmCryptoHash.h"
|
||||
#include "cmList.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
|
||||
bool ImportedCxxModuleLookup::Initialized() const
|
||||
{
|
||||
return this->DoneInit;
|
||||
}
|
||||
|
||||
void ImportedCxxModuleLookup::Initialize(std::string const& importedModules)
|
||||
{
|
||||
for (auto const& entry : cmList{ importedModules }) {
|
||||
auto nameSep = entry.find('=');
|
||||
if (nameSep == std::string::npos) {
|
||||
// Invalid entry; ignore.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto name = entry.substr(0, nameSep);
|
||||
|
||||
auto sourceSep = entry.find(',', nameSep);
|
||||
std::string source;
|
||||
if (sourceSep == std::string::npos) {
|
||||
source = entry.substr(nameSep + 1);
|
||||
} else {
|
||||
source = entry.substr(nameSep + 1, sourceSep - nameSep - 1);
|
||||
}
|
||||
|
||||
std::vector<std::string> bmis;
|
||||
if (sourceSep != std::string::npos) {
|
||||
auto bmiPaths = entry.substr(sourceSep + 1);
|
||||
bmis = cmSystemTools::SplitString(bmiPaths, ',');
|
||||
}
|
||||
|
||||
this->ImportedInfo.emplace(source,
|
||||
ImportedCxxModuleInfo{ name, std::move(bmis) });
|
||||
}
|
||||
|
||||
this->DoneInit = true;
|
||||
}
|
||||
|
||||
std::string ImportedCxxModuleLookup::BmiNameForSource(std::string const& path)
|
||||
{
|
||||
auto genit = this->GeneratorInfo.find(path);
|
||||
if (genit != this->GeneratorInfo.end()) {
|
||||
return genit->second.BmiName;
|
||||
}
|
||||
|
||||
auto importit = this->ImportedInfo.find(path);
|
||||
std::string bmiName;
|
||||
auto hasher = cmCryptoHash::New("SHA3_512");
|
||||
constexpr size_t HASH_TRUNCATION = 12;
|
||||
if (importit != this->ImportedInfo.end()) {
|
||||
auto safename = hasher->HashString(importit->second.Name);
|
||||
bmiName = cmStrCat(safename.substr(0, HASH_TRUNCATION), ".bmi");
|
||||
} else {
|
||||
auto dirhash = hasher->HashString(path);
|
||||
bmiName = cmStrCat(dirhash.substr(0, HASH_TRUNCATION), ".bmi");
|
||||
}
|
||||
|
||||
this->GeneratorInfo.emplace(
|
||||
path, ImportedCxxModuleGeneratorInfo{ &importit->second, bmiName });
|
||||
return bmiName;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct ImportedCxxModuleInfo
|
||||
{
|
||||
std::string const Name;
|
||||
std::vector<std::string> const AvailableBmis;
|
||||
};
|
||||
|
||||
struct ImportedCxxModuleGeneratorInfo
|
||||
{
|
||||
ImportedCxxModuleInfo const* ImportedInfo;
|
||||
std::string const BmiName;
|
||||
};
|
||||
|
||||
struct ImportedCxxModuleLookup
|
||||
{
|
||||
ImportedCxxModuleLookup() = default;
|
||||
~ImportedCxxModuleLookup() = default;
|
||||
|
||||
bool Initialized() const;
|
||||
void Initialize(std::string const& importedModules);
|
||||
|
||||
std::string BmiNameForSource(std::string const& path);
|
||||
|
||||
private:
|
||||
bool DoneInit = false;
|
||||
std::map<std::string, ImportedCxxModuleInfo> ImportedInfo;
|
||||
std::map<std::string, ImportedCxxModuleGeneratorInfo> GeneratorInfo;
|
||||
};
|
||||
@@ -62,12 +62,15 @@ cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator() = default;
|
||||
|
||||
void cmNinjaNormalTargetGenerator::Generate(const std::string& config)
|
||||
{
|
||||
std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
|
||||
if (this->TargetLinkLanguage(config).empty()) {
|
||||
cmSystemTools::Error(
|
||||
cmStrCat("CMake can not determine linker language for target: ",
|
||||
this->GetGeneratorTarget()->GetName()));
|
||||
return;
|
||||
if (this->GetGeneratorTarget()->GetType() !=
|
||||
cmStateEnums::INTERFACE_LIBRARY) {
|
||||
std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
|
||||
if (this->TargetLinkLanguage(config).empty()) {
|
||||
cmSystemTools::Error(
|
||||
cmStrCat("CMake can not determine linker language for target: ",
|
||||
this->GetGeneratorTarget()->GetName()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the rules for each language.
|
||||
@@ -87,6 +90,34 @@ void cmNinjaNormalTargetGenerator::Generate(const std::string& config)
|
||||
|
||||
if (this->GetGeneratorTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) {
|
||||
this->WriteObjectLibStatement(config);
|
||||
} else if (this->GetGeneratorTarget()->GetType() ==
|
||||
cmStateEnums::INTERFACE_LIBRARY) {
|
||||
bool haveCxxModuleSources = false;
|
||||
if (this->GetGeneratorTarget()->HaveCxx20ModuleSources()) {
|
||||
haveCxxModuleSources = true;
|
||||
}
|
||||
|
||||
if (!haveCxxModuleSources) {
|
||||
cmSystemTools::Error(cmStrCat(
|
||||
"Ninja does not support INTERFACE libraries without C++ module "
|
||||
"sources as a normal target: ",
|
||||
this->GetGeneratorTarget()->GetName()));
|
||||
return;
|
||||
}
|
||||
|
||||
firstForConfig = true;
|
||||
for (auto const& fileConfig : this->GetConfigNames()) {
|
||||
if (!this->GetGlobalGenerator()
|
||||
->GetCrossConfigs(fileConfig)
|
||||
.count(config)) {
|
||||
continue;
|
||||
}
|
||||
if (haveCxxModuleSources) {
|
||||
this->WriteCxxModuleLibraryStatement(config, fileConfig,
|
||||
firstForConfig);
|
||||
}
|
||||
firstForConfig = false;
|
||||
}
|
||||
} else {
|
||||
firstForConfig = true;
|
||||
for (auto const& fileConfig : this->GetConfigNames()) {
|
||||
@@ -123,12 +154,26 @@ void cmNinjaNormalTargetGenerator::WriteLanguagesRules(
|
||||
#endif
|
||||
|
||||
// Write rules for languages compiled in this target.
|
||||
std::set<std::string> languages;
|
||||
std::vector<cmSourceFile const*> sourceFiles;
|
||||
this->GetGeneratorTarget()->GetObjectSources(sourceFiles, config);
|
||||
if (this->HaveRequiredLanguages(sourceFiles, languages)) {
|
||||
for (std::string const& language : languages) {
|
||||
this->WriteLanguageRules(language, config);
|
||||
{
|
||||
std::set<std::string> languages;
|
||||
std::vector<cmSourceFile const*> sourceFiles;
|
||||
this->GetGeneratorTarget()->GetObjectSources(sourceFiles, config);
|
||||
if (this->HaveRequiredLanguages(sourceFiles, languages)) {
|
||||
for (std::string const& language : languages) {
|
||||
this->WriteLanguageRules(language, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write rules for languages in BMI-only rules.
|
||||
{
|
||||
std::set<std::string> languages;
|
||||
std::vector<cmSourceFile const*> sourceFiles;
|
||||
this->GetGeneratorTarget()->GetCxxModuleSources(sourceFiles, config);
|
||||
if (this->HaveRequiredLanguages(sourceFiles, languages)) {
|
||||
for (std::string const& language : languages) {
|
||||
this->WriteLanguageRules(language, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1637,6 +1682,34 @@ void cmNinjaNormalTargetGenerator::WriteObjectLibStatement(
|
||||
this->GetTargetName(), this->GetGeneratorTarget(), config);
|
||||
}
|
||||
|
||||
void cmNinjaNormalTargetGenerator::WriteCxxModuleLibraryStatement(
|
||||
const std::string& config, const std::string& /*fileConfig*/,
|
||||
bool firstForConfig)
|
||||
{
|
||||
// TODO: How to use `fileConfig` properly?
|
||||
|
||||
// Write a phony output that depends on the scanning output.
|
||||
{
|
||||
cmNinjaBuild build("phony");
|
||||
build.Comment =
|
||||
cmStrCat("Imported C++ module library ", this->GetTargetName());
|
||||
this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
|
||||
build.Outputs, config);
|
||||
if (firstForConfig) {
|
||||
this->GetLocalGenerator()->AppendTargetOutputs(
|
||||
this->GetGeneratorTarget(),
|
||||
this->GetGlobalGenerator()->GetByproductsForCleanTarget(config),
|
||||
config);
|
||||
}
|
||||
build.ExplicitDeps.emplace_back(this->GetDyndepFilePath("CXX", config));
|
||||
this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(), build);
|
||||
}
|
||||
|
||||
// Add aliases for the target name.
|
||||
this->GetGlobalGenerator()->AddTargetAlias(
|
||||
this->GetTargetName(), this->GetGeneratorTarget(), config);
|
||||
}
|
||||
|
||||
cmGeneratorTarget::Names cmNinjaNormalTargetGenerator::TargetNames(
|
||||
const std::string& config) const
|
||||
{
|
||||
|
||||
@@ -49,6 +49,9 @@ private:
|
||||
const std::string& output);
|
||||
|
||||
void WriteObjectLibStatement(const std::string& config);
|
||||
void WriteCxxModuleLibraryStatement(const std::string& config,
|
||||
const std::string& fileConfig,
|
||||
bool firstForConfig);
|
||||
|
||||
std::vector<std::string> ComputeLinkCmd(const std::string& config);
|
||||
std::vector<std::string> ComputeDeviceLinkCmd();
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "cmGeneratedFileStream.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmGeneratorTarget.h"
|
||||
#include "cmGlobalCommonGenerator.h"
|
||||
#include "cmGlobalNinjaGenerator.h"
|
||||
#include "cmList.h"
|
||||
#include "cmLocalGenerator.h"
|
||||
@@ -59,8 +60,13 @@ std::unique_ptr<cmNinjaTargetGenerator> cmNinjaTargetGenerator::New(
|
||||
case cmStateEnums::OBJECT_LIBRARY:
|
||||
return cm::make_unique<cmNinjaNormalTargetGenerator>(target);
|
||||
|
||||
case cmStateEnums::UTILITY:
|
||||
case cmStateEnums::INTERFACE_LIBRARY:
|
||||
if (target->HaveCxx20ModuleSources()) {
|
||||
return cm::make_unique<cmNinjaNormalTargetGenerator>(target);
|
||||
}
|
||||
CM_FALLTHROUGH;
|
||||
|
||||
case cmStateEnums::UTILITY:
|
||||
case cmStateEnums::GLOBAL_TARGET:
|
||||
return cm::make_unique<cmNinjaUtilityTargetGenerator>(target);
|
||||
|
||||
@@ -167,7 +173,7 @@ std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget(
|
||||
// Refactor it.
|
||||
std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
|
||||
cmSourceFile const* source, const std::string& language,
|
||||
const std::string& config)
|
||||
const std::string& config, const std::string& objectFileName)
|
||||
{
|
||||
std::unordered_map<std::string, std::string> pchSources;
|
||||
std::vector<std::string> architectures =
|
||||
@@ -247,6 +253,18 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
|
||||
"\nin a file set of type \"", fs->GetType(),
|
||||
R"(" but the source is not classified as a "CXX" source.)"));
|
||||
}
|
||||
|
||||
if (!this->GeneratorTarget->Target->IsNormal()) {
|
||||
auto flag = this->GetMakefile()->GetSafeDefinition(
|
||||
"CMAKE_EXPERIMENTAL_CXX_MODULE_BMI_ONLY_FLAG");
|
||||
cmRulePlaceholderExpander::RuleVariables compileObjectVars;
|
||||
compileObjectVars.Object = objectFileName.c_str();
|
||||
auto rulePlaceholderExpander =
|
||||
this->GetLocalGenerator()->CreateRulePlaceholderExpander();
|
||||
rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
|
||||
flag, compileObjectVars);
|
||||
this->LocalGenerator->AppendCompileOptions(flags, flag);
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
@@ -394,6 +412,31 @@ std::string cmNinjaTargetGenerator::GetObjectFilePath(
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string cmNinjaTargetGenerator::GetBmiFilePath(
|
||||
cmSourceFile const* source, const std::string& config) const
|
||||
{
|
||||
std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
|
||||
if (!path.empty()) {
|
||||
path += '/';
|
||||
}
|
||||
|
||||
auto& importedConfigInfo = this->Configs.at(config).ImportedCxxModules;
|
||||
if (!importedConfigInfo.Initialized()) {
|
||||
std::string configUpper = cmSystemTools::UpperCase(config);
|
||||
std::string propName = cmStrCat("IMPORTED_CXX_MODULES_", configUpper);
|
||||
auto value = this->GeneratorTarget->GetSafeProperty(propName);
|
||||
importedConfigInfo.Initialize(value);
|
||||
}
|
||||
|
||||
std::string bmiName =
|
||||
importedConfigInfo.BmiNameForSource(source->GetFullPath());
|
||||
|
||||
path += cmStrCat(
|
||||
this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
|
||||
this->GetGlobalGenerator()->ConfigDirectory(config), '/', bmiName);
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string cmNinjaTargetGenerator::GetClangTidyReplacementsFilePath(
|
||||
std::string const& directory, cmSourceFile const& source,
|
||||
std::string const& config) const
|
||||
@@ -1027,6 +1070,16 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<cmSourceFile const*> bmiOnlySources;
|
||||
this->GeneratorTarget->GetCxxModuleSources(bmiOnlySources, config);
|
||||
|
||||
for (cmSourceFile const* sf : bmiOnlySources) {
|
||||
this->WriteCxxModuleBmiBuildStatement(sf, config, fileConfig,
|
||||
firstForConfig);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& langScanningFiles : this->Configs[config].ScanningInfo) {
|
||||
std::string const& language = langScanningFiles.first;
|
||||
std::vector<ScanningFiles> const& scanningFiles = langScanningFiles.second;
|
||||
@@ -1149,22 +1202,22 @@ cmNinjaBuild GetScanBuildStatement(const std::string& ruleName,
|
||||
scanBuild.Variables["OBJ_FILE"] = objectFileName;
|
||||
|
||||
// Tell dependency scanner where to store dyndep intermediate results.
|
||||
std::string const& ddiFile = cmStrCat(objectFileName, ".ddi");
|
||||
scanBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
|
||||
std::string ddiFileName = cmStrCat(objectFileName, ".ddi");
|
||||
scanBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFileName;
|
||||
|
||||
// Outputs of the scan/preprocessor build statement.
|
||||
if (compilePP) {
|
||||
scanBuild.Outputs.push_back(ppFileName);
|
||||
scanBuild.ImplicitOuts.push_back(ddiFile);
|
||||
scanBuild.ImplicitOuts.push_back(ddiFileName);
|
||||
} else {
|
||||
scanBuild.Outputs.push_back(ddiFile);
|
||||
scanBuild.Outputs.push_back(ddiFileName);
|
||||
scanBuild.Variables["PREPROCESSED_OUTPUT_FILE"] = ppFileName;
|
||||
if (!compilationPreprocesses) {
|
||||
// Compilation does not preprocess and we are not compiling an
|
||||
// already-preprocessed source. Make compilation depend on the scan
|
||||
// results to honor implicit dependencies discovered during scanning
|
||||
// (such as Fortran INCLUDE directives).
|
||||
objBuild.ImplicitDeps.emplace_back(ddiFile);
|
||||
objBuild.ImplicitDeps.emplace_back(ddiFileName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1214,7 +1267,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
|
||||
cmNinjaBuild objBuild(this->LanguageCompilerRule(
|
||||
language, config, needDyndep ? WithScanning::Yes : WithScanning::No));
|
||||
cmNinjaVars& vars = objBuild.Variables;
|
||||
vars["FLAGS"] = this->ComputeFlagsForObject(source, language, config);
|
||||
vars["FLAGS"] =
|
||||
this->ComputeFlagsForObject(source, language, config, objectFileName);
|
||||
vars["DEFINES"] = this->ComputeDefines(source, language, config);
|
||||
vars["INCLUDES"] = this->ComputeIncludes(source, language, config);
|
||||
|
||||
@@ -1545,6 +1599,155 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
|
||||
}
|
||||
}
|
||||
|
||||
void cmNinjaTargetGenerator::WriteCxxModuleBmiBuildStatement(
|
||||
cmSourceFile const* source, const std::string& config,
|
||||
const std::string& fileConfig, bool firstForConfig)
|
||||
{
|
||||
std::string const language = source->GetLanguage();
|
||||
if (language != "CXX"_s) {
|
||||
this->GetMakefile()->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("Source file '", source->GetFullPath(), "' of target '",
|
||||
this->GetTargetName(), "' is a '", language,
|
||||
"' source but must be 'CXX' in order to have a BMI build "
|
||||
"statement generated."));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string const sourceFilePath = this->GetCompiledSourceNinjaPath(source);
|
||||
std::string const bmiDir = this->ConvertToNinjaPath(
|
||||
cmStrCat(this->GeneratorTarget->GetSupportDirectory(),
|
||||
this->GetGlobalGenerator()->ConfigDirectory(config)));
|
||||
std::string const bmiFileName =
|
||||
this->ConvertToNinjaPath(this->GetBmiFilePath(source, config));
|
||||
std::string const bmiFileDir = cmSystemTools::GetFilenamePath(bmiFileName);
|
||||
|
||||
int const commandLineLengthLimit = this->ForceResponseFile() ? -1 : 0;
|
||||
|
||||
cmNinjaBuild bmiBuild(
|
||||
this->LanguageCompilerRule(language, config, WithScanning::Yes));
|
||||
cmNinjaVars& vars = bmiBuild.Variables;
|
||||
vars["FLAGS"] =
|
||||
this->ComputeFlagsForObject(source, language, config, bmiFileName);
|
||||
vars["DEFINES"] = this->ComputeDefines(source, language, config);
|
||||
vars["INCLUDES"] = this->ComputeIncludes(source, language, config);
|
||||
|
||||
if (this->GetMakefile()->GetSafeDefinition(
|
||||
cmStrCat("CMAKE_", language, "_DEPFILE_FORMAT")) != "msvc"_s) {
|
||||
bool replaceExt(false);
|
||||
if (!language.empty()) {
|
||||
std::string repVar =
|
||||
cmStrCat("CMAKE_", language, "_DEPFILE_EXTENSION_REPLACE");
|
||||
replaceExt = this->Makefile->IsOn(repVar);
|
||||
}
|
||||
if (!replaceExt) {
|
||||
// use original code
|
||||
vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
|
||||
cmStrCat(bmiFileName, ".d"), cmOutputConverter::SHELL);
|
||||
} else {
|
||||
// Replace the original source file extension with the
|
||||
// depend file extension.
|
||||
std::string dependFileName = cmStrCat(
|
||||
cmSystemTools::GetFilenameWithoutLastExtension(bmiFileName), ".d");
|
||||
vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
|
||||
cmStrCat(bmiFileDir, '/', dependFileName), cmOutputConverter::SHELL);
|
||||
}
|
||||
}
|
||||
|
||||
std::string d =
|
||||
this->GeneratorTarget->GetClangTidyExportFixesDirectory(language);
|
||||
if (!d.empty()) {
|
||||
this->GlobalCommonGenerator->AddClangTidyExportFixesDir(d);
|
||||
std::string fixesFile =
|
||||
this->GetClangTidyReplacementsFilePath(d, *source, config);
|
||||
this->GlobalCommonGenerator->AddClangTidyExportFixesFile(fixesFile);
|
||||
cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(fixesFile));
|
||||
fixesFile = this->ConvertToNinjaPath(fixesFile);
|
||||
vars["CLANG_TIDY_EXPORT_FIXES"] = fixesFile;
|
||||
}
|
||||
|
||||
if (firstForConfig) {
|
||||
this->ExportObjectCompileCommand(
|
||||
language, sourceFilePath, bmiDir, bmiFileName, bmiFileDir, vars["FLAGS"],
|
||||
vars["DEFINES"], vars["INCLUDES"], config);
|
||||
}
|
||||
|
||||
bmiBuild.Outputs.push_back(bmiFileName);
|
||||
bmiBuild.ExplicitDeps.push_back(sourceFilePath);
|
||||
|
||||
std::vector<std::string> depList;
|
||||
|
||||
std::vector<std::string> architectures =
|
||||
this->GeneratorTarget->GetAppleArchs(config, language);
|
||||
if (architectures.empty()) {
|
||||
architectures.emplace_back();
|
||||
}
|
||||
|
||||
bmiBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget(config));
|
||||
|
||||
// For some cases we scan to dynamically discover dependencies.
|
||||
std::string modmapFormat;
|
||||
if (true) {
|
||||
std::string const modmapFormatVar =
|
||||
cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FORMAT");
|
||||
modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar);
|
||||
}
|
||||
|
||||
{
|
||||
bool const compilePPWithDefines = this->CompileWithDefines(language);
|
||||
|
||||
std::string scanRuleName = this->LanguageScanRule(language, config);
|
||||
std::string ppFileName = cmStrCat(bmiFileName, ".ddi.i");
|
||||
|
||||
cmNinjaBuild ppBuild = GetScanBuildStatement(
|
||||
scanRuleName, ppFileName, false, compilePPWithDefines, true, bmiBuild,
|
||||
vars, bmiFileName, this->LocalGenerator);
|
||||
|
||||
ScanningFiles scanningFiles;
|
||||
|
||||
if (firstForConfig) {
|
||||
scanningFiles.ScanningOutput = cmStrCat(bmiFileName, ".ddi");
|
||||
}
|
||||
|
||||
this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
|
||||
ppBuild.Variables);
|
||||
|
||||
this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
|
||||
ppBuild, commandLineLengthLimit);
|
||||
|
||||
std::string const dyndep = this->GetDyndepFilePath(language, config);
|
||||
bmiBuild.OrderOnlyDeps.push_back(dyndep);
|
||||
vars["dyndep"] = dyndep;
|
||||
|
||||
if (!modmapFormat.empty()) {
|
||||
std::string ddModmapFile = cmStrCat(bmiFileName, ".modmap");
|
||||
vars["DYNDEP_MODULE_MAP_FILE"] = ddModmapFile;
|
||||
scanningFiles.ModuleMapFile = std::move(ddModmapFile);
|
||||
}
|
||||
|
||||
if (!scanningFiles.IsEmpty()) {
|
||||
this->Configs[config].ScanningInfo[language].emplace_back(scanningFiles);
|
||||
}
|
||||
}
|
||||
|
||||
this->EnsureParentDirectoryExists(bmiFileName);
|
||||
|
||||
vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
|
||||
bmiDir, cmOutputConverter::SHELL);
|
||||
vars["OBJECT_FILE_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
|
||||
bmiFileDir, cmOutputConverter::SHELL);
|
||||
|
||||
this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
|
||||
vars);
|
||||
|
||||
this->SetMsvcTargetPdbVariable(vars, config);
|
||||
|
||||
bmiBuild.RspFile = cmStrCat(bmiFileName, ".rsp");
|
||||
|
||||
this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
|
||||
bmiBuild, commandLineLengthLimit);
|
||||
}
|
||||
|
||||
void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
|
||||
const std::string& config)
|
||||
{
|
||||
@@ -1605,6 +1808,9 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
|
||||
cb.ObjectFilePath = [this](cmSourceFile const* sf, std::string const& cnf) {
|
||||
return this->GetObjectFilePath(sf, cnf);
|
||||
};
|
||||
cb.BmiFilePath = [this](cmSourceFile const* sf, std::string const& cnf) {
|
||||
return this->GetBmiFilePath(sf, cnf);
|
||||
};
|
||||
|
||||
#if !defined(CMAKE_BOOTSTRAP)
|
||||
cmDyndepCollation::AddCollationInformation(tdi, this->GeneratorTarget,
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "cmCommonTargetGenerator.h"
|
||||
#include "cmGlobalNinjaGenerator.h"
|
||||
#include "cmImportedCxxModuleInfo.h"
|
||||
#include "cmNinjaTypes.h"
|
||||
#include "cmOSXBundleGenerator.h"
|
||||
|
||||
@@ -91,7 +92,8 @@ protected:
|
||||
*/
|
||||
std::string ComputeFlagsForObject(cmSourceFile const* source,
|
||||
const std::string& language,
|
||||
const std::string& config);
|
||||
const std::string& config,
|
||||
const std::string& objectFileName);
|
||||
|
||||
void AddIncludeFlags(std::string& flags, std::string const& lang,
|
||||
const std::string& config) override;
|
||||
@@ -129,6 +131,8 @@ protected:
|
||||
/// @return the object file path for the given @a source.
|
||||
std::string GetObjectFilePath(cmSourceFile const* source,
|
||||
const std::string& config) const;
|
||||
std::string GetBmiFilePath(cmSourceFile const* source,
|
||||
const std::string& config) const;
|
||||
|
||||
/// @return the preprocessed source file path for the given @a source.
|
||||
std::string GetPreprocessedFilePath(cmSourceFile const* source,
|
||||
@@ -163,6 +167,10 @@ protected:
|
||||
void WriteObjectBuildStatements(const std::string& config,
|
||||
const std::string& fileConfig,
|
||||
bool firstForConfig);
|
||||
void WriteCxxModuleBmiBuildStatement(cmSourceFile const* source,
|
||||
const std::string& config,
|
||||
const std::string& fileConfig,
|
||||
bool firstForConfig);
|
||||
void WriteObjectBuildStatement(cmSourceFile const* source,
|
||||
const std::string& config,
|
||||
const std::string& fileConfig,
|
||||
@@ -239,6 +247,8 @@ private:
|
||||
cmNinjaDeps Objects;
|
||||
// Dyndep Support
|
||||
std::map<std::string, std::vector<ScanningFiles>> ScanningInfo;
|
||||
// Imported C++ module info.
|
||||
mutable ImportedCxxModuleLookup ImportedCxxModules;
|
||||
// Swift Support
|
||||
Json::Value SwiftOutputMap;
|
||||
std::vector<cmCustomCommand const*> CustomCommands;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class cmGeneratorTarget;
|
||||
|
||||
struct cmSyntheticTargetCache
|
||||
{
|
||||
std::map<std::string, cmGeneratorTarget const*> CxxModuleTargets;
|
||||
};
|
||||
+227
-6
@@ -246,9 +246,9 @@ struct UsageRequirementProperty
|
||||
{
|
||||
}
|
||||
|
||||
void CopyFromDirectory(cmBTStringRange directoryEntries)
|
||||
void CopyFromEntries(cmBTStringRange entries)
|
||||
{
|
||||
return cm::append(this->Entries, directoryEntries);
|
||||
return cm::append(this->Entries, entries);
|
||||
}
|
||||
|
||||
enum class Action
|
||||
@@ -673,6 +673,11 @@ public:
|
||||
UsageRequirementProperty InterfaceLinkLibraries;
|
||||
UsageRequirementProperty InterfaceLinkLibrariesDirect;
|
||||
UsageRequirementProperty InterfaceLinkLibrariesDirectExclude;
|
||||
UsageRequirementProperty ImportedCxxModulesIncludeDirectories;
|
||||
UsageRequirementProperty ImportedCxxModulesCompileDefinitions;
|
||||
UsageRequirementProperty ImportedCxxModulesCompileFeatures;
|
||||
UsageRequirementProperty ImportedCxxModulesCompileOptions;
|
||||
UsageRequirementProperty ImportedCxxModulesLinkLibraries;
|
||||
|
||||
FileSetType HeadersFileSets;
|
||||
FileSetType CxxModulesFileSets;
|
||||
@@ -723,6 +728,14 @@ cmTargetInternals::cmTargetInternals()
|
||||
, InterfaceLinkLibrariesDirect("INTERFACE_LINK_LIBRARIES_DIRECT"_s)
|
||||
, InterfaceLinkLibrariesDirectExclude(
|
||||
"INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"_s)
|
||||
, ImportedCxxModulesIncludeDirectories(
|
||||
"IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES"_s)
|
||||
, ImportedCxxModulesCompileDefinitions(
|
||||
"IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS"_s)
|
||||
, ImportedCxxModulesCompileFeatures(
|
||||
"IMPORTED_CXX_MODULES_COMPILE_FEATURES"_s)
|
||||
, ImportedCxxModulesCompileOptions("IMPORTED_CXX_MODULES_COMPILE_OPTIONS"_s)
|
||||
, ImportedCxxModulesLinkLibraries("IMPORTED_CXX_MODULES_LINK_LIBRARIES"_s)
|
||||
, HeadersFileSets("HEADERS"_s, "HEADER_DIRS"_s, "HEADER_SET"_s,
|
||||
"HEADER_DIRS_"_s, "HEADER_SET_"_s, "Header"_s,
|
||||
"The default header set"_s, "Header set"_s,
|
||||
@@ -951,7 +964,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
|
||||
if (this->IsNormal()) {
|
||||
// Initialize the INCLUDE_DIRECTORIES property based on the current value
|
||||
// of the same directory property:
|
||||
this->impl->IncludeDirectories.CopyFromDirectory(
|
||||
this->impl->IncludeDirectories.CopyFromEntries(
|
||||
this->impl->Makefile->GetIncludeDirectoriesEntries());
|
||||
|
||||
{
|
||||
@@ -960,11 +973,11 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
|
||||
sysInc.end());
|
||||
}
|
||||
|
||||
this->impl->CompileOptions.CopyFromDirectory(
|
||||
this->impl->CompileOptions.CopyFromEntries(
|
||||
this->impl->Makefile->GetCompileOptionsEntries());
|
||||
this->impl->LinkOptions.CopyFromDirectory(
|
||||
this->impl->LinkOptions.CopyFromEntries(
|
||||
this->impl->Makefile->GetLinkOptionsEntries());
|
||||
this->impl->LinkDirectories.CopyFromDirectory(
|
||||
this->impl->LinkDirectories.CopyFromEntries(
|
||||
this->impl->Makefile->GetLinkDirectoriesEntries());
|
||||
}
|
||||
|
||||
@@ -1735,6 +1748,186 @@ cmBTStringRange cmTarget::GetLinkInterfaceDirectExcludeEntries() const
|
||||
return cmMakeRange(this->impl->InterfaceLinkLibrariesDirectExclude.Entries);
|
||||
}
|
||||
|
||||
void cmTarget::CopyPolicyStatuses(cmTarget const* tgt)
|
||||
{
|
||||
// Normal targets cannot be the target of a copy.
|
||||
assert(!this->IsNormal());
|
||||
// Imported targets cannot be the target of a copy.
|
||||
assert(!this->IsImported());
|
||||
// Only imported targets can be the source of a copy.
|
||||
assert(tgt->IsImported());
|
||||
|
||||
this->impl->PolicyMap = tgt->impl->PolicyMap;
|
||||
}
|
||||
|
||||
void cmTarget::CopyImportedCxxModulesEntries(cmTarget const* tgt)
|
||||
{
|
||||
// Normal targets cannot be the target of a copy.
|
||||
assert(!this->IsNormal());
|
||||
// Imported targets cannot be the target of a copy.
|
||||
assert(!this->IsImported());
|
||||
// Only imported targets can be the source of a copy.
|
||||
assert(tgt->IsImported());
|
||||
|
||||
this->impl->IncludeDirectories.Entries.clear();
|
||||
this->impl->IncludeDirectories.CopyFromEntries(
|
||||
cmMakeRange(tgt->impl->ImportedCxxModulesIncludeDirectories.Entries));
|
||||
this->impl->CompileDefinitions.Entries.clear();
|
||||
this->impl->CompileDefinitions.CopyFromEntries(
|
||||
cmMakeRange(tgt->impl->ImportedCxxModulesCompileDefinitions.Entries));
|
||||
this->impl->CompileFeatures.Entries.clear();
|
||||
this->impl->CompileFeatures.CopyFromEntries(
|
||||
cmMakeRange(tgt->impl->ImportedCxxModulesCompileFeatures.Entries));
|
||||
this->impl->CompileOptions.Entries.clear();
|
||||
this->impl->CompileOptions.CopyFromEntries(
|
||||
cmMakeRange(tgt->impl->ImportedCxxModulesCompileOptions.Entries));
|
||||
this->impl->LinkLibraries.Entries.clear();
|
||||
this->impl->LinkLibraries.CopyFromEntries(
|
||||
cmMakeRange(tgt->impl->LinkLibraries.Entries));
|
||||
|
||||
// Copy the C++ module fileset entries from `tgt`'s `INTERFACE` to this
|
||||
// target's `PRIVATE`.
|
||||
this->impl->CxxModulesFileSets.SelfEntries.Entries.clear();
|
||||
this->impl->CxxModulesFileSets.SelfEntries.Entries =
|
||||
tgt->impl->CxxModulesFileSets.InterfaceEntries.Entries;
|
||||
}
|
||||
|
||||
void cmTarget::CopyImportedCxxModulesProperties(cmTarget const* tgt)
|
||||
{
|
||||
// Normal targets cannot be the target of a copy.
|
||||
assert(!this->IsNormal());
|
||||
// Imported targets cannot be the target of a copy.
|
||||
assert(!this->IsImported());
|
||||
// Only imported targets can be the source of a copy.
|
||||
assert(tgt->IsImported());
|
||||
|
||||
// The list of properties that are relevant here include:
|
||||
// - compilation-specific properties for any language or platform
|
||||
// - compilation-specific properties for C++
|
||||
// - build graph-specific properties that affect compilation
|
||||
// - IDE metadata properties
|
||||
// - static analysis properties
|
||||
|
||||
static const std::string propertiesToCopy[] = {
|
||||
// Compilation properties
|
||||
"DEFINE_SYMBOL",
|
||||
"DEPRECATION",
|
||||
"NO_SYSTEM_FROM_IMPORTED",
|
||||
"POSITION_INDEPENDENT_CODE",
|
||||
"VISIBILITY_INLINES_HIDDEN",
|
||||
// -- Platforms
|
||||
// ---- Android
|
||||
"ANDROID_API",
|
||||
"ANDROID_API_MIN",
|
||||
"ANDROID_ARCH",
|
||||
"ANDROID_STL_TYPE",
|
||||
// ---- macOS
|
||||
"OSX_ARCHITECTURES",
|
||||
// ---- Windows
|
||||
"MSVC_DEBUG_INFORMATION_FORMAT",
|
||||
"MSVC_RUNTIME_LIBRARY",
|
||||
"VS_PLATFORM_TOOLSET",
|
||||
// ---- OpenWatcom
|
||||
"WATCOM_RUNTIME_LIBRARY",
|
||||
// -- Language
|
||||
// ---- C++
|
||||
"CXX_COMPILER_LAUNCHER",
|
||||
"CXX_STANDARD",
|
||||
"CXX_STANDARD_REQUIRED",
|
||||
"CXX_EXTENSIONS",
|
||||
"CXX_VISIBILITY_PRESET",
|
||||
|
||||
// Static analysis
|
||||
"CXX_CLANG_TIDY",
|
||||
"CXX_CLANG_TIDY_EXPORT_FIXES_DIR",
|
||||
"CXX_CPPLINT",
|
||||
"CXX_CPPCHECK",
|
||||
"CXX_INCLUDE_WHAT_YOU_USE",
|
||||
|
||||
// Build graph properties
|
||||
"EXCLUDE_FROM_ALL",
|
||||
"EXCLUDE_FROM_DEFAULT_BUILD",
|
||||
"OPTIMIZE_DEPENDENCIES",
|
||||
// -- Ninja
|
||||
"JOB_POOL_COMPILE",
|
||||
// -- Visual Studio
|
||||
"VS_NO_COMPILE_BATCHING",
|
||||
"VS_PROJECT_IMPORT",
|
||||
|
||||
// Metadata
|
||||
"EchoString",
|
||||
"EXPORT_COMPILE_COMMANDS",
|
||||
"FOLDER",
|
||||
"LABELS",
|
||||
"PROJECT_LABEL",
|
||||
"SYSTEM",
|
||||
};
|
||||
|
||||
auto copyProperty = [this, tgt](std::string const& prop) -> cmValue {
|
||||
cmValue value = tgt->GetProperty(prop);
|
||||
// Always set the property; it may have been explicitly unset.
|
||||
this->SetProperty(prop, value);
|
||||
return value;
|
||||
};
|
||||
|
||||
for (auto const& prop : propertiesToCopy) {
|
||||
copyProperty(prop);
|
||||
}
|
||||
|
||||
static const cm::static_string_view perConfigPropertiesToCopy[] = {
|
||||
"EXCLUDE_FROM_DEFAULT_BUILD_"_s,
|
||||
"IMPORTED_CXX_MODULES_"_s,
|
||||
"MAP_IMPORTED_CONFIG_"_s,
|
||||
"OSX_ARCHITECTURES_"_s,
|
||||
};
|
||||
|
||||
std::vector<std::string> configNames =
|
||||
this->impl->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
|
||||
for (std::string const& configName : configNames) {
|
||||
std::string configUpper = cmSystemTools::UpperCase(configName);
|
||||
for (auto const& perConfigProp : perConfigPropertiesToCopy) {
|
||||
copyProperty(cmStrCat(perConfigProp, configUpper));
|
||||
}
|
||||
}
|
||||
|
||||
if (this->GetGlobalGenerator()->IsXcode()) {
|
||||
cmValue xcodeGenerateScheme = copyProperty("XCODE_GENERATE_SCHEME");
|
||||
|
||||
// TODO: Make sure these show up on the imported target in the first place
|
||||
// XCODE_ATTRIBUTE_???
|
||||
|
||||
if (xcodeGenerateScheme.IsOn()) {
|
||||
#ifdef __APPLE__
|
||||
static const std::string xcodeSchemePropertiesToCopy[] = {
|
||||
// FIXME: Do all of these apply? Do they matter?
|
||||
"XCODE_SCHEME_ADDRESS_SANITIZER",
|
||||
"XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN",
|
||||
"XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER",
|
||||
"XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS",
|
||||
"XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE",
|
||||
"XCODE_SCHEME_ENABLE_GPU_API_VALIDATION",
|
||||
"XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION",
|
||||
"XCODE_SCHEME_GUARD_MALLOC",
|
||||
"XCODE_SCHEME_LAUNCH_CONFIGURATION",
|
||||
"XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP",
|
||||
"XCODE_SCHEME_MALLOC_GUARD_EDGES",
|
||||
"XCODE_SCHEME_MALLOC_SCRIBBLE",
|
||||
"XCODE_SCHEME_MALLOC_STACK",
|
||||
"XCODE_SCHEME_THREAD_SANITIZER",
|
||||
"XCODE_SCHEME_THREAD_SANITIZER_STOP",
|
||||
"XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER",
|
||||
"XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP",
|
||||
"XCODE_SCHEME_ZOMBIE_OBJECTS",
|
||||
};
|
||||
|
||||
for (auto const& xcodeProperty : xcodeSchemePropertiesToCopy) {
|
||||
copyProperty(xcodeProperty);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmBTStringRange cmTarget::GetHeaderSetsEntries() const
|
||||
{
|
||||
return cmMakeRange(this->impl->HeadersFileSets.SelfEntries.Entries);
|
||||
@@ -1777,6 +1970,11 @@ MAKE_PROP(IMPORTED);
|
||||
MAKE_PROP(IMPORTED_GLOBAL);
|
||||
MAKE_PROP(INCLUDE_DIRECTORIES);
|
||||
MAKE_PROP(LINK_OPTIONS);
|
||||
MAKE_PROP(IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES);
|
||||
MAKE_PROP(IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS);
|
||||
MAKE_PROP(IMPORTED_CXX_MODULES_COMPILE_FEATURES);
|
||||
MAKE_PROP(IMPORTED_CXX_MODULES_COMPILE_OPTIONS);
|
||||
MAKE_PROP(IMPORTED_CXX_MODULES_LINK_LIBRARIES);
|
||||
MAKE_PROP(LINK_DIRECTORIES);
|
||||
MAKE_PROP(LINK_LIBRARIES);
|
||||
MAKE_PROP(MANUALLY_ADDED_DEPENDENCIES);
|
||||
@@ -1846,6 +2044,11 @@ void cmTarget::SetProperty(const std::string& prop, cmValue value)
|
||||
&this->impl->InterfaceLinkLibraries,
|
||||
&this->impl->InterfaceLinkLibrariesDirect,
|
||||
&this->impl->InterfaceLinkLibrariesDirectExclude,
|
||||
&this->impl->ImportedCxxModulesIncludeDirectories,
|
||||
&this->impl->ImportedCxxModulesCompileDefinitions,
|
||||
&this->impl->ImportedCxxModulesCompileFeatures,
|
||||
&this->impl->ImportedCxxModulesCompileOptions,
|
||||
&this->impl->ImportedCxxModulesLinkLibraries,
|
||||
};
|
||||
|
||||
for (auto* usageRequirement : usageRequirements) {
|
||||
@@ -2019,6 +2222,11 @@ void cmTarget::AppendProperty(const std::string& prop,
|
||||
&this->impl->InterfaceLinkLibraries,
|
||||
&this->impl->InterfaceLinkLibrariesDirect,
|
||||
&this->impl->InterfaceLinkLibrariesDirectExclude,
|
||||
&this->impl->ImportedCxxModulesIncludeDirectories,
|
||||
&this->impl->ImportedCxxModulesCompileDefinitions,
|
||||
&this->impl->ImportedCxxModulesCompileFeatures,
|
||||
&this->impl->ImportedCxxModulesCompileOptions,
|
||||
&this->impl->ImportedCxxModulesLinkLibraries,
|
||||
};
|
||||
|
||||
for (auto* usageRequirement : usageRequirements) {
|
||||
@@ -2445,6 +2653,11 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
|
||||
propINTERFACE_LINK_LIBRARIES,
|
||||
propINTERFACE_LINK_LIBRARIES_DIRECT,
|
||||
propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE,
|
||||
propIMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES,
|
||||
propIMPORTED_CXX_MODULES_COMPILE_DEFINITIONS,
|
||||
propIMPORTED_CXX_MODULES_COMPILE_FEATURES,
|
||||
propIMPORTED_CXX_MODULES_COMPILE_OPTIONS,
|
||||
propIMPORTED_CXX_MODULES_LINK_LIBRARIES,
|
||||
};
|
||||
if (specialProps.count(prop)) {
|
||||
if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
|
||||
@@ -2470,6 +2683,11 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
|
||||
&this->impl->InterfaceLinkLibraries,
|
||||
&this->impl->InterfaceLinkLibrariesDirect,
|
||||
&this->impl->InterfaceLinkLibrariesDirectExclude,
|
||||
&this->impl->ImportedCxxModulesIncludeDirectories,
|
||||
&this->impl->ImportedCxxModulesCompileDefinitions,
|
||||
&this->impl->ImportedCxxModulesCompileFeatures,
|
||||
&this->impl->ImportedCxxModulesCompileOptions,
|
||||
&this->impl->ImportedCxxModulesLinkLibraries,
|
||||
};
|
||||
|
||||
for (auto const* usageRequirement : usageRequirements) {
|
||||
@@ -2675,6 +2893,9 @@ bool cmTarget::CanCompileSources() const
|
||||
if (this->IsImported()) {
|
||||
return false;
|
||||
}
|
||||
if (this->IsSynthetic()) {
|
||||
return true;
|
||||
}
|
||||
switch (this->GetType()) {
|
||||
case cmStateEnums::EXECUTABLE:
|
||||
case cmStateEnums::STATIC_LIBRARY:
|
||||
|
||||
@@ -291,6 +291,10 @@ public:
|
||||
cmBTStringRange GetLinkInterfaceDirectEntries() const;
|
||||
cmBTStringRange GetLinkInterfaceDirectExcludeEntries() const;
|
||||
|
||||
void CopyPolicyStatuses(cmTarget const* tgt);
|
||||
void CopyImportedCxxModulesEntries(cmTarget const* tgt);
|
||||
void CopyImportedCxxModulesProperties(cmTarget const* tgt);
|
||||
|
||||
cmBTStringRange GetHeaderSetsEntries() const;
|
||||
cmBTStringRange GetCxxModuleSetsEntries() const;
|
||||
|
||||
|
||||
@@ -2517,6 +2517,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
|
||||
case cmGeneratorTarget::SourceKindModuleDefinition:
|
||||
tool = "None";
|
||||
break;
|
||||
case cmGeneratorTarget::SourceKindCxxModuleSource:
|
||||
case cmGeneratorTarget::SourceKindUnityBatched:
|
||||
case cmGeneratorTarget::SourceKindObjectSource: {
|
||||
const std::string& lang = si.Source->GetLanguage();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
project(${RunCMake_TEST} NONE)
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "a816ed09-43d1-40e5-bc8c-1a2824ee194e")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
include(${RunCMake_TEST}.cmake)
|
||||
|
||||
@@ -187,7 +187,20 @@ endif ()
|
||||
if ("export_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
|
||||
run_cxx_module_test(export-interface-no-properties-build)
|
||||
run_cxx_module_test(export-interface-build)
|
||||
run_cxx_module_test(export-usage-build)
|
||||
run_cxx_module_test(export-bmi-and-interface-build)
|
||||
|
||||
if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION AND
|
||||
"bmionly" IN_LIST CMake_TEST_MODULE_COMPILATION)
|
||||
set(test_suffix export-interface-build)
|
||||
run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-build")
|
||||
|
||||
set(test_suffix export-interface-no-properties-build)
|
||||
run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-build" -DNO_PROPERTIES=1)
|
||||
|
||||
set(test_suffix export-bmi-and-interface-build)
|
||||
run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-build" -DWITH_BMIS=1)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# All of the following tests perform installation.
|
||||
@@ -201,6 +214,21 @@ if ("install_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
|
||||
if ("export_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
|
||||
run_cxx_module_test(export-interface-no-properties-install)
|
||||
run_cxx_module_test(export-interface-install)
|
||||
run_cxx_module_test(export-usage-install)
|
||||
run_cxx_module_test(export-bmi-and-interface-install)
|
||||
|
||||
if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION AND
|
||||
"bmionly" IN_LIST CMake_TEST_MODULE_COMPILATION)
|
||||
set(RunCMake_CXXModules_INSTALL 0)
|
||||
set(test_suffix export-interface-install)
|
||||
run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-install")
|
||||
|
||||
set(test_suffix export-interface-no-properties-install)
|
||||
run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-install" -DNO_PROPERTIES=1)
|
||||
|
||||
set(test_suffix export-bmi-and-interface-install)
|
||||
run_cxx_module_test(import-modules "import-modules-${test_suffix}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${test_suffix}-install" -DWITH_BMIS=1)
|
||||
set(RunCMake_CXXModules_INSTALL 1)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "a816ed09-43d1-40e5-bc8c-1a2824ee194e")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
if (NOT EXISTS "${CMake_TEST_MODULE_COMPILATION_RULES}")
|
||||
message(FATAL_ERROR
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(cxx_modules_library NONE)
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "a816ed09-43d1-40e5-bc8c-1a2824ee194e")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
find_package(export_bmi_and_interfaces REQUIRED)
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(cxx_modules_library NONE)
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "a816ed09-43d1-40e5-bc8c-1a2824ee194e")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
find_package(export_bmi_and_interfaces REQUIRED)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(cxx_modules_library NONE)
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "a816ed09-43d1-40e5-bc8c-1a2824ee194e")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
find_package(export_interfaces REQUIRED)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(cxx_modules_library NONE)
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "a816ed09-43d1-40e5-bc8c-1a2824ee194e")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
find_package(export_interfaces REQUIRED)
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(cxx_modules_library NONE)
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "a816ed09-43d1-40e5-bc8c-1a2824ee194e")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
find_package(export_interfaces_no_properties REQUIRED)
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(cxx_modules_library NONE)
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "a816ed09-43d1-40e5-bc8c-1a2824ee194e")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
find_package(export_interfaces_no_properties REQUIRED)
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\):
|
||||
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.
|
||||
@@ -0,0 +1,110 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(cxx_modules_export_usage CXX)
|
||||
|
||||
include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
|
||||
|
||||
add_library(export_usage STATIC)
|
||||
target_sources(export_usage
|
||||
PRIVATE
|
||||
forward.cxx
|
||||
PRIVATE
|
||||
FILE_SET modules_private TYPE CXX_MODULES
|
||||
BASE_DIRS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
FILES
|
||||
private.cxx
|
||||
PUBLIC
|
||||
FILE_SET modules TYPE CXX_MODULES
|
||||
BASE_DIRS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
FILES
|
||||
importable.cxx)
|
||||
target_compile_features(export_usage PUBLIC cxx_std_20)
|
||||
|
||||
list(APPEND CMAKE_CXX_KNOWN_FEATURES
|
||||
exported
|
||||
buildiface
|
||||
installiface
|
||||
buildlocaliface)
|
||||
|
||||
target_include_directories(export_usage
|
||||
PRIVATE
|
||||
"/usr/exported"
|
||||
"$<BUILD_INTERFACE:/usr/buildiface>"
|
||||
"$<INSTALL_INTERFACE:/usr/installiface>"
|
||||
"$<BUILD_LOCAL_INTERFACE:/usr/buildlocaliface>")
|
||||
target_compile_definitions(export_usage
|
||||
PRIVATE
|
||||
"exported"
|
||||
"$<BUILD_INTERFACE:buildiface>"
|
||||
"$<INSTALL_INTERFACE:installiface>"
|
||||
"$<BUILD_LOCAL_INTERFACE:buildlocaliface>")
|
||||
target_compile_features(export_usage
|
||||
PRIVATE
|
||||
"cxx_std_11"
|
||||
"$<BUILD_INTERFACE:cxx_std_14>"
|
||||
"$<INSTALL_INTERFACE:cxx_std_17>"
|
||||
"$<BUILD_LOCAL_INTERFACE:cxx_std_20>")
|
||||
|
||||
if (MSVC)
|
||||
set(variable_flag "-constexpr:depth")
|
||||
else ()
|
||||
set(variable_flag "-fconstexpr-depth=")
|
||||
endif ()
|
||||
|
||||
target_compile_options(export_usage
|
||||
PRIVATE
|
||||
"${variable_flag}100"
|
||||
"$<BUILD_INTERFACE:${variable_flag}200>"
|
||||
"$<INSTALL_INTERFACE:${variable_flag}300>"
|
||||
"$<BUILD_LOCAL_INTERFACE:${variable_flag}400>")
|
||||
|
||||
add_library(export_used INTERFACE)
|
||||
add_library(export_build INTERFACE)
|
||||
add_library(export_install INTERFACE)
|
||||
add_library(export_never INTERFACE)
|
||||
|
||||
target_link_libraries(export_usage
|
||||
PRIVATE
|
||||
"export_used"
|
||||
"$<BUILD_INTERFACE:export_build>"
|
||||
"$<INSTALL_INTERFACE:export_install>"
|
||||
"$<BUILD_LOCAL_INTERFACE:export_never>")
|
||||
|
||||
install(TARGETS export_usage
|
||||
EXPORT CXXModules
|
||||
FILE_SET modules DESTINATION "lib/cxx/miu")
|
||||
export(EXPORT CXXModules
|
||||
NAMESPACE CXXModules::
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/export_usage-targets.cmake")
|
||||
install(TARGETS export_used export_build export_install
|
||||
EXPORT CXXModulesDeps)
|
||||
export(EXPORT CXXModulesDeps
|
||||
NAMESPACE CXXModules::
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/export_usage-dep-targets.cmake")
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_usage-config.cmake"
|
||||
"include(\"\${CMAKE_CURRENT_LIST_DIR}/export_usage-dep-targets.cmake\")
|
||||
include(\"\${CMAKE_CURRENT_LIST_DIR}/export_usage-targets.cmake\")
|
||||
set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
|
||||
")
|
||||
|
||||
set(generator
|
||||
-G "${CMAKE_GENERATOR}")
|
||||
if (CMAKE_GENERATOR_TOOLSET)
|
||||
list(APPEND generator
|
||||
-T "${CMAKE_GENERATOR_TOOLSET}")
|
||||
endif ()
|
||||
if (CMAKE_GENERATOR_PLATFORM)
|
||||
list(APPEND generator
|
||||
-A "${CMAKE_GENERATOR_PLATFORM}")
|
||||
endif ()
|
||||
|
||||
add_test(NAME export_usage_build
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}"
|
||||
"-Dexpected_dir=${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"-Dexport_interfaces_flag=${variable_flag}"
|
||||
"-Dexport_usage_DIR=${CMAKE_CURRENT_BINARY_DIR}"
|
||||
${generator}
|
||||
-S "${CMAKE_CURRENT_SOURCE_DIR}/test"
|
||||
-B "${CMAKE_CURRENT_BINARY_DIR}/test")
|
||||
@@ -0,0 +1,6 @@
|
||||
import priv;
|
||||
|
||||
int forwarding()
|
||||
{
|
||||
return from_private();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export module importable;
|
||||
|
||||
extern "C++" {
|
||||
int forwarding();
|
||||
}
|
||||
|
||||
export int from_import()
|
||||
{
|
||||
return forwarding();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export module priv;
|
||||
|
||||
export int from_private()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(cxx_modules_library NONE)
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
find_package(export_usage REQUIRED)
|
||||
|
||||
if (NOT TARGET CXXModules::export_usage)
|
||||
message(FATAL_ERROR
|
||||
"Missing imported target")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET CXXModules::export_used)
|
||||
message(FATAL_ERROR
|
||||
"Missing imported target")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET CXXModules::export_build)
|
||||
message(FATAL_ERROR
|
||||
"Missing imported target")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET CXXModules::export_install)
|
||||
message(FATAL_ERROR
|
||||
"Missing imported target")
|
||||
endif ()
|
||||
|
||||
if (TARGET CXXModules::export_never)
|
||||
message(FATAL_ERROR
|
||||
"Extra imported target")
|
||||
endif ()
|
||||
|
||||
function (check_property expected property)
|
||||
get_property(actual TARGET CXXModules::export_usage
|
||||
PROPERTY "${property}")
|
||||
if (NOT actual STREQUAL expected)
|
||||
message(SEND_ERROR
|
||||
"Mismatch for ${property}:\n expected: ${expected}\n actual: ${actual}")
|
||||
endif ()
|
||||
endfunction ()
|
||||
|
||||
check_property("/usr/exported;/usr/buildiface" "IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES")
|
||||
check_property("exported;buildiface" "IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS")
|
||||
check_property("cxx_std_20;cxx_std_11;cxx_std_14" "IMPORTED_CXX_MODULES_COMPILE_FEATURES")
|
||||
check_property("${export_interfaces_flag}100;${export_interfaces_flag}200" "IMPORTED_CXX_MODULES_COMPILE_OPTIONS")
|
||||
check_property("$<COMPILE_ONLY:CXXModules::export_used>;$<COMPILE_ONLY:CXXModules::export_build>" "IMPORTED_CXX_MODULES_LINK_LIBRARIES")
|
||||
|
||||
# Extract the export-dependent targets from the export file.
|
||||
file(STRINGS "${export_usage_DIR}/export_usage-targets.cmake" usage_dependent_targets
|
||||
REGEX "foreach._target ")
|
||||
# Rudimentary argument splitting.
|
||||
string(REPLACE " " ";" usage_dependent_targets "${usage_dependent_targets}")
|
||||
# Keep only "target" names.
|
||||
list(FILTER usage_dependent_targets INCLUDE REGEX "CXXModules::")
|
||||
# Strip quotes.
|
||||
string(REPLACE "\"" "" usage_dependent_targets "${usage_dependent_targets}")
|
||||
|
||||
if (NOT "CXXModules::export_used" IN_LIST usage_dependent_targets)
|
||||
message(SEND_ERROR
|
||||
"The main export does not require the 'CXXModules::export_used' target")
|
||||
endif ()
|
||||
if (NOT "CXXModules::export_build" IN_LIST usage_dependent_targets)
|
||||
message(SEND_ERROR
|
||||
"The main export does not require the 'CXXModules::export_build' target")
|
||||
endif ()
|
||||
if ("CXXModules::export_install" IN_LIST usage_dependent_targets)
|
||||
message(SEND_ERROR
|
||||
"The main export requires the 'CXXModules::export_install' target")
|
||||
endif ()
|
||||
@@ -0,0 +1,4 @@
|
||||
CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\):
|
||||
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.
|
||||
@@ -0,0 +1,114 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(cxx_modules_export_usage CXX)
|
||||
|
||||
include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
|
||||
|
||||
add_library(export_usage STATIC)
|
||||
target_sources(export_usage
|
||||
PRIVATE
|
||||
forward.cxx
|
||||
PRIVATE
|
||||
FILE_SET modules_private TYPE CXX_MODULES
|
||||
BASE_DIRS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
FILES
|
||||
private.cxx
|
||||
PUBLIC
|
||||
FILE_SET modules TYPE CXX_MODULES
|
||||
BASE_DIRS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
FILES
|
||||
importable.cxx)
|
||||
target_compile_features(export_usage PUBLIC cxx_std_20)
|
||||
|
||||
list(APPEND CMAKE_CXX_KNOWN_FEATURES
|
||||
exported
|
||||
buildiface
|
||||
installiface
|
||||
buildlocaliface)
|
||||
|
||||
target_include_directories(export_usage
|
||||
PRIVATE
|
||||
"/usr/exported"
|
||||
"$<BUILD_INTERFACE:/usr/buildiface>"
|
||||
"$<INSTALL_INTERFACE:/usr/installiface>"
|
||||
"$<BUILD_LOCAL_INTERFACE:/usr/buildlocaliface>")
|
||||
target_compile_definitions(export_usage
|
||||
PRIVATE
|
||||
"exported"
|
||||
"$<BUILD_INTERFACE:buildiface>"
|
||||
"$<INSTALL_INTERFACE:installiface>"
|
||||
"$<BUILD_LOCAL_INTERFACE:buildlocaliface>")
|
||||
target_compile_features(export_usage
|
||||
PRIVATE
|
||||
"cxx_std_11"
|
||||
"$<BUILD_INTERFACE:cxx_std_14>"
|
||||
"$<INSTALL_INTERFACE:cxx_std_17>"
|
||||
"$<BUILD_LOCAL_INTERFACE:cxx_std_20>")
|
||||
|
||||
if (MSVC)
|
||||
set(variable_flag "-constexpr:depth")
|
||||
else ()
|
||||
set(variable_flag "-fconstexpr-depth=")
|
||||
endif ()
|
||||
|
||||
target_compile_options(export_usage
|
||||
PRIVATE
|
||||
"${variable_flag}100"
|
||||
"$<BUILD_INTERFACE:${variable_flag}200>"
|
||||
"$<INSTALL_INTERFACE:${variable_flag}300>"
|
||||
"$<BUILD_LOCAL_INTERFACE:${variable_flag}400>")
|
||||
|
||||
add_library(export_used INTERFACE)
|
||||
add_library(export_build INTERFACE)
|
||||
add_library(export_install INTERFACE)
|
||||
add_library(export_never INTERFACE)
|
||||
|
||||
target_link_libraries(export_usage
|
||||
PRIVATE
|
||||
"export_used"
|
||||
"$<BUILD_INTERFACE:export_build>"
|
||||
"$<INSTALL_INTERFACE:export_install>"
|
||||
"$<BUILD_LOCAL_INTERFACE:export_never>")
|
||||
|
||||
install(TARGETS export_usage
|
||||
EXPORT CXXModules
|
||||
FILE_SET modules DESTINATION "lib/cxx/miu")
|
||||
install(EXPORT CXXModules
|
||||
NAMESPACE CXXModules::
|
||||
DESTINATION "lib/cmake/export_usage"
|
||||
FILE "export_usage-targets.cmake")
|
||||
install(TARGETS export_used export_build export_install
|
||||
EXPORT CXXModulesDeps)
|
||||
install(EXPORT CXXModulesDeps
|
||||
NAMESPACE CXXModules::
|
||||
DESTINATION "lib/cmake/export_usage"
|
||||
FILE "export_usage-dep-targets.cmake")
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_usage-config.cmake"
|
||||
"include(\"\${CMAKE_CURRENT_LIST_DIR}/export_usage-dep-targets.cmake\")
|
||||
include(\"\${CMAKE_CURRENT_LIST_DIR}/export_usage-targets.cmake\")
|
||||
set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
|
||||
")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/export_usage-config.cmake"
|
||||
DESTINATION "lib/cmake/export_usage")
|
||||
|
||||
set(generator
|
||||
-G "${CMAKE_GENERATOR}")
|
||||
if (CMAKE_GENERATOR_TOOLSET)
|
||||
list(APPEND generator
|
||||
-T "${CMAKE_GENERATOR_TOOLSET}")
|
||||
endif ()
|
||||
if (CMAKE_GENERATOR_PLATFORM)
|
||||
list(APPEND generator
|
||||
-A "${CMAKE_GENERATOR_PLATFORM}")
|
||||
endif ()
|
||||
|
||||
add_test(NAME export_usage_build
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}"
|
||||
"-Dexpected_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/miu"
|
||||
"-Dexport_interfaces_flag=${variable_flag}"
|
||||
"-Dexport_usage_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/export_usage"
|
||||
${generator}
|
||||
-S "${CMAKE_CURRENT_SOURCE_DIR}/test"
|
||||
-B "${CMAKE_CURRENT_BINARY_DIR}/test")
|
||||
@@ -0,0 +1,6 @@
|
||||
import priv;
|
||||
|
||||
int forwarding()
|
||||
{
|
||||
return from_private();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export module importable;
|
||||
|
||||
extern "C++" {
|
||||
int forwarding();
|
||||
}
|
||||
|
||||
export int from_import()
|
||||
{
|
||||
return forwarding();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export module priv;
|
||||
|
||||
export int from_private()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(cxx_modules_library NONE)
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
find_package(export_usage REQUIRED)
|
||||
|
||||
if (NOT TARGET CXXModules::export_usage)
|
||||
message(FATAL_ERROR
|
||||
"Missing imported target")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET CXXModules::export_used)
|
||||
message(FATAL_ERROR
|
||||
"Missing imported target")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET CXXModules::export_build)
|
||||
message(FATAL_ERROR
|
||||
"Missing imported target")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET CXXModules::export_install)
|
||||
message(FATAL_ERROR
|
||||
"Missing imported target")
|
||||
endif ()
|
||||
|
||||
if (TARGET CXXModules::export_never)
|
||||
message(FATAL_ERROR
|
||||
"Extra imported target")
|
||||
endif ()
|
||||
|
||||
function (check_property expected property)
|
||||
get_property(actual TARGET CXXModules::export_usage
|
||||
PROPERTY "${property}")
|
||||
if (NOT actual STREQUAL expected)
|
||||
message(SEND_ERROR
|
||||
"Mismatch for ${property}:\n expected: ${expected}\n actual : ${actual}")
|
||||
endif ()
|
||||
endfunction ()
|
||||
|
||||
check_property("/usr/exported;/usr/installiface" "IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES")
|
||||
check_property("exported;installiface" "IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS")
|
||||
check_property("cxx_std_20;cxx_std_11;cxx_std_17" "IMPORTED_CXX_MODULES_COMPILE_FEATURES")
|
||||
check_property("${export_interfaces_flag}100;${export_interfaces_flag}300" "IMPORTED_CXX_MODULES_COMPILE_OPTIONS")
|
||||
check_property("$<COMPILE_ONLY:CXXModules::export_used>;$<COMPILE_ONLY:CXXModules::export_install>" "IMPORTED_CXX_MODULES_LINK_LIBRARIES")
|
||||
|
||||
# Extract the export-dependent targets from the export file.
|
||||
file(STRINGS "${export_usage_DIR}/export_usage-targets.cmake" usage_dependent_targets
|
||||
REGEX "foreach._target ")
|
||||
# Rudimentary argument splitting.
|
||||
string(REPLACE " " ";" usage_dependent_targets "${usage_dependent_targets}")
|
||||
# Keep only "target" names.
|
||||
list(FILTER usage_dependent_targets INCLUDE REGEX "CXXModules::")
|
||||
# Strip quotes.
|
||||
string(REPLACE "\"" "" usage_dependent_targets "${usage_dependent_targets}")
|
||||
|
||||
if (NOT "CXXModules::export_used" IN_LIST usage_dependent_targets)
|
||||
message(SEND_ERROR
|
||||
"The main export does not require the 'CXXModules::export_used' target")
|
||||
endif ()
|
||||
if ("CXXModules::export_build" IN_LIST usage_dependent_targets)
|
||||
message(SEND_ERROR
|
||||
"The main export requires the 'CXXModules::export_build' target")
|
||||
endif ()
|
||||
if (NOT "CXXModules::export_install" IN_LIST usage_dependent_targets)
|
||||
message(SEND_ERROR
|
||||
"The main export does not require the 'CXXModules::export_install' target")
|
||||
endif ()
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
CMake Warning \(dev\) at .*/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build-build/export_bmi_and_interfaces-targets.cmake:[0-9]* \(target_sources\):
|
||||
CMake's C\+\+ module support is experimental. It is meant only for
|
||||
experimentation and feedback to CMake developers.
|
||||
Call Stack \(most recent call first\):
|
||||
.*/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build-build/export_bmi_and_interfaces-config.cmake:1 \(include\)
|
||||
CMakeLists.txt:15 \(find_package\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
CMake Warning \(dev\) at .*/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install-install/lib/cmake/export_bmi_and_interfaces/export_bmi_and_interfaces-targets.cmake:[0-9]* \(target_sources\):
|
||||
CMake's C\+\+ module support is experimental. It is meant only for
|
||||
experimentation and feedback to CMake developers.
|
||||
Call Stack \(most recent call first\):
|
||||
.*/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install-install/lib/cmake/export_bmi_and_interfaces/export_bmi_and_interfaces-config.cmake:1 \(include\)
|
||||
CMakeLists.txt:15 \(find_package\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
@@ -0,0 +1,7 @@
|
||||
CMake Warning \(dev\) at .*/Tests/RunCMake/CXXModules/examples/export-interface-build-build/export_interfaces-targets.cmake:[0-9]* \(target_sources\):
|
||||
CMake's C\+\+ module support is experimental. It is meant only for
|
||||
experimentation and feedback to CMake developers.
|
||||
Call Stack \(most recent call first\):
|
||||
.*/Tests/RunCMake/CXXModules/examples/export-interface-build-build/export_interfaces-config.cmake:1 \(include\)
|
||||
CMakeLists.txt:15 \(find_package\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
@@ -0,0 +1,7 @@
|
||||
CMake Warning \(dev\) at .*/Tests/RunCMake/CXXModules/examples/export-interface-install-install/lib/cmake/export_interfaces/export_interfaces-targets.cmake:[0-9]* \(target_sources\):
|
||||
CMake's C\+\+ module support is experimental. It is meant only for
|
||||
experimentation and feedback to CMake developers.
|
||||
Call Stack \(most recent call first\):
|
||||
.*/Tests/RunCMake/CXXModules/examples/export-interface-install-install/lib/cmake/export_interfaces/export_interfaces-config.cmake:1 \(include\)
|
||||
CMakeLists.txt:15 \(find_package\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
CMake Warning \(dev\) at .*/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build-build/export_interfaces_no_properties-targets.cmake:[0-9]* \(target_sources\):
|
||||
CMake's C\+\+ module support is experimental. It is meant only for
|
||||
experimentation and feedback to CMake developers.
|
||||
Call Stack \(most recent call first\):
|
||||
.*/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build-build/export_interfaces_no_properties-config.cmake:1 \(include\)
|
||||
CMakeLists.txt:15 \(find_package\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
CMake Warning \(dev\) at .*/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install-install/lib/cmake/export_interfaces_no_properties/export_interfaces_no_properties-targets.cmake:[0-9]* \(target_sources\):
|
||||
CMake's C\+\+ module support is experimental. It is meant only for
|
||||
experimentation and feedback to CMake developers.
|
||||
Call Stack \(most recent call first\):
|
||||
.*/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install-install/lib/cmake/export_interfaces_no_properties/export_interfaces_no_properties-config.cmake:1 \(include\)
|
||||
CMakeLists.txt:15 \(find_package\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
@@ -0,0 +1,24 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(cxx_modules_import_interfaces CXX)
|
||||
|
||||
include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
|
||||
|
||||
if (NO_PROPERTIES)
|
||||
set(package_name "export_interfaces_no_properties")
|
||||
elseif (WITH_BMIS)
|
||||
set(package_name "export_bmi_and_interfaces")
|
||||
else ()
|
||||
set(package_name "export_interfaces")
|
||||
endif ()
|
||||
set(target_name "CXXModules::${package_name}")
|
||||
|
||||
find_package("${package_name}" REQUIRED)
|
||||
|
||||
add_executable(use_import_interfaces)
|
||||
target_sources(use_import_interfaces
|
||||
PRIVATE
|
||||
use.cxx)
|
||||
target_compile_features(use_import_interfaces PRIVATE cxx_std_20)
|
||||
target_link_libraries(use_import_interfaces PRIVATE "${target_name}")
|
||||
|
||||
add_test(NAME use_import_interfaces COMMAND use_import_interfaces)
|
||||
@@ -0,0 +1,6 @@
|
||||
import importable;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
return from_import();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
enable_language(C)
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "a816ed09-43d1-40e5-bc8c-1a2824ee194e")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
add_library(lib1 STATIC empty.c)
|
||||
target_sources(lib1 PRIVATE FILE_SET UNKNOWN)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
enable_language(C)
|
||||
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "a816ed09-43d1-40e5-bc8c-1a2824ee194e")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6")
|
||||
|
||||
add_library(lib1 STATIC empty.c)
|
||||
target_sources(lib1 PRIVATE FILE_SET a TYPE UNKNOWN)
|
||||
|
||||
@@ -333,6 +333,7 @@ CMAKE_CXX_SOURCES="\
|
||||
cmCustomCommandGenerator \
|
||||
cmCustomCommandLines \
|
||||
cmCxxModuleMapper \
|
||||
cmCxxModuleUsageEffects \
|
||||
cmDefinePropertyCommand \
|
||||
cmDefinitions \
|
||||
cmDocumentationFormatter \
|
||||
@@ -392,6 +393,7 @@ CMAKE_CXX_SOURCES="\
|
||||
cmGlobVerificationManager \
|
||||
cmHexFileConverter \
|
||||
cmIfCommand \
|
||||
cmImportedCxxModuleInfo \
|
||||
cmIncludeCommand \
|
||||
cmIncludeGuardCommand \
|
||||
cmIncludeDirectoryCommand \
|
||||
|
||||
Reference in New Issue
Block a user