From d4cc39842e9b912f8b25e2c7329f55bf7b53e5f0 Mon Sep 17 00:00:00 2001
From: Mikko Sivulainen <mikko.sivulainen@supercell.com>
Date: Wed, 14 Sep 2022 14:30:41 +0300
Subject: Xcode: Do not append per-config suffixes to library search paths

Add policy `CMP0142` to remove the automatic addition of the
`$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)` suffix in a compatible way.

Fixes: #21757
---
 Help/manual/cmake-policies.7.rst                   |  1 +
 Help/policy/CMP0142.rst                            | 27 ++++++++++++++++++++++
 Help/release/dev/xcode-lib-dirs.rst                |  6 +++++
 Source/cmGlobalXCodeGenerator.cxx                  | 10 ++++++--
 Source/cmPolicies.h                                |  9 ++++++--
 .../RunCMake/TargetPolicies/PolicyList-stderr.txt  |  1 +
 .../RunCMake/XcodeProject/SearchPaths-check.cmake  | 14 +++++++++++
 Tests/RunCMake/XcodeProject/SearchPaths.cmake      | 10 ++++++++
 8 files changed, 74 insertions(+), 4 deletions(-)
 create mode 100644 Help/policy/CMP0142.rst
 create mode 100644 Help/release/dev/xcode-lib-dirs.rst

diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index c0c37d1..d6a30ff 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -58,6 +58,7 @@ Policies Introduced by CMake 3.25
 .. toctree::
    :maxdepth: 1
 
+   CMP0142: The Xcode generator does not append per-config suffixes to library search paths. </policy/CMP0142>
    CMP0141: MSVC debug information format flags are selected by an abstraction. </policy/CMP0141>
    CMP0140: The return() command checks its arguments. </policy/CMP0140>
 
