Browse Source

Swift: Expand generator expressions in Swift_MODULE_DIRECTORY

This patch makes the `Swift_MODULE_DIRECTORY` property behave more like
the other output directory properties, allowing generator expressions
and fixing the behavior with multi-config generators.

Issue: #26010
Evan Wilde 1 year ago
parent
commit
e1d635e71c

+ 8 - 8
Help/prop_tgt/Swift_MODULE_DIRECTORY.rst

@@ -11,14 +11,14 @@ placed in the build directory corresponding to the target's source directory.
 If the variable :variable:`CMAKE_Swift_MODULE_DIRECTORY` is set when a target is
 created its value is used to initialize this property.
 
-.. warning::
+.. versionadded:: 3.32
 
-  This property does not currently provide a way to express per-config
-  module directories, so use with multi-config generators is problematic:
+  The property value may use
+  :manual:`generator expressions <cmake-generator-expressions(7)>`.
+  Multi-configuration generators (:generator:`Ninja Multi-Config`) append a
+  per-configuration subdirectory to the specified directory unless a generator
+  expression is used.
 
-  * The :generator:`Xcode` generator does not implement the property at all.
+.. warning::
 
-  * The :generator:`Ninja Multi-Config` generator implements this property,
-    but module files generated for different build configurations have the
-    same path, which can lead to subtle problems when building more than
-    one configuration.
+  The :generator:`Xcode` generator ignores this property.

+ 5 - 0
Help/release/dev/swift-module-dir-genex.rst

@@ -0,0 +1,5 @@
+swift-module-dir-genex
+----------------------
+
+* The :prop_tgt:`Swift_MODULE_DIRECTORY` target property now supports
+  :manual:`generator expressions <cmake-generator-expressions(7)>`.

+ 15 - 3
Source/cmGeneratorTarget.cxx

@@ -6011,15 +6011,27 @@ std::string cmGeneratorTarget::GetSwiftModuleFileName() const
 std::string cmGeneratorTarget::GetSwiftModuleDirectory(
   std::string const& config) const
 {
-  std::string moduleDirectory =
-    this->GetPropertyOrDefault("Swift_MODULE_DIRECTORY", "");
+  // This is like the *_OUTPUT_DIRECTORY properties except that we don't have a
+  // separate per-configuration target property.
+  //
+  // The property expands generator expressions. Multi-config generators append
+  // a per-configuration subdirectory to the specified directory unless a
+  // generator expression is used.
+  bool appendConfigDir = true;
+  std::string moduleDirectory;
 
+  if (cmValue value = this->GetProperty("Swift_MODULE_DIRECTORY")) {
+    moduleDirectory = cmGeneratorExpression::Evaluate(
+      *value, this->LocalGenerator, config, this);
+    appendConfigDir = *value == moduleDirectory;
+  }
   if (moduleDirectory.empty()) {
     moduleDirectory = this->LocalGenerator->GetCurrentBinaryDirectory();
+  }
+  if (appendConfigDir) {
     this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
       "/", config, "", moduleDirectory);
   }
-
   return moduleDirectory;
 }
 

+ 2 - 2
Tests/RunCMake/Swift/CompileCommands-check.cmake

