From c386aaebf83a453f65ba4bb4b51ce01959b9d2ec Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Thu, 12 Mar 2026 10:29:48 +0100 Subject: [PATCH] FILE_SET: install and export SOURCES file set type --- Help/command/install.rst | 18 ++-- Source/cmExportBuildCMakeConfigGenerator.cxx | 7 +- Source/cmExportBuildFileGenerator.cxx | 23 +++++ Source/cmExportBuildFileGenerator.h | 4 + Source/cmExportCMakeConfigGenerator.cxx | 22 ++++- Source/cmExportCMakeConfigGenerator.h | 2 + Source/cmExportFileGenerator.cxx | 38 +++++++++ Source/cmExportFileGenerator.h | 11 +++ .../cmExportInstallCMakeConfigGenerator.cxx | 7 +- Source/cmExportInstallFileGenerator.cxx | 54 ++++++++++++ Source/cmExportInstallFileGenerator.h | 10 +++ .../FileSet-SOURCES/FileSetExport.cmake | 40 +++++++++ .../FileSet-SOURCES/FileSetImport.cmake | 85 +++++++++++++++++++ .../InstallMissingSetsInterface-result.txt | 1 + .../InstallMissingSetsInterface-stderr.txt | 5 ++ .../InstallMissingSetsInterface.cmake | 5 ++ ...MissingSetsInterfacePostInstall-result.txt | 1 + ...MissingSetsInterfacePostInstall-stderr.txt | 6 ++ ...stallMissingSetsInterfacePostInstall.cmake | 6 ++ .../FileSet-SOURCES/RunCMakeTest.cmake | 50 +++++++++++ Tests/RunCMake/FileSet-SOURCES/lib5.c | 4 + 21 files changed, 388 insertions(+), 11 deletions(-) create mode 100644 Tests/RunCMake/FileSet-SOURCES/FileSetExport.cmake create mode 100644 Tests/RunCMake/FileSet-SOURCES/FileSetImport.cmake create mode 100644 Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface-result.txt create mode 100644 Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface-stderr.txt create mode 100644 Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface.cmake create mode 100644 Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall-result.txt create mode 100644 Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall-stderr.txt create mode 100644 Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall.cmake diff --git a/Help/command/install.rst b/Help/command/install.rst index 783b2198e6..7ed27e7546 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst @@ -245,7 +245,10 @@ Signatures File sets are defined by the :command:`target_sources(FILE_SET)` command. If the file set ```` exists and is ``PUBLIC`` or ``INTERFACE``, - any files in the set are installed under the destination (see below). + any files in the set of type ``HEADERS`` are installed under + the destination (see below). Other types do not have any default + destination, so ``DESTINATION`` option must be specified for each + ``FILE_SET``. The directory structure relative to the file set's base directories is preserved. For example, a file added to the file set as ``/blah/include/myproj/here.h`` with a base directory ``/blah/include`` @@ -265,12 +268,13 @@ Signatures ``DESTINATION`` is omitted, a default destination will be taken from the appropriate variable from :module:`GNUInstallDirs`, or set to a built-in default value if that variable is not defined. The same is true for file - sets, and the public and private headers associated with the installed - targets through the :prop_tgt:`PUBLIC_HEADER` and :prop_tgt:`PRIVATE_HEADER` - target properties. A destination must always be provided for module libraries, - Apple bundles and frameworks. A destination can be omitted for interface and - object libraries, but they are handled differently (see the discussion of this - topic toward the end of this section). + sets of type ``HEADERS``, and the public and private headers associated with + the installed targets through the :prop_tgt:`PUBLIC_HEADER` and + :prop_tgt:`PRIVATE_HEADER` target properties. A destination must always be + provided for module libraries, Apple bundles and frameworks. A destination + can be omitted for interface and object libraries, but they are handled + differently (see the discussion of this topic toward the end of this + section). For shared libraries on DLL platforms, if neither ``RUNTIME`` nor ``ARCHIVE`` destinations are specified, both the ``RUNTIME`` and ``ARCHIVE`` components are diff --git a/Source/cmExportBuildCMakeConfigGenerator.cxx b/Source/cmExportBuildCMakeConfigGenerator.cxx index d7ee97f3ed..6ca639c58f 100644 --- a/Source/cmExportBuildCMakeConfigGenerator.cxx +++ b/Source/cmExportBuildCMakeConfigGenerator.cxx @@ -71,12 +71,17 @@ bool cmExportBuildCMakeConfigGenerator::GenerateMainFile(std::ostream& os) return false; } + ImportFileSetPropertyMap fsProperties; + if (!this->PopulateFileSetInterfaceProperties(gte, fsProperties)) { + return false; + } + this->PopulateInterfaceLinkLibrariesProperty( gte, cmGeneratorExpression::BuildInterface, properties); this->GenerateInterfaceProperties(gte, os, properties); - this->GenerateTargetFileSets(gte, os); + this->GenerateTargetFileSets(gte, os, fsProperties); } std::string cxx_modules_name; diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index ba090f5dd0..54b4ad5976 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -11,6 +11,8 @@ #include "cmExportSet.h" #include "cmGeneratorExpression.h" +#include "cmGeneratorFileSet.h" +#include "cmGeneratorFileSets.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmList.h" @@ -284,3 +286,24 @@ bool cmExportBuildFileGenerator::PopulateInterfaceProperties( return this->PopulateInterfaceProperties( target, {}, cmGeneratorExpression::BuildInterface, properties); } + +bool cmExportBuildFileGenerator::PopulateFileSetInterfaceProperties( + cmGeneratorTarget const* target, ImportFileSetPropertyMap& properties) +{ + cmGeneratorFileSets const* const gfs = target->GetGeneratorFileSets(); + bool result = true; + + for (auto const& type : gfs->GetInterfaceFileSetTypes()) { + for (auto const* fileSet : gfs->GetInterfaceFileSets(type)) { + ImportPropertyMap& fsProperties = properties[fileSet->GetName()]; + this->PopulateFileSetInterfaceProperty( + "INTERFACE_INCLUDE_DIRECTORIES", target, fileSet, + cmGeneratorExpression::BuildInterface, fsProperties); + result = result && + this->PopulateFileSetInterfaceProperties( + target, fileSet, cmGeneratorExpression::InstallInterface, + fsProperties); + } + } + return result; +} diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index b3ee5d461b..5e9e4c834a 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -114,6 +114,10 @@ protected: bool PopulateInterfaceProperties(cmGeneratorTarget const* target, ImportPropertyMap& properties); + using cmExportFileGenerator::PopulateFileSetInterfaceProperties; + bool PopulateFileSetInterfaceProperties( + cmGeneratorTarget const* target, ImportFileSetPropertyMap& properties); + struct TargetExportPrivate { TargetExportPrivate(cmGeneratorTarget* target, diff --git a/Source/cmExportCMakeConfigGenerator.cxx b/Source/cmExportCMakeConfigGenerator.cxx index 617a7a4109..353d38f9eb 100644 --- a/Source/cmExportCMakeConfigGenerator.cxx +++ b/Source/cmExportCMakeConfigGenerator.cxx @@ -612,6 +612,8 @@ cm::optional GetFileSetInformation(cm::string_view type) fileSetsInformation{ { cm::FileSetMetadata::HEADERS, { cm::FileSetMetadata::HEADERS, "3.23.0"_s } }, + { cm::FileSetMetadata::SOURCES, + { cm::FileSetMetadata::SOURCES, "4.4.0"_s } }, { cm::FileSetMetadata::CXX_MODULES, { cm::FileSetMetadata::CXX_MODULES, "3.28.0"_s } }, }; @@ -625,7 +627,8 @@ cm::optional GetFileSetInformation(cm::string_view type) } void cmExportCMakeConfigGenerator::GenerateTargetFileSets( - cmGeneratorTarget* gte, std::ostream& os, cmTargetExport const* te) + cmGeneratorTarget* gte, std::ostream& os, + ImportFileSetPropertyMap const& properties, cmTargetExport const* te) { cmGeneratorFileSets const* gfs = gte->GetGeneratorFileSets(); auto const& types = gfs->GetInterfaceFileSetTypes(); @@ -648,9 +651,20 @@ void cmExportCMakeConfigGenerator::GenerateTargetFileSets( << this->GetFileSetDirectories(gte, fileSet, te) << "\n FILES " << this->GetFileSetFiles(gte, fileSet, te) << '\n'; } + os << " )\n"; + for (auto const* fileSet : gfs->GetInterfaceFileSets(type)) { + auto fsProperties = properties.find(fileSet->GetName()); + if (fsProperties != properties.end()) { + for (auto const& property : fsProperties->second) { + os << "\n set_property(FILE_SET " + << cmScriptGenerator::Quote(fileSet->GetName()) << " TARGET " + << targetName << "\n PROPERTY " << property.first << ' ' + << cmExportFileGeneratorEscape(property.second) << "\n )"; + } + } + } if (fsInfo) { - os << " )"; if (type == cm::FileSetMetadata::HEADERS) { os << "\nelse()\n set_property(TARGET " << targetName << "\n APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES"; @@ -658,6 +672,10 @@ void cmExportCMakeConfigGenerator::GenerateTargetFileSets( os << "\n " << this->GetFileSetDirectories(gte, fileSet, te); } os << "\n )"; + } else if (type == cm::FileSetMetadata::SOURCES) { + os << "\nelse()\n message(FATAL_ERROR \"The target '" << targetName + << "' cannot be imported because it relies on 'FILE_SET' of type " + "'SOURCES' which is not supported by this CMake version.\")"; } else if (type == cm::FileSetMetadata::CXX_MODULES) { os << "\nelse()\n message(AUTHOR_WARNING \"The target '" << targetName diff --git a/Source/cmExportCMakeConfigGenerator.h b/Source/cmExportCMakeConfigGenerator.h index a715280086..b2401e5da7 100644 --- a/Source/cmExportCMakeConfigGenerator.h +++ b/Source/cmExportCMakeConfigGenerator.h @@ -44,6 +44,7 @@ public: protected: using ImportPropertyMap = std::map; + using ImportFileSetPropertyMap = std::map; // Methods to implement export file code generation. bool GenerateImportFile(std::ostream& os) override; @@ -84,6 +85,7 @@ protected: cmGeneratorTarget const* target, ImportPropertyMap& properties); void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os, + ImportFileSetPropertyMap const& properties, cmTargetExport const* te = nullptr); std::string GetCxxModuleFile(std::string const& name) const override; diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 8e6df039c5..aeb68a35d7 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -16,6 +16,7 @@ #include "cmComputeLinkInformation.h" #include "cmFindPackageStack.h" #include "cmGeneratedFileStream.h" +#include "cmGeneratorFileSet.h" #include "cmGeneratorTarget.h" #include "cmLinkItem.h" #include "cmList.h" @@ -139,6 +140,20 @@ bool cmExportFileGenerator::PopulateInterfaceProperties( return true; } +bool cmExportFileGenerator::PopulateFileSetInterfaceProperties( + cmGeneratorTarget const* target, cmGeneratorFileSet const* fileSet, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties) +{ + this->PopulateFileSetInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", + target, fileSet, preprocessRule, + properties); + this->PopulateFileSetInterfaceProperty("INTERFACE_COMPILE_OPTIONS", target, + fileSet, preprocessRule, properties); + + return true; +} + void cmExportFileGenerator::PopulateInterfaceProperty( std::string const& propName, cmGeneratorTarget const* target, ImportPropertyMap& properties) const @@ -181,6 +196,29 @@ void cmExportFileGenerator::PopulateInterfaceProperty( properties); } +void cmExportFileGenerator::PopulateFileSetInterfaceProperty( + std::string const& propName, cmGeneratorTarget const* target, + cmGeneratorFileSet const* fileSet, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties) +{ + cmValue input = fileSet->GetProperty(propName); + if (input) { + if (input->empty()) { + // Set to empty + properties[propName].clear(); + return; + } + + std::string prepro = + cmGeneratorExpression::Preprocess(*input, preprocessRule); + if (!prepro.empty()) { + this->ResolveTargetsInGeneratorExpressions(prepro, target); + properties[propName] = prepro; + } + } +} + bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index fdd1879b90..814fd544e7 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -18,6 +18,7 @@ class cmExportSet; class cmGeneratorTarget; +class cmGeneratorFileSet; class cmLocalGenerator; /** \class cmExportFileGenerator @@ -48,6 +49,7 @@ public: protected: using ImportPropertyMap = std::map; + using ImportFileSetPropertyMap = std::map; // Collect properties with detailed information about targets beyond // their location on disk. @@ -112,6 +114,10 @@ protected: cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, ImportPropertyMap& properties); + void PopulateFileSetInterfaceProperty( + std::string const& propName, cmGeneratorTarget const* target, + cmGeneratorFileSet const* fileSet, + cmGeneratorExpression::PreprocessContext, ImportPropertyMap& properties); bool PopulateInterfaceLinkLibrariesProperty( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, ImportPropertyMap& properties); @@ -122,6 +128,11 @@ protected: cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties); + bool PopulateFileSetInterfaceProperties( + cmGeneratorTarget const* target, cmGeneratorFileSet const* fileSet, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties); + virtual void IssueMessage(MessageType type, std::string const& message) const = 0; virtual void IssueDiagnostic(cmDiagnosticCategory category, diff --git a/Source/cmExportInstallCMakeConfigGenerator.cxx b/Source/cmExportInstallCMakeConfigGenerator.cxx index 912ff39d71..eae42b6ee5 100644 --- a/Source/cmExportInstallCMakeConfigGenerator.cxx +++ b/Source/cmExportInstallCMakeConfigGenerator.cxx @@ -83,6 +83,11 @@ bool cmExportInstallCMakeConfigGenerator::GenerateMainFile(std::ostream& os) return false; } + ImportFileSetPropertyMap fsProperties; + if (!this->PopulateFileSetInterfaceProperties(te, fsProperties)) { + return false; + } + if (this->PopulateInterfaceLinkLibrariesProperty( gt, cmGeneratorExpression::InstallInterface, properties) && !this->ExportOld) { @@ -99,7 +104,7 @@ bool cmExportInstallCMakeConfigGenerator::GenerateMainFile(std::ostream& os) this->GenerateInterfaceProperties(gt, os, properties); - this->GenerateTargetFileSets(gt, os, te); + this->GenerateTargetFileSets(gt, os, fsProperties, te); } this->LoadConfigFiles(os); diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 00e7c35395..c63f8a93b1 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -12,6 +12,8 @@ #include "cmExportSet.h" #include "cmGeneratedFileStream.h" +#include "cmGeneratorFileSet.h" +#include "cmGeneratorFileSets.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmInstallTargetGenerator.h" @@ -410,6 +412,27 @@ bool cmExportInstallFileGenerator::PopulateInterfaceProperties( properties); } +bool cmExportInstallFileGenerator::PopulateFileSetInterfaceProperties( + cmTargetExport const* targetExport, ImportFileSetPropertyMap& properties) +{ + cmGeneratorTarget const* const gt = targetExport->Target; + cmGeneratorFileSets const* const gfs = gt->GetGeneratorFileSets(); + + bool result = true; + + for (auto const& type : gfs->GetInterfaceFileSetTypes()) { + for (auto const* fileSet : gfs->GetInterfaceFileSets(type)) { + ImportPropertyMap& fsProperties = properties[fileSet->GetName()]; + this->PopulateFileSetIncludeDirectoriesInterface( + gt, fileSet, cmGeneratorExpression::InstallInterface, fsProperties); + result = result && + this->PopulateFileSetInterfaceProperties( + gt, fileSet, cmGeneratorExpression::InstallInterface, fsProperties); + } + } + return result; +} + namespace { bool isSubDirectory(std::string const& a, std::string const& b) { @@ -620,6 +643,37 @@ void cmExportInstallFileGenerator::PopulateIncludeDirectoriesInterface( } } +void cmExportInstallFileGenerator::PopulateFileSetIncludeDirectoriesInterface( + cmGeneratorTarget const* target, cmGeneratorFileSet const* fileSet, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties) +{ + assert(preprocessRule == cmGeneratorExpression::InstallInterface); + + char const* const propName = "INTERFACE_INCLUDE_DIRECTORIES"; + cmValue includes = fileSet->GetProperty(propName); + + if (!includes) { + return; + } + if (includes && includes->empty()) { + // Set to empty + properties[propName].clear(); + return; + } + + std::string prepro = cmGeneratorExpression::Preprocess( + *includes, preprocessRule, this->GetImportPrefixWithSlash()); + if (!prepro.empty()) { + this->ResolveTargetsInGeneratorExpressions(prepro, target); + + if (!this->CheckInterfaceDirs(prepro, target, propName)) { + return; + } + properties[propName] = prepro; + } +} + void cmExportInstallFileGenerator::PopulateLinkDependsInterface( cmGeneratorTarget const* gt, cmGeneratorExpression::PreprocessContext preprocessRule, diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index ad0bdd3065..baee7852fc 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -19,6 +19,7 @@ #include "cmStateTypes.h" class cmGeneratorTarget; +class cmGeneratorFileSet; class cmInstallTargetGenerator; class cmTargetExport; @@ -138,6 +139,10 @@ protected: ImportPropertyMap& properties, std::set& importedLocations); + using cmExportFileGenerator::PopulateFileSetInterfaceProperties; + bool PopulateFileSetInterfaceProperties( + cmTargetExport const* targetExport, ImportFileSetPropertyMap& properties); + virtual bool CheckInterfaceDirs(std::string const& prepro, cmGeneratorTarget const* target, std::string const& prop) const; @@ -179,4 +184,9 @@ private: cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties); + + void PopulateFileSetIncludeDirectoriesInterface( + cmGeneratorTarget const* target, cmGeneratorFileSet const* fileSet, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties); }; diff --git a/Tests/RunCMake/FileSet-SOURCES/FileSetExport.cmake b/Tests/RunCMake/FileSet-SOURCES/FileSetExport.cmake new file mode 100644 index 0000000000..9f508671c5 --- /dev/null +++ b/Tests/RunCMake/FileSet-SOURCES/FileSetExport.cmake @@ -0,0 +1,40 @@ +enable_language(C) + +add_library(lib1 STATIC) +target_sources(lib1 PRIVATE lib1.c) +target_sources(lib1 PUBLIC FILE_SET a TYPE SOURCES FILES lib2.c) + +set_property(FILE_SET a TARGET lib1 PROPERTY COMPILE_DEFINITIONS LIB1_A) +set_property(FILE_SET a TARGET lib1 PROPERTY COMPILE_OPTIONS -DOPT_LIB1_A) +set_property(FILE_SET a TARGET lib1 PROPERTY INCLUDE_DIRECTORIES "$" + "$") + +set_property(FILE_SET a TARGET lib1 PROPERTY INTERFACE_COMPILE_DEFINITIONS INTERFACE_LIB1_A) +set_property(FILE_SET a TARGET lib1 PROPERTY INTERFACE_COMPILE_OPTIONS -DOPT_INTERFACE_LIB1_A) +set_property(FILE_SET a TARGET lib1 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$" + "$") + +target_sources(lib1 PUBLIC FILE_SET SOURCES FILES lib5.c) + +set_property(FILE_SET SOURCES TARGET lib1 PROPERTY INTERFACE_COMPILE_DEFINITIONS INTERFACE_LIB1_SRCS) +set_property(FILE_SET SOURCES TARGET lib1 PROPERTY INTERFACE_COMPILE_OPTIONS -DOPT_INTERFACE_LIB1_SRCS) +set_property(FILE_SET SOURCES TARGET lib1 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$" + "$") + + +add_executable(main main.c) +target_link_libraries(main PRIVATE lib1) +target_compile_definitions(main PRIVATE CONSUMER) + +if(CMAKE_GENERATOR MATCHES "Xcode") + install(TARGETS lib1 EXPORT export FILE_SET a DESTINATION sources + FILE_SET SOURCES DESTINATION sources/srcs) +else() + install(TARGETS lib1 EXPORT export FILE_SET a DESTINATION sources + FILE_SET SOURCES DESTINATION sources/$,debug,release>) +endif() +install(FILES subdir1/h1.h subdir1/h3.h DESTINATION include/subdir1) +install(FILES subdir2/h2.h subdir2/h3.h DESTINATION include/subdir2) + +install(EXPORT export FILE export.cmake NAMESPACE install:: DESTINATION lib/cmake) +export(EXPORT export FILE export.cmake NAMESPACE export::) diff --git a/Tests/RunCMake/FileSet-SOURCES/FileSetImport.cmake b/Tests/RunCMake/FileSet-SOURCES/FileSetImport.cmake new file mode 100644 index 0000000000..53264cf66f --- /dev/null +++ b/Tests/RunCMake/FileSet-SOURCES/FileSetImport.cmake @@ -0,0 +1,85 @@ +enable_language(C) + +get_property(multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + +function(assert_target_prop_eq tgt prop value) + unset(actual_value) + get_property(actual_value TARGET ${tgt} PROPERTY ${prop}) + if(NOT actual_value STREQUAL value) + message(SEND_ERROR "Expected value of target ${prop}:\n ${value}\nActual value:\n ${actual_value}") + endif() +endfunction() + +function(assert_fileset_prop_eq tgt fs prop value) + unset(actual_value) + get_property(actual_value FILE_SET ${fs} TARGET ${tgt} PROPERTY ${prop}) + if(NOT actual_value STREQUAL value) + message(SEND_ERROR "Expected value of file set ${prop}:\n ${value}\nActual value:\n ${actual_value}") + endif() +endfunction() + +cmake_path(GET CMAKE_BINARY_DIR PARENT_PATH export_build_dir) +cmake_path(APPEND export_build_dir "FileSetExport-build") + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_EQUAL 4.3 + AND NOT CMAKE_PATCH_VERSION VERSION_LESS 20000000) + # development version for future 4.4: Force version 4.4 + set(CMAKE_VERSION_BACKUP "${CMAKE_VERSION}") + set(CMAKE_VERSION 4.4) +endif() +include("${export_build_dir}/export.cmake") +include("${export_build_dir}/install/lib/cmake/export.cmake") +if(CMAKE_VERSION VERSION_GREATER 4.3 AND CMAKE_VERSION VERSION_LESS 4.4 + AND NOT CMake_VERSION_PATCH VERSION_LESS 20000000) + # development version for future 4.4: Force version 4.4 + set(CMAKE_VERSION "${CMAKE_VERSION_BACKUP}") +endif() + + +assert_target_prop_eq(export::lib1 SOURCE_SETS "") +assert_target_prop_eq(export::lib1 INTERFACE_SOURCE_SETS "a;SOURCES") +assert_target_prop_eq(export::lib1 SOURCE_SET_a "${CMAKE_CURRENT_SOURCE_DIR}/lib2.c") +assert_target_prop_eq(export::lib1 SOURCE_SET "${CMAKE_CURRENT_SOURCE_DIR}/lib5.c") +assert_target_prop_eq(export::lib1 SOURCE_SET_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/lib5.c") + +assert_fileset_prop_eq(export::lib1 a INTERFACE_COMPILE_DEFINITIONS "INTERFACE_LIB1_A") +assert_fileset_prop_eq(export::lib1 a INTERFACE_COMPILE_OPTIONS "-DOPT_INTERFACE_LIB1_A") +assert_fileset_prop_eq(export::lib1 a INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/subdir2") + +assert_fileset_prop_eq(export::lib1 SOURCES INTERFACE_COMPILE_DEFINITIONS "INTERFACE_LIB1_SRCS") +assert_fileset_prop_eq(export::lib1 SOURCES INTERFACE_COMPILE_OPTIONS "-DOPT_INTERFACE_LIB1_SRCS") +assert_fileset_prop_eq(export::lib1 SOURCES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/srcs") + + +assert_target_prop_eq(install::lib1 SOURCE_SETS "") +assert_target_prop_eq(install::lib1 INTERFACE_SOURCE_SETS "a;SOURCES") +assert_target_prop_eq(install::lib1 SOURCE_SET_a "${export_build_dir}/install/sources/lib2.c") +if(multi_config) + if(CMAKE_GENERATOR MATCHES "Xcode") + assert_target_prop_eq(install::lib1 SOURCE_SET "${export_build_dir}/install/sources/srcs/lib5.c") + assert_target_prop_eq(install::lib1 SOURCE_SET_SOURCES "${export_build_dir}/install/sources/srcs/lib5.c") + else() + assert_target_prop_eq(install::lib1 SOURCE_SET "$<$:${export_build_dir}/install/sources/debug/lib5.c>;$<$:${export_build_dir}/install/sources/release/lib5.c>") + assert_target_prop_eq(install::lib1 SOURCE_SET_SOURCES "$<$:${export_build_dir}/install/sources/debug/lib5.c>;$<$:${export_build_dir}/install/sources/release/lib5.c>") + endif() +else() + assert_target_prop_eq(install::lib1 SOURCE_SET "${export_build_dir}/install/sources/debug/lib5.c") + assert_target_prop_eq(install::lib1 SOURCE_SET_SOURCES "${export_build_dir}/install/sources/debug/lib5.c") +endif() + +assert_fileset_prop_eq(install::lib1 a INTERFACE_COMPILE_DEFINITIONS "INTERFACE_LIB1_A") +assert_fileset_prop_eq(install::lib1 a INTERFACE_COMPILE_OPTIONS "-DOPT_INTERFACE_LIB1_A") +assert_fileset_prop_eq(install::lib1 a INTERFACE_INCLUDE_DIRECTORIES "${export_build_dir}/install/include/subdir2") + +assert_fileset_prop_eq(install::lib1 SOURCES INTERFACE_COMPILE_DEFINITIONS "INTERFACE_LIB1_SRCS") +assert_fileset_prop_eq(install::lib1 SOURCES INTERFACE_COMPILE_OPTIONS "-DOPT_INTERFACE_LIB1_SRCS") +assert_fileset_prop_eq(install::lib1 SOURCES INTERFACE_INCLUDE_DIRECTORIES "${export_build_dir}/install/include/srcs") + + +add_executable(main_export main.c) +target_link_libraries(main_export PRIVATE export::lib1) +target_compile_definitions(main_export PRIVATE CONSUMER) + +add_executable(main_install main.c) +target_link_libraries(main_install PRIVATE install::lib1) +target_compile_definitions(main_install PRIVATE CONSUMER) diff --git a/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface-result.txt b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface-stderr.txt b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface-stderr.txt new file mode 100644 index 0000000000..62bef3e166 --- /dev/null +++ b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface-stderr.txt @@ -0,0 +1,5 @@ +CMake Error at InstallMissingSetsInterface\.cmake:[0-9]+ \(install\): + install TARGETS target lib1 is exported but not all of its interface file + sets are installed +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface.cmake b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface.cmake new file mode 100644 index 0000000000..9567291d66 --- /dev/null +++ b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterface.cmake @@ -0,0 +1,5 @@ +enable_language(C) + +add_library(lib1 STATIC) +target_sources(lib1 INTERFACE FILE_SET a TYPE SOURCES BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES lib1.c) +install(TARGETS lib1 EXPORT a) diff --git a/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall-result.txt b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall-stderr.txt b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall-stderr.txt new file mode 100644 index 0000000000..948dbf7afa --- /dev/null +++ b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall-stderr.txt @@ -0,0 +1,6 @@ +CMake Error in CMakeLists\.txt: + File set "a" is listed in interface file sets of lib1 but has not been + exported + + +CMake Generate step failed\. Build files cannot be regenerated correctly\. diff --git a/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall.cmake b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall.cmake new file mode 100644 index 0000000000..b3c2476d77 --- /dev/null +++ b/Tests/RunCMake/FileSet-SOURCES/InstallMissingSetsInterfacePostInstall.cmake @@ -0,0 +1,6 @@ +enable_language(C) + +add_library(lib1 STATIC) +install(TARGETS lib1 EXPORT a) +target_sources(lib1 INTERFACE FILE_SET a TYPE SOURCES BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES lib1.c) +install(EXPORT a DESTINATION lib/cmake/test) diff --git a/Tests/RunCMake/FileSet-SOURCES/RunCMakeTest.cmake b/Tests/RunCMake/FileSet-SOURCES/RunCMakeTest.cmake index 0b02f0782b..54df951916 100644 --- a/Tests/RunCMake/FileSet-SOURCES/RunCMakeTest.cmake +++ b/Tests/RunCMake/FileSet-SOURCES/RunCMakeTest.cmake @@ -41,3 +41,53 @@ if ((RunCMake_GENERATOR MATCHES "Makefiles|Ninja|Xcode" AND NOT CMAKE_C_COMPILER_ID STREQUAL "Intel") run_and_check(FileSetProperties2 lib1 main) endif() + +function(run_export_import name) + if(ARGV1) + set(importname ${ARGV1}) + else() + set(importname ${name}) + endif() + + if(RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(_config_options "-DCMAKE_CONFIGURATION_TYPES=Debug\\\\;Release") + else() + set(_config_options -DCMAKE_BUILD_TYPE=Debug) + endif() + + set(RunCMake_TEST_NO_CLEAN 1) + set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${name}Export-build") + set(RunCMake_TEST_OPTIONS "--install-prefix=${RunCMake_TEST_BINARY_DIR}/install" ${_config_options}) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + run_cmake(${name}Export) + if(RunCMake_GENERATOR_IS_MULTI_CONFIG) + run_cmake_command(${name}Export-build-Debug ${CMAKE_COMMAND} --build . --config Debug) + run_cmake_command(${name}Export-install-Debug ${CMAKE_COMMAND} --install . --config Debug) + run_cmake_command(${name}Export-build-Release ${CMAKE_COMMAND} --build . --config Release) + run_cmake_command(${name}Export-install-Release ${CMAKE_COMMAND} --install . --config Release) + else() + run_cmake_command(${name}Export-build ${CMAKE_COMMAND} --build . --config Debug) + run_cmake_command(${name}Export-install ${CMAKE_COMMAND} --install . --config Debug) + endif() + unset(RunCMake_TEST_OPTIONS) + + set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${importname}Import-build") + unset(RunCMake_TEST_OPTIONS) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + run_cmake(${importname}Import) + if(RunCMake_GENERATOR_IS_MULTI_CONFIG) + run_cmake_command(${importname}Import-build-Debug ${CMAKE_COMMAND} --build . --config Debug) + run_cmake_command(${importname}Import-build-Release ${CMAKE_COMMAND} --build . --config Release) + else() + run_cmake_command(${importname}Import-build ${CMAKE_COMMAND} --build . --config Debug) + endif() + + unset(RunCMake_TEST_BINARY_DIR) + unset(RunCMake_TEST_NO_CLEAN) +endfunction() + +run_cmake(InstallMissingSetsInterface) +run_cmake(InstallMissingSetsInterfacePostInstall) +run_export_import(FileSet) diff --git a/Tests/RunCMake/FileSet-SOURCES/lib5.c b/Tests/RunCMake/FileSet-SOURCES/lib5.c index e69de29bb2..431805cf55 100644 --- a/Tests/RunCMake/FileSet-SOURCES/lib5.c +++ b/Tests/RunCMake/FileSet-SOURCES/lib5.c @@ -0,0 +1,4 @@ + +void f5(void) +{ +}