Browse Source

target_sources(): Process multiple FILE_SET arguments per block

Fixes: #23287
Kyle Edwards 3 years ago
parent
commit
8c23ecbd93

+ 3 - 2
Help/command/target_sources.rst

@@ -68,8 +68,9 @@ File Sets
 .. code-block:: cmake
 
   target_sources(<target>
-    <INTERFACE|PUBLIC|PRIVATE> FILE_SET set1 [TYPE type1] [BASE_DIRS dirs1...] [FILES files1...]
-    [<INTERFACE|PUBLIC|PRIVATE> FILE_SET set2 [TYPE type2] [BASE_DIRS dirs2...] [FILES files2...])
+    [<INTERFACE|PUBLIC|PRIVATE>
+     [FILE_SET <set> [TYPE <type>] [BASE_DIRS <dirs>...] [FILES <files>...]]...
+    ]...)
 
 Adds a file set to a target, or adds files to an existing file set. Targets
 have zero or more named file sets. Each file set has a name, a type, a scope of

+ 28 - 5
Source/cmTargetSourcesCommand.cxx

@@ -38,6 +38,14 @@ auto const FileSetArgsParser = cmArgumentParser<FileSetArgs>()
                                  .Bind("BASE_DIRS"_s, &FileSetArgs::BaseDirs)
                                  .Bind("FILES"_s, &FileSetArgs::Files);
 
+struct FileSetsArgs
+{
+  std::vector<std::vector<std::string>> FileSets;
+};
+
+auto const FileSetsArgsParser =
+  cmArgumentParser<FileSetsArgs>().Bind("FILE_SET"_s, &FileSetsArgs::FileSets);
+
 class TargetSourcesImpl : public cmTargetPropCommandBase
 {
 public:
@@ -79,7 +87,7 @@ private:
                                 bool prepend, bool system) override
   {
     if (!content.empty() && content.front() == "FILE_SET"_s) {
-      return this->HandleFileSetMode(scope, content, prepend, system);
+      return this->HandleFileSetMode(scope, content);
     }
     return this->cmTargetPropCommandBase::PopulateTargetProperties(
       scope, content, prepend, system);
@@ -105,8 +113,9 @@ private:
     IsInterface isInterfaceContent, CheckCMP0076 checkCmp0076);
 
   bool HandleFileSetMode(const std::string& scope,
-                         const std::vector<std::string>& content, bool prepend,
-                         bool system);
+                         const std::vector<std::string>& content);
+  bool HandleOneFileSet(const std::string& scope,
+                        const std::vector<std::string>& content);
 };
 
 std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent(
@@ -186,8 +195,22 @@ std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent(
 }
 
 bool TargetSourcesImpl::HandleFileSetMode(
-  const std::string& scope, const std::vector<std::string>& content,
-  bool /*prepend*/, bool /*system*/)
+  const std::string& scope, const std::vector<std::string>& content)
+{
+  auto args = FileSetsArgsParser.Parse(content);
+
+  for (auto& argList : args.FileSets) {
+    argList.emplace(argList.begin(), "FILE_SET"_s);
+    if (!this->HandleOneFileSet(scope, argList)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool TargetSourcesImpl::HandleOneFileSet(
+  const std::string& scope, const std::vector<std::string>& content)
 {
   std::vector<std::string> unparsed;
   auto args = FileSetArgsParser.Parse(content, &unparsed);

+ 9 - 5
Tests/RunCMake/target_sources/FileSetProperties.cmake

@@ -46,22 +46,26 @@ assert_prop_eq(lib1 HEADER_SET_b "${CMAKE_CURRENT_SOURCE_DIR}/dir/dir.h")
 assert_prop_eq(lib1 INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir>")
 assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>")
 
-target_sources(lib1 INTERFACE FILE_SET c TYPE HEADERS)
+target_sources(lib1 INTERFACE FILE_SET c TYPE HEADERS FILE_SET d TYPE HEADERS)
 assert_prop_eq(lib1 HEADER_SETS "a;b")
-assert_prop_eq(lib1 INTERFACE_HEADER_SETS "a;c")
+assert_prop_eq(lib1 INTERFACE_HEADER_SETS "a;c;d")
 assert_prop_eq(lib1 HEADER_DIRS_c "${CMAKE_CURRENT_SOURCE_DIR}")
 assert_prop_eq(lib1 HEADER_SET_c "")
+assert_prop_eq(lib1 HEADER_DIRS_d "${CMAKE_CURRENT_SOURCE_DIR}")
+assert_prop_eq(lib1 HEADER_SET_d "")
 assert_prop_eq(lib1 INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir>")
-assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
+assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
 
 target_sources(lib1 PUBLIC FILE_SET HEADERS BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}" FILES h1.h)
+assert_prop_eq(lib1 INTERFACE_HEADER_SETS "a;c;d;HEADERS")
 assert_prop_eq(lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
 assert_prop_eq(lib1 HEADER_SET "${CMAKE_CURRENT_SOURCE_DIR}/h1.h")
 assert_prop_eq(lib1 INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
-assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
+assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
 
 target_sources(lib1 PUBLIC FILE_SET HEADERS FILES h2.h)
+assert_prop_eq(lib1 INTERFACE_HEADER_SETS "a;c;d;HEADERS")
 assert_prop_eq(lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
 assert_prop_eq(lib1 HEADER_SET "${CMAKE_CURRENT_SOURCE_DIR}/h1.h;${CMAKE_CURRENT_SOURCE_DIR}/h2.h")
 assert_prop_eq(lib1 INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
-assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
+assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")