@@ -11,13 +11,13 @@ set(expected_compile_commands
   "directory": ".*(/Tests/RunCMake/Swift/CompileCommands-build|\\\\Tests\\\\RunCMake\\\\Swift\\\\CompileCommands-build)",
   "command": ".*swiftc .* (\\")?.*(/Tests/RunCMake/Swift/E.swift|\\\\Tests\\\\RunCMake\\\\Swift\\\\E.swift)(\\")? (\\")?.*(/Tests/RunCMake/Swift/L.swift|\\\\Tests\\\\RunCMake\\\\Swift\\\\L.swift)(\\")?",
   "file": ".*(/Tests/RunCMake/Swift/E.swift|\\\\Tests\\\\RunCMake\\\\Swift\\\\E.swift)",
-  "output": "CMakeFiles/CompileCommandLib.dir/(Debug(/|\\))?E.swift.o|CMakeFiles\\\\CompileCommandLib.dir\\\\E.swift.obj"
+  "output": "CMakeFiles/CompileCommandLib.dir/(Debug(/|\\))?E.swift.o|CMakeFiles\\\\CompileCommandLib.dir\\\\(Debug\\\\|Release\\\\)?E.swift.obj"
 },
 {
   "directory": ".*(/Tests/RunCMake/Swift/CompileCommands-build|\\\\Tests\\\\RunCMake\\\\Swift\\\\CompileCommands-build)",
   "command": ".*swiftc .* (\\")?.*(/Tests/RunCMake/Swift/E.swift|\\\\Tests\\\\RunCMake\\\\Swift\\\\E.swift)(\\")? (\\")?.*(/Tests/RunCMake/Swift/L.swift|\\\\Tests\\\\RunCMake\\\\Swift\\\\L.swift)(\\")?",
   "file": ".*/Tests/RunCMake/Swift/L.swift",
-  "output": "CMakeFiles/CompileCommandLib.dir/(Debug(/|\\))?L.swift.o|CMakeFiles\\\\CompileCommandLib.dir\\\\L.swift.obj"
+  "output": "CMakeFiles/CompileCommandLib.dir/(Debug(/|\\))?L.swift.o|CMakeFiles\\\\CompileCommandLib.dir\\\\(Debug\\\\|Release\\\\)?L.swift.obj"
 }
 ]$]==]
 )

+ 1 - 1
Tests/RunCMake/Swift/ImportLibraryFlags-check-stdout.txt

@@ -1 +1 @@
-.*-implib:lib\\L.lib
+.*-implib:lib\\(Debug\\|Release\\)?L.lib

+ 9 - 2
Tests/RunCMake/Swift/SwiftLibraryModuleCommand-check-stdout-darwin.txt

@@ -1,13 +1,20 @@
 .*swiftc(.exe)? [^
-]* -parse-as-library -static -emit-module [^
+]* -parse-as-library -static[^
+]* -emit-module -emit-module-path (Debug/|Release/)?StaticLibrary.swiftmodule[^
 ]* -module-name StaticLibrary [^
 ]*
 .*swiftc(.exe)? [^
-]* -parse-as-library -emit-module [^
+]* -parse-as-library[^
+]* -emit-module -emit-module-path (debug|release)/modules/DynamicLibrary.swiftmodule[^
 ]* -module-name DynamicLibrary [^
 ]*
 .*swiftc(.exe)? [^
 ]* -emit-library [^
 ]* -Xlinker -install_name -Xlinker @rpath/libDynamicLibrary.dylib -o ([A-Za-z]+/)?libDynamicLibrary.dylib [^
 ]*
+.*swiftc(.exe)? [^
+]* -parse-as-library[^
+]* -emit-module -emit-module-path Modules/(Debug/|Release/)?DynamicLibrary2.swiftmodule[^
+]* -module-name DynamicLibrary2[^
+]*
 .*swiftc(.exe)? -j [0-9]+ -num-threads [0-9]+ -c  -module-name Executable

+ 10 - 3
Tests/RunCMake/Swift/SwiftLibraryModuleCommand-check-stdout-windows.txt