diff --git a/Help/policy/CMP0142.rst b/Help/policy/CMP0142.rst
new file mode 100644
index 0000000..1f928f0
--- /dev/null
+++ b/Help/policy/CMP0142.rst
@@ -0,0 +1,27 @@
+CMP0142
+-------
+
+.. versionadded:: 3.25
+
+The :generator:`Xcode` generator does not append per-config suffixes to
+library search paths.
+
+In CMake 3.24 and below, the :generator:`Xcode` generator preceded each
+entry of a library search path with a copy of itself appended with
+``$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)``.  This was left from
+very early versions of CMake in which per-config directories were not well
+modeled.  Such paths often do not exist, resulting in warnings from the
+toolchain.  CMake 3.25 and above prefer to not add such library search
+paths.  This policy provides compatibility for projects that may have been
+accidentally relying on the old behavior.
+
+The ``OLD`` behavior for this policy is to append
+``$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)`` to all library search paths.
+The ``NEW`` behavior is to not modify library search paths.
+
+This policy was introduced in CMake version 3.25.  Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/release/dev/xcode-lib-dirs.rst b/Help/release/dev/xcode-lib-dirs.rst
new file mode 100644
index 0000000..fc1fe1b
--- /dev/null
+++ b/Help/release/dev/xcode-lib-dirs.rst
@@ -0,0 +1,6 @@
+xcode-lib-dirs
+--------------
+
+* The :generator:`Xcode` generator no longer adds the per-config suffix
+  ``$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)`` to library search paths.
+  See policy :policy:`CMP0142`.
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index eb85b47..b4f1279 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -3776,14 +3776,20 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
     // add the library search paths
     {
       BuildObjectListOrString libSearchPaths(this, true);
+
       std::string linkDirs;
       for (auto const& libDir : cli->GetDirectories()) {
         if (!libDir.empty() && libDir != "/usr/lib") {
-          libSearchPaths.Add(this->XCodeEscapePath(
-            libDir + "/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"));
+          cmPolicies::PolicyStatus cmp0142 =
+            target->GetTarget()->GetPolicyStatusCMP0142();
+          if (cmp0142 == cmPolicies::OLD || cmp0142 == cmPolicies::WARN) {
+            libSearchPaths.Add(this->XCodeEscapePath(
+              libDir + "/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"));
+          }
           libSearchPaths.Add(this->XCodeEscapePath(libDir));
         }
       }
+
       // Add previously collected paths where to look for libraries
       // that were added to "Link Binary With Libraries"
       for (auto& libDir : linkSearchPaths) {
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index ea25814..4643868 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -427,7 +427,11 @@ class cmMakefile;
   SELECT(                                                                     \
     POLICY, CMP0141,                                                          \
     "MSVC debug information format flags are selected by an abstraction.", 3, \
-    25, 0, cmPolicies::WARN)
+    25, 0, cmPolicies::WARN)                                                  \
+  SELECT(POLICY, CMP0142,                                                     \
+         "The Xcode generator does not append per-config suffixes to "        \
+         "library search paths.",                                             \
+         3, 25, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
@@ -464,7 +468,8 @@ class cmMakefile;
   F(CMP0112)                                                                  \
   F(CMP0113)                                                                  \
   F(CMP0119)                                                                  \
-  F(CMP0131)
+  F(CMP0131)                                                                  \
+  F(CMP0142)
 
 /** \class cmPolicies
  * \brief Handles changes in CMake behavior and policies
diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
index 97c3394..0d8e4c9 100644
--- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
+++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
@@ -36,6 +36,7 @@
    \* CMP0113
    \* CMP0119
    \* CMP0131
+   \* CMP0142
 
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/XcodeProject/SearchPaths-check.cmake b/Tests/RunCMake/XcodeProject/SearchPaths-check.cmake
index 71b7d8f..bec8790 100644
--- a/Tests/RunCMake/XcodeProject/SearchPaths-check.cmake
+++ b/Tests/RunCMake/XcodeProject/SearchPaths-check.cmake
@@ -12,6 +12,8 @@ set(found_target_library_FRAMEWORK_SEARCH_PATHS 0)
 set(found_inherited_FRAMEWORK_SEARCH_PATHS 0)
 set(found_project_LIBRARY_SEARCH_PATHS 0)
 set(found_target_library_LIBRARY_SEARCH_PATHS 0)
+set(found_target_cmp0142old_LIBRARY_SEARCH_PATHS 0)
+set(found_target_cmp0142new_LIBRARY_SEARCH_PATHS 0)
 set(found_inherited_LIBRARY_SEARCH_PATHS 0)
 file(STRINGS "${xcProjectFile}" lines)
 foreach(line IN LISTS lines)
@@ -42,6 +44,12 @@ foreach(line IN LISTS lines)
     if(line MATCHES [[LIBRARY_SEARCH_PATHS = \("(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathLib/\$\(CONFIGURATION\)\$\(EFFECTIVE_PLATFORM_NAME\)(\\")?","(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathLib(\\")?","\$\(inherited\)"\);]])
       set(found_target_library_LIBRARY_SEARCH_PATHS 1)
     endif()
+    if(line MATCHES [[LIBRARY_SEARCH_PATHS = \("(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathCMP0142OLD/\$\(CONFIGURATION\)\$\(EFFECTIVE_PLATFORM_NAME\)(\\")?","(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathCMP0142OLD(\\")?","\$\(inherited\)"\);]])
+      set(found_target_cmp0142old_LIBRARY_SEARCH_PATHS 1)
+    endif()
+    if(line MATCHES [[LIBRARY_SEARCH_PATHS = \("(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathCMP0142NEW(\\")?","\$\(inherited\)"\);]])
+      set(found_target_cmp0142new_LIBRARY_SEARCH_PATHS 1)
+    endif()
     if(line MATCHES [[LIBRARY_SEARCH_PATHS = \("\$\(inherited\)"\);]])
       set(found_inherited_LIBRARY_SEARCH_PATHS 1)
     endif()
@@ -68,6 +76,12 @@ endif()
 if(NOT found_target_library_LIBRARY_SEARCH_PATHS)
   string(APPEND RunCMake_TEST_FAILED "Did not find expected LIBRARY_SEARCH_PATHS for target 'library' in\n  ${xcProjectFile}\n")
 endif()
+if(NOT found_target_cmp0142old_LIBRARY_SEARCH_PATHS)
+  string(APPEND RunCMake_TEST_FAILED "Did not find expected LIBRARY_SEARCH_PATHS for target 'cmp0142old' in\n  ${xcProjectFile}\n")
+endif()
+if(NOT found_target_cmp0142new_LIBRARY_SEARCH_PATHS)
+  string(APPEND RunCMake_TEST_FAILED "Did not find expected LIBRARY_SEARCH_PATHS for target 'cmp0142new' in\n  ${xcProjectFile}\n")
+endif()
 if(found_inherited_LIBRARY_SEARCH_PATHS)
   string(APPEND RunCMake_TEST_FAILED "Found unexpected LIBRARY_SEARCH_PATHS inherited-only value in\n  ${xcProjectFile}\n")
 endif()
diff --git a/Tests/RunCMake/XcodeProject/SearchPaths.cmake b/Tests/RunCMake/XcodeProject/SearchPaths.cmake
index ef97709..b469772 100644
--- a/Tests/RunCMake/XcodeProject/SearchPaths.cmake
+++ b/Tests/RunCMake/XcodeProject/SearchPaths.cmake
@@ -3,6 +3,8 @@ enable_language(C)
 file(MAKE_DIRECTORY  "${CMAKE_CURRENT_BINARY_DIR}/ProjectSearchPath")
 file(MAKE_DIRECTORY  "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathInc/TargetInc.framework")
 file(MAKE_DIRECTORY  "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathLib/TargetLib.framework")
+file(MAKE_DIRECTORY  "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathCMP0142OLD")
+file(MAKE_DIRECTORY  "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathCMP0142NEW")
 
 set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS "${CMAKE_CURRENT_BINARY_DIR}/ProjectSearchPath")
 set(CMAKE_XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS "${CMAKE_CURRENT_BINARY_DIR}/ProjectSearchPath")
@@ -19,3 +21,11 @@ target_include_directories(include PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSe
 add_executable(library main.c)
 target_link_libraries(library PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathLib/TargetLib.framework")
 target_link_directories(library PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathLib")
+
+cmake_policy(SET CMP0142 OLD)
+add_executable(cmp0142old main.c)
+target_link_directories(cmp0142old PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathCMP0142OLD")
+
+cmake_policy(SET CMP0142 NEW)
+add_executable(cmp0142new main.c)
+target_link_directories(cmp0142new PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathCMP0142NEW")
-- 
cgit v0.12