mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-14 02:08:27 +08:00
@@ -3,6 +3,7 @@
|
||||
#include "cmExportBuildPackageInfoGenerator.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -10,7 +11,9 @@
|
||||
|
||||
#include <cm3p/json/value.h>
|
||||
|
||||
#include "cmAlgorithms.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmList.h"
|
||||
#include "cmPackageInfoArguments.h"
|
||||
#include "cmStateTypes.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
@@ -68,6 +71,14 @@ bool cmExportBuildPackageInfoGenerator::GenerateMainFile(std::ostream& os)
|
||||
}
|
||||
}
|
||||
|
||||
// De-duplicate include directories prior to generation.
|
||||
auto it = properties.find("INTERFACE_INCLUDE_DIRECTORIES");
|
||||
if (it != properties.end()) {
|
||||
auto list = cmList{ it->second };
|
||||
list = cmList{ list.begin(), cmRemoveDuplicates(list) };
|
||||
properties["INTERFACE_INCLUDE_DIRECTORIES"] = list.to_string();
|
||||
}
|
||||
|
||||
// Set configuration-agnostic properties for component.
|
||||
this->GenerateInterfaceProperties(*component, target, properties);
|
||||
}
|
||||
|
@@ -2,19 +2,32 @@
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#include "cmExportInstallPackageInfoGenerator.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
#include <cm/string_view>
|
||||
#include <cmext/algorithm>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include <cm3p/json/value.h>
|
||||
|
||||
#include "cmAlgorithms.h"
|
||||
#include "cmExportSet.h"
|
||||
#include "cmFileSet.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmGeneratorTarget.h"
|
||||
#include "cmInstallExportGenerator.h"
|
||||
#include "cmInstallFileSetGenerator.h"
|
||||
#include "cmList.h"
|
||||
#include "cmLocalGenerator.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmOutputConverter.h"
|
||||
#include "cmPackageInfoArguments.h"
|
||||
#include "cmStateTypes.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
@@ -67,7 +80,6 @@ bool cmExportInstallPackageInfoGenerator::GenerateMainFile(std::ostream& os)
|
||||
root["cps_path"] = packagePath;
|
||||
|
||||
// Create all the imported targets.
|
||||
bool requiresConfigFiles = false;
|
||||
for (cmTargetExport const* te : allTargets) {
|
||||
cmGeneratorTarget* gt = te->Target;
|
||||
cmStateEnums::TargetType targetType = this->GetExportTargetType(te);
|
||||
@@ -86,11 +98,22 @@ bool cmExportInstallPackageInfoGenerator::GenerateMainFile(std::ostream& os)
|
||||
gt, cmGeneratorExpression::InstallInterface, properties);
|
||||
|
||||
if (targetType != cmStateEnums::INTERFACE_LIBRARY) {
|
||||
requiresConfigFiles = true;
|
||||
this->RequiresConfigFiles = true;
|
||||
}
|
||||
|
||||
// De-duplicate include directories prior to generation.
|
||||
auto it = properties.find("INTERFACE_INCLUDE_DIRECTORIES");
|
||||
if (it != properties.end()) {
|
||||
auto list = cmList{ it->second };
|
||||
list = cmList{ list.begin(), cmRemoveDuplicates(list) };
|
||||
properties["INTERFACE_INCLUDE_DIRECTORIES"] = list.to_string();
|
||||
}
|
||||
|
||||
// Set configuration-agnostic properties for component.
|
||||
this->GenerateInterfaceProperties(*component, gt, properties);
|
||||
if (!this->GenerateFileSetProperties(*component, gt, te)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this->GeneratePackageRequires(root);
|
||||
@@ -101,7 +124,7 @@ bool cmExportInstallPackageInfoGenerator::GenerateMainFile(std::ostream& os)
|
||||
bool result = true;
|
||||
|
||||
// Generate an import file for each configuration.
|
||||
if (requiresConfigFiles) {
|
||||
if (this->RequiresConfigFiles) {
|
||||
for (std::string const& c : this->Configurations) {
|
||||
if (!this->GenerateImportFileConfig(c)) {
|
||||
result = false;
|
||||
@@ -123,19 +146,19 @@ void cmExportInstallPackageInfoGenerator::GenerateImportTargetsConfig(
|
||||
|
||||
for (auto const& te : this->GetExportSet()->GetTargetExports()) {
|
||||
// Collect import properties for this target.
|
||||
if (this->GetExportTargetType(te.get()) ==
|
||||
cmStateEnums::INTERFACE_LIBRARY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ImportPropertyMap properties;
|
||||
std::set<std::string> importedLocations;
|
||||
|
||||
this->PopulateImportProperties(config, suffix, te.get(), properties,
|
||||
importedLocations);
|
||||
if (this->GetExportTargetType(te.get()) !=
|
||||
cmStateEnums::INTERFACE_LIBRARY) {
|
||||
this->PopulateImportProperties(config, suffix, te.get(), properties,
|
||||
importedLocations);
|
||||
}
|
||||
|
||||
Json::Value component =
|
||||
this->GenerateInterfaceConfigProperties(suffix, properties);
|
||||
this->GenerateFileSetProperties(component, te->Target, te.get(), config);
|
||||
|
||||
if (!component.empty()) {
|
||||
components[te->Target->GetExportName()] = std::move(component);
|
||||
}
|
||||
@@ -193,3 +216,82 @@ std::string cmExportInstallPackageInfoGenerator::GetCxxModulesDirectory() const
|
||||
// return IEGen->GetCxxModuleDirectory();
|
||||
return {};
|
||||
}
|
||||
|
||||
cm::optional<std::string>
|
||||
cmExportInstallPackageInfoGenerator::GetFileSetDirectory(
|
||||
cmGeneratorTarget* gte, cmTargetExport const* te, cmFileSet* fileSet,
|
||||
cm::optional<std::string> const& config)
|
||||
{
|
||||
cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance());
|
||||
auto cge =
|
||||
ge.Parse(te->FileSetGenerators.at(fileSet->GetName())->GetDestination());
|
||||
|
||||
std::string const unescapedDest =
|
||||
cge->Evaluate(gte->LocalGenerator, config.value_or(""), gte);
|
||||
bool const isConfigDependent = cge->GetHadContextSensitiveCondition();
|
||||
|
||||
if (config && !isConfigDependent) {
|
||||
return {};
|
||||
}
|
||||
if (!config && isConfigDependent) {
|
||||
this->RequiresConfigFiles = true;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string const& type = fileSet->GetType();
|
||||
if (config && (type == "CXX_MODULES"_s)) {
|
||||
// C++ modules do not support interface file sets which are dependent
|
||||
// upon the configuration.
|
||||
cmMakefile* mf = gte->LocalGenerator->GetMakefile();
|
||||
std::ostringstream e;
|
||||
e << "The \"" << gte->GetName() << "\" target's interface file set \""
|
||||
<< fileSet->GetName() << "\" of type \"" << type
|
||||
<< "\" contains context-sensitive base file entries which is not "
|
||||
"supported.";
|
||||
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
||||
return {};
|
||||
}
|
||||
|
||||
cm::optional<std::string> dest = cmOutputConverter::EscapeForCMake(
|
||||
unescapedDest, cmOutputConverter::WrapQuotes::NoWrap);
|
||||
|
||||
if (!cmSystemTools::FileIsFullPath(unescapedDest)) {
|
||||
dest = cmStrCat("@prefix@/"_s, *dest);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
bool cmExportInstallPackageInfoGenerator::GenerateFileSetProperties(
|
||||
Json::Value& component, cmGeneratorTarget* gte, cmTargetExport const* te,
|
||||
cm::optional<std::string> config)
|
||||
{
|
||||
std::set<std::string> seenIncludeDirectories;
|
||||
for (auto const& name : gte->Target->GetAllInterfaceFileSets()) {
|
||||
cmFileSet* fileSet = gte->Target->GetFileSet(name);
|
||||
|
||||
if (!fileSet) {
|
||||
gte->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("File set \"", name,
|
||||
"\" is listed in interface file sets of ", gte->GetName(),
|
||||
" but has not been created"));
|
||||
return false;
|
||||
}
|
||||
|
||||
cm::optional<std::string> const& fileSetDirectory =
|
||||
this->GetFileSetDirectory(gte, te, fileSet, config);
|
||||
|
||||
if (fileSet->GetType() == "HEADERS"_s) {
|
||||
if (fileSetDirectory &&
|
||||
!cm::contains(seenIncludeDirectories, *fileSetDirectory)) {
|
||||
component["includes"].append(*fileSetDirectory);
|
||||
seenIncludeDirectories.insert(*fileSetDirectory);
|
||||
}
|
||||
} else if (fileSet->GetType() == "CXX_MODULES"_s) {
|
||||
/* TODO: Handle the CXX_MODULE directory */
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@@ -7,12 +7,20 @@
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include <cm/optional>
|
||||
|
||||
#include "cmExportInstallFileGenerator.h"
|
||||
#include "cmExportPackageInfoGenerator.h"
|
||||
|
||||
class cmFileSet;
|
||||
class cmGeneratorTarget;
|
||||
class cmInstallExportGenerator;
|
||||
class cmPackageInfoArguments;
|
||||
class cmTargetExport;
|
||||
|
||||
namespace Json {
|
||||
class Value;
|
||||
}
|
||||
|
||||
/** \class cmExportInstallPackageInfoGenerator
|
||||
* \brief Generate files exporting targets from an install tree.
|
||||
@@ -43,6 +51,8 @@ public:
|
||||
std::string GetConfigImportFileGlob() const override;
|
||||
|
||||
protected:
|
||||
bool RequiresConfigFiles = false;
|
||||
|
||||
std::string const& GetExportName() const override;
|
||||
|
||||
// Implement virtual methods from the superclass.
|
||||
@@ -60,4 +70,13 @@ protected:
|
||||
|
||||
std::string GetCxxModulesDirectory() const override;
|
||||
// TODO: Generate C++ module info in a not-CMake-specific format.
|
||||
|
||||
cm::optional<std::string> GetFileSetDirectory(
|
||||
cmGeneratorTarget* gte, cmTargetExport const* te, cmFileSet* fileSet,
|
||||
cm::optional<std::string> const& config = {});
|
||||
|
||||
bool GenerateFileSetProperties(Json::Value& component,
|
||||
cmGeneratorTarget* gte,
|
||||
cmTargetExport const* te,
|
||||
cm::optional<std::string> config = {});
|
||||
};
|
||||
|
@@ -1,12 +1,33 @@
|
||||
project(TestLibrary C)
|
||||
|
||||
add_library(liba SHARED liba.c)
|
||||
add_library(libb SHARED libb.c)
|
||||
add_library(liba SHARED)
|
||||
target_sources(liba
|
||||
PRIVATE
|
||||
liba/liba.c
|
||||
INTERFACE
|
||||
FILE_SET HEADERS
|
||||
BASE_DIRS
|
||||
liba
|
||||
FILES
|
||||
liba/liba.h
|
||||
)
|
||||
|
||||
add_library(libb SHARED)
|
||||
target_sources(libb
|
||||
PRIVATE
|
||||
libb/libb.c
|
||||
INTERFACE
|
||||
FILE_SET HEADERS
|
||||
BASE_DIRS
|
||||
libb
|
||||
FILES
|
||||
libb/libb.h
|
||||
)
|
||||
|
||||
target_link_libraries(libb PUBLIC liba)
|
||||
|
||||
install(TARGETS liba EXPORT liba DESTINATION lib)
|
||||
install(TARGETS liba EXPORT liba FILE_SET HEADERS)
|
||||
export(EXPORT liba PACKAGE_INFO liba)
|
||||
|
||||
install(TARGETS libb EXPORT libb DESTINATION lib)
|
||||
install(TARGETS libb EXPORT libb FILE_SET HEADERS)
|
||||
export(EXPORT libb PACKAGE_INFO libb)
|
||||
|
@@ -1,11 +1,6 @@
|
||||
#include <libb.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern
|
||||
#ifdef _WIN32
|
||||
__declspec(dllimport)
|
||||
#endif
|
||||
int ask(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("%i\n", ask());
|
||||
|
3
Tests/RunCMake/CpsExportImportBuild/liba/liba.h
Normal file
3
Tests/RunCMake/CpsExportImportBuild/liba/liba.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
int answer(void);
|
@@ -1,8 +1,4 @@
|
||||
extern
|
||||
#ifdef _WIN32
|
||||
__declspec(dllimport)
|
||||
#endif
|
||||
int answer(void);
|
||||
#include <liba.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
3
Tests/RunCMake/CpsExportImportBuild/libb/libb.h
Normal file
3
Tests/RunCMake/CpsExportImportBuild/libb/libb.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
int ask(void);
|
@@ -2,13 +2,34 @@ project(TestLibrary C)
|
||||
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/../install")
|
||||
|
||||
add_library(liba SHARED liba.c)
|
||||
add_library(libb SHARED libb.c)
|
||||
add_library(liba SHARED)
|
||||
target_sources(liba
|
||||
PRIVATE
|
||||
liba/liba.c
|
||||
INTERFACE
|
||||
FILE_SET HEADERS
|
||||
BASE_DIRS
|
||||
liba
|
||||
FILES
|
||||
liba/liba.h
|
||||
)
|
||||
|
||||
add_library(libb SHARED)
|
||||
target_sources(libb
|
||||
PRIVATE
|
||||
libb/libb.c
|
||||
INTERFACE
|
||||
FILE_SET HEADERS
|
||||
BASE_DIRS
|
||||
libb
|
||||
FILES
|
||||
libb/libb.h
|
||||
)
|
||||
|
||||
target_link_libraries(libb PUBLIC liba)
|
||||
|
||||
install(TARGETS liba EXPORT liba DESTINATION lib)
|
||||
install(TARGETS liba EXPORT liba FILE_SET HEADERS)
|
||||
install(PACKAGE_INFO liba DESTINATION cps EXPORT liba)
|
||||
|
||||
install(TARGETS libb EXPORT libb DESTINATION lib)
|
||||
install(TARGETS libb EXPORT libb FILE_SET HEADERS)
|
||||
install(PACKAGE_INFO libb DESTINATION cps EXPORT libb)
|
||||
|
@@ -1,11 +1,6 @@
|
||||
#include <libb.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern
|
||||
#ifdef _WIN32
|
||||
__declspec(dllimport)
|
||||
#endif
|
||||
int ask(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("%i\n", ask());
|
||||
|
3
Tests/RunCMake/CpsExportImportInstall/liba/liba.h
Normal file
3
Tests/RunCMake/CpsExportImportInstall/liba/liba.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
int answer(void);
|
@@ -1,8 +1,4 @@
|
||||
extern
|
||||
#ifdef _WIN32
|
||||
__declspec(dllimport)
|
||||
#endif
|
||||
int answer(void);
|
||||
#include <liba.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
3
Tests/RunCMake/CpsExportImportInstall/libb/libb.h
Normal file
3
Tests/RunCMake/CpsExportImportInstall/libb/libb.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
int ask(void);
|
10
Tests/RunCMake/ExportPackageInfo/FileSetHeaders-check.cmake
Normal file
10
Tests/RunCMake/ExportPackageInfo/FileSetHeaders-check.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
|
||||
|
||||
set(out_dir "${RunCMake_BINARY_DIR}/FileSetHeaders-build")
|
||||
|
||||
file(READ "${out_dir}/foo.cps" content)
|
||||
|
||||
string(JSON component GET "${content}" "components" "foo")
|
||||
|
||||
expect_array("${component}" 1 "includes")
|
||||
expect_value("${component}" "${CMAKE_CURRENT_LIST_DIR}/foo" "includes" 0)
|
29
Tests/RunCMake/ExportPackageInfo/FileSetHeaders.cmake
Normal file
29
Tests/RunCMake/ExportPackageInfo/FileSetHeaders.cmake
Normal file
@@ -0,0 +1,29 @@
|
||||
add_library(foo INTERFACE)
|
||||
|
||||
# Primarily this tests for de-duplication of the BASE_DIRS, ensuring DESTINATION
|
||||
# genex have no effect on build exports is a bonus covering a very unlikely bug
|
||||
|
||||
target_sources(foo
|
||||
INTERFACE
|
||||
FILE_SET no_genex
|
||||
TYPE HEADERS
|
||||
BASE_DIRS ${CMAKE_CURRENT_LIST_DIR}/foo
|
||||
|
||||
INTERFACE
|
||||
FILE_SET genex
|
||||
TYPE HEADERS
|
||||
BASE_DIRS ${CMAKE_CURRENT_LIST_DIR}/foo
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS foo
|
||||
EXPORT foo
|
||||
DESTINATION .
|
||||
|
||||
FILE_SET no_genex
|
||||
DESTINATION no_genex
|
||||
|
||||
FILE_SET genex
|
||||
DESTINATION $<$<CONFIG:FAKE_CONFIG>:FAKE_DEST>genex
|
||||
)
|
||||
export(EXPORT foo PACKAGE_INFO foo)
|
@@ -41,3 +41,4 @@ run_cmake(TargetTypes)
|
||||
run_cmake(DependsMultiple)
|
||||
run_cmake(LinkOnly)
|
||||
run_cmake(PerConfigGeneration)
|
||||
run_cmake(FileSetHeaders)
|
||||
|
28
Tests/RunCMake/InstallPackageInfo/FileSetHeaders-check.cmake
Normal file
28
Tests/RunCMake/InstallPackageInfo/FileSetHeaders-check.cmake
Normal file
@@ -0,0 +1,28 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
|
||||
|
||||
set(out_dir "${RunCMake_BINARY_DIR}/FileSetHeaders-build/CMakeFiles/Export/510c5684a4a8a792eadfb55bc9744983")
|
||||
|
||||
file(READ "${out_dir}/foo.cps" content)
|
||||
|
||||
string(JSON component GET "${content}" "components" "foo")
|
||||
|
||||
expect_array("${component}" 1 "includes")
|
||||
expect_value("${component}" "@prefix@/no_genex" "includes" 0)
|
||||
|
||||
file(GLOB configs "${out_dir}/foo@*.cps")
|
||||
list(LENGTH configs configs_len)
|
||||
|
||||
if(NOT configs_len)
|
||||
set(RunCMake_TEST_FAILED
|
||||
"No configuration-specific CPS files were generated" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
foreach(config ${configs})
|
||||
file(READ "${config}" content)
|
||||
|
||||
string(JSON component GET "${content}" "components" "foo")
|
||||
|
||||
expect_array("${component}" 1 "includes")
|
||||
expect_value("${component}" "@prefix@/genex" "includes" 0)
|
||||
endforeach()
|
38
Tests/RunCMake/InstallPackageInfo/FileSetHeaders.cmake
Normal file
38
Tests/RunCMake/InstallPackageInfo/FileSetHeaders.cmake
Normal file
@@ -0,0 +1,38 @@
|
||||
add_library(foo INTERFACE)
|
||||
|
||||
target_sources(foo
|
||||
INTERFACE
|
||||
FILE_SET no_genex
|
||||
TYPE HEADERS
|
||||
|
||||
INTERFACE
|
||||
FILE_SET no_genex_dup
|
||||
TYPE HEADERS
|
||||
|
||||
INTERFACE
|
||||
FILE_SET genex
|
||||
TYPE HEADERS
|
||||
|
||||
INTERFACE
|
||||
FILE_SET genex_dup
|
||||
TYPE HEADERS
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS foo
|
||||
EXPORT foo
|
||||
DESTINATION .
|
||||
|
||||
FILE_SET no_genex
|
||||
DESTINATION no_genex
|
||||
|
||||
FILE_SET no_genex_dup
|
||||
DESTINATION no_genex
|
||||
|
||||
FILE_SET genex
|
||||
DESTINATION $<$<CONFIG:FAKE_CONFIG>:FAKE_DEST>genex
|
||||
|
||||
FILE_SET genex_dup
|
||||
DESTINATION $<$<CONFIG:FAKE_CONFIG>:FAKE_DEST>genex
|
||||
)
|
||||
install(PACKAGE_INFO foo DESTINATION cps EXPORT foo)
|
@@ -49,4 +49,5 @@ run_cmake(TargetTypes)
|
||||
run_cmake(DependsMultiple)
|
||||
run_cmake(DependsMultipleNotInstalled)
|
||||
run_cmake(PerConfigGeneration)
|
||||
run_cmake(FileSetHeaders)
|
||||
run_cmake_install(Destination)
|
||||
|
Reference in New Issue
Block a user