@@ -1,13 +1,20 @@
 .*swiftc(.exe)? [^
-]* -parse-as-library -static -emit-module [^
+]* -parse-as-library -static[^
+]* -emit-module -emit-module-path (Debug\\|Release\\)?StaticLibrary.swiftmodule[^
 ]* -module-name StaticLibrary [^
 ]*
 .*swiftc(.exe)? [^
-]* -parse-as-library -emit-module [^
+]* -parse-as-library[^
+]* -emit-module -emit-module-path (debug|release)\\modules\\DynamicLibrary.swiftmodule[^
 ]* -module-name DynamicLibrary [^
 ]*
 .*swiftc(.exe)? [^
 ]* -emit-library [^
-]* -Xlinker -implib:DynamicLibrary.lib +-o ([A-Za-z]+/)?DynamicLibrary.dll [^
+]* -Xlinker -implib:(Debug\\|Release\\)?DynamicLibrary.lib +-o ([A-Za-z]+/)?(Debug\\|Release\\)?DynamicLibrary.dll [^
+]*
+.*swiftc(.exe)? [^
+]* -parse-as-library[^
+]* -emit-module -emit-module-path Modules\\(Debug\\|Release\\)?DynamicLibrary2.swiftmodule[^
+]* -module-name DynamicLibrary2 [^
 ]*
 .*swiftc(.exe)? -j [0-9]+ -num-threads [0-9]+ -c  -module-name Executable

+ 9 - 2
Tests/RunCMake/Swift/SwiftLibraryModuleCommand-check-stdout.txt

@@ -1,13 +1,20 @@
 .*swiftc(.exe)? [^
-]* -parse-as-library -static -emit-module [^
+]* -parse-as-library -static[^
+]* -emit-module -emit-module-path (Debug/|Release/)?StaticLibrary.swiftmodule[^
 ]* -module-name StaticLibrary [^
 ]*
 .*swiftc(.exe)? [^
-]* -parse-as-library -emit-module [^
+]* -parse-as-library[^
+]* -emit-module -emit-module-path (debug|release)/modules/DynamicLibrary.swiftmodule[^
 ]* -module-name DynamicLibrary [^
 ]*
 .*swiftc(.exe)? [^
 ]* -emit-library [^
 ]* -Xlinker -soname -Xlinker libDynamicLibrary.so -o ([A-Za-z]+/)?libDynamicLibrary.so [^
 ]*
+.*swiftc(.exe)? [^
+]* -parse-as-library[^
+]* -emit-module -emit-module-path Modules/(Debug/|Release/)?DynamicLibrary2.swiftmodule[^
+]* -module-name DynamicLibrary2[^
+]*
 .*swiftc(.exe)? -j [0-9]+ -num-threads [0-9]+ -c  -module-name Executable

+ 13 - 2
Tests/RunCMake/Swift/SwiftLibraryModuleCommand.cmake

@@ -6,8 +6,19 @@ enable_language(Swift)
 
 add_library(StaticLibrary STATIC L.swift)
 add_library(DynamicLibrary SHARED L.swift)
-set_target_properties(DynamicLibrary PROPERTIES INSTALL_NAME_DIR "@rpath")
+set_target_properties(DynamicLibrary
+  PROPERTIES
+    Swift_MODULE_DIRECTORY "$<IF:$<CONFIG:Release>,release/modules,debug/modules>"
+    INSTALL_NAME_DIR "@rpath")
+
+add_library(DynamicLibrary2 SHARED L.swift)
+set_target_properties(DynamicLibrary2
+  PROPERTIES
+    Swift_MODULE_DIRECTORY "Modules"
+    INSTALL_NAME_DIR "@rpath")
+
 add_executable(Executable E.swift)
 
+add_dependencies(DynamicLibrary2 DynamicLibrary)
 add_dependencies(DynamicLibrary StaticLibrary)
-add_dependencies(Executable DynamicLibrary)
+add_dependencies(Executable DynamicLibrary2)

+ 2 - 1
Tests/SwiftOnly/CMakeLists.txt

@@ -34,7 +34,8 @@ add_subdirectory(SubE)
 
 add_subdirectory("Sub Space")
 
-set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift)
+set(CMAKE_Swift_MODULE_DIRECTORY
+  "${CMAKE_BINARY_DIR}/modules/$<IF:$<CONFIG:Debug>,debug/,release/>swift")
 
 add_executable(SwiftOnly main.swift)
 target_compile_definitions(SwiftOnly PRIVATE SWIFTONLY)