[clang] [llvm] [CMake] Version Darwin dylib identities (PR #189004)

Tamir Duberstein via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 27 09:25:01 PDT 2026


https://github.com/tamird updated https://github.com/llvm/llvm-project/pull/189004

>From a15a0471999eb013bf98273dc10042877c2c9978 Mon Sep 17 00:00:00 2001
From: Tamir Duberstein <tamird at gmail.com>
Date: Fri, 27 Mar 2026 08:45:11 -0700
Subject: [PATCH 1/2] [CMake] Group SOVERSION logic

There are two blocks who conditions are quite coupled; combine them to
make the conditional logic less error prone.
---
 llvm/cmake/modules/AddLLVM.cmake | 48 +++++++++++++++-----------------
 1 file changed, 22 insertions(+), 26 deletions(-)

diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
index e2d0f74f26058..f528af9b2bdf3 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -796,14 +796,28 @@ function(llvm_add_library name)
         )
     endif()
 
-    # Set SOVERSION on shared libraries that lack explicit SONAME
-    # specifier, on *nix systems that are not Darwin.
-    if(UNIX AND NOT APPLE AND NOT ARG_SONAME)
-      set_target_properties(${name}
-        PROPERTIES
-        # Since 18.1.0, the ABI version is indicated by the major and minor version.
-        SOVERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}${LLVM_VERSION_SUFFIX}
-        VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}${LLVM_VERSION_SUFFIX})
+    if(NOT APPLE)
+      if(ARG_SONAME)
+        get_target_property(output_name ${name} OUTPUT_NAME)
+        if(${output_name} STREQUAL "output_name-NOTFOUND")
+          set(output_name ${name})
+        endif()
+        set(library_name ${output_name}-${LLVM_VERSION_MAJOR}${LLVM_VERSION_SUFFIX})
+        set(api_name ${output_name}-${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}${LLVM_VERSION_SUFFIX})
+        set_target_properties(${name} PROPERTIES OUTPUT_NAME ${library_name})
+        if(UNIX AND NOT CYGWIN)
+          llvm_install_library_symlink(${api_name} ${library_name} SHARED
+            COMPONENT ${name})
+          llvm_install_library_symlink(${output_name} ${library_name} SHARED
+            COMPONENT ${name})
+        endif()
+      elseif(UNIX)
+        set_target_properties(${name}
+          PROPERTIES
+          # Since 18.1.0, the ABI version is indicated by the major and minor version.
+          SOVERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}${LLVM_VERSION_SUFFIX}
+          VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}${LLVM_VERSION_SUFFIX})
+      endif()
     endif()
   endif()
 
@@ -819,24 +833,6 @@ function(llvm_add_library name)
     endif()
   endif()
 
-  if(ARG_SHARED)
-    if(NOT APPLE AND ARG_SONAME)
-      get_target_property(output_name ${name} OUTPUT_NAME)
-      if(${output_name} STREQUAL "output_name-NOTFOUND")
-        set(output_name ${name})
-      endif()
-      set(library_name ${output_name}-${LLVM_VERSION_MAJOR}${LLVM_VERSION_SUFFIX})
-      set(api_name ${output_name}-${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}${LLVM_VERSION_SUFFIX})
-      set_target_properties(${name} PROPERTIES OUTPUT_NAME ${library_name})
-      if(UNIX AND NOT CYGWIN)
-        llvm_install_library_symlink(${api_name} ${library_name} SHARED
-          COMPONENT ${name})
-        llvm_install_library_symlink(${output_name} ${library_name} SHARED
-          COMPONENT ${name})
-      endif()
-    endif()
-  endif()
-
   if(ARG_STATIC)
     set(libtype PUBLIC)
   else()

>From 35c0d1328a620e8cbb4919163022c6a62e44c3fb Mon Sep 17 00:00:00 2001
From: Tamir Duberstein <tamird at gmail.com>
Date: Thu, 26 Mar 2026 19:43:05 -0700
Subject: [PATCH 2/2] [CMake] Version Darwin dylib identities

Make Darwin shared libraries built through AddLLVM use versioned dylib
names and install names by default, and add a narrow opt-out for
downstream users that still depend on the legacy unversioned install
name.

This makes LLVM_VERSION_SUFFIX affect the Mach-O dylib identity rather
than only an extra filesystem alias. Distinct LLVM builds should not
advertise the same @rpath/libLLVM.dylib identity when they are not
interchangeable.

Implement this with VERSION/SOVERSION on Darwin too. Targets with
non-default Mach-O compatibility and current versions now set the
corresponding MACHO_* properties so CMake still owns the dylib name and
install_name while preserving their existing embedded version policy.
libLTO and libclang continue to use their own existing version policies
for the Darwin dylib identity instead of falling back to the generic
LLVM one. Export the new default through LLVMConfig.cmake as well so
in-tree and out-of-tree consumers see the same behavior, and pass the
option through clang bootstrap so later stages do not silently flip
back to the default.

The current split is historical. 5e96fe90 deliberately kept Darwin
libraries unversioned while changing Linux naming for ldconfig, and
6b929d5b later reintroduced VERSION/SOVERSION on Unix while explicitly
excluding Darwin. 61e900b4 then wired Darwin builds to use @rpath-based
install names, which made the unversioned policy part of the runtime
identity instead of just a filename choice. Linux continued to evolve in
91a38462 toward a more conventional versioned libLLVM identity, but
Darwin kept the older model.

Keep an escape hatch with LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN=OFF for
the plausible compatibility case where a downstream consumer still
expects the legacy unversioned @rpath/libLLVM.dylib identity.
---
 clang/CMakeLists.txt                    |  1 +
 clang/tools/libclang/CMakeLists.txt     | 12 ++++++------
 llvm/CMakeLists.txt                     |  7 +++++++
 llvm/cmake/modules/AddLLVM.cmake        |  9 ++++++++-
 llvm/cmake/modules/LLVMConfig.cmake.in  |  1 +
 llvm/docs/CMake.rst                     |  7 +++++++
 llvm/tools/llvm-shlib/CMakeLists.txt    |  7 +++----
 llvm/tools/lto/CMakeLists.txt           |  9 ++++++---
 llvm/tools/remarks-shlib/CMakeLists.txt |  5 +----
 9 files changed, 40 insertions(+), 18 deletions(-)

diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt
index b3bc56209fc9e..d9ee5e05d995c 100644
--- a/clang/CMakeLists.txt
+++ b/clang/CMakeLists.txt
@@ -724,6 +724,7 @@ if (CLANG_ENABLE_BOOTSTRAP)
     LLVM_VERSION_MAJOR
     LLVM_VERSION_MINOR
     LLVM_VERSION_PATCH
+    LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN
     CLANG_VERSION_MAJOR
     CLANG_VERSION_MINOR
     CLANG_VERSION_PATCHLEVEL
diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt
index 09322a424f488..02799dd4683e9 100644
--- a/clang/tools/libclang/CMakeLists.txt
+++ b/clang/tools/libclang/CMakeLists.txt
@@ -170,11 +170,12 @@ if(ENABLE_SHARED)
       # implicitly be exported from libclang.
       target_compile_definitions(libclang PRIVATE CLANG_BUILD_STATIC)
   elseif(APPLE)
-    set(LIBCLANG_LINK_FLAGS " -Wl,-compatibility_version -Wl,1")
-    set(LIBCLANG_LINK_FLAGS "${LIBCLANG_LINK_FLAGS} -Wl,-current_version -Wl,${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
-
-    set_property(TARGET libclang APPEND_STRING PROPERTY
-                 LINK_FLAGS ${LIBCLANG_LINK_FLAGS})
+    if(LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN)
+      set_target_properties(libclang PROPERTIES
+        VERSION ${LIBCLANG_LIBRARY_VERSION}
+        ${LIBCLANG_SOVERSION_ARG})
+    endif()
+    llvm_set_macho_current_version(libclang ${LLVM_VERSION_MAJOR})
   else()
     set_target_properties(libclang
       PROPERTIES
@@ -253,4 +254,3 @@ if(NOT LLVM_ENABLE_IDE)
                            COMPONENT
                              libclang-python-bindings)
 endif()
-
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index 6dbe47600cb2f..6a351cd1ab166 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -16,6 +16,13 @@ if(NOT LLVM_NO_INSTALL_NAME_DIR_FOR_BUILD_TREE)
   set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON)
 endif()
 
+# Darwin used to keep libLLVM's install name unversioned even when
+# LLVM_VERSION_SUFFIX was set. That makes distinct LLVM builds look
+# interchangeable to Mach-O consumers. Keep an opt-out for downstream users
+# that still depend on the legacy install name.
+option(LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN "If set, use versioned dylib names and install names on Darwin like other Unix platforms" ON)
+mark_as_advanced(LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN)
+
 include(${LLVM_COMMON_CMAKE_UTILS}/Modules/LLVMVersion.cmake)
 
 set_directory_properties(PROPERTIES LLVM_VERSION_MAJOR "${LLVM_VERSION_MAJOR}")
diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
index f528af9b2bdf3..0730ba2f529ed 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -246,6 +246,13 @@ function(add_llvm_symbol_exports target_name export_file)
   set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE)
 endfunction(add_llvm_symbol_exports)
 
+function(llvm_set_macho_current_version target major)
+  set_target_properties(${target} PROPERTIES
+    MACHO_COMPATIBILITY_VERSION 1
+    MACHO_CURRENT_VERSION
+      ${major}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH})
+endfunction()
+
 if (NOT DEFINED LLVM_LINKER_DETECTED AND NOT WIN32)
   # Detect what linker we have here.
   if(APPLE)
@@ -796,7 +803,7 @@ function(llvm_add_library name)
         )
     endif()
 
-    if(NOT APPLE)
+    if(NOT APPLE OR LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN)
       if(ARG_SONAME)
         get_target_property(output_name ${name} OUTPUT_NAME)
         if(${output_name} STREQUAL "output_name-NOTFOUND")
diff --git a/llvm/cmake/modules/LLVMConfig.cmake.in b/llvm/cmake/modules/LLVMConfig.cmake.in
index 0a7ae97bd7549..c7793005be258 100644
--- a/llvm/cmake/modules/LLVMConfig.cmake.in
+++ b/llvm/cmake/modules/LLVMConfig.cmake.in
@@ -17,6 +17,7 @@ set(LLVM_BUILD_TYPE @CMAKE_BUILD_TYPE@)
 set(CMAKE_MSVC_RUNTIME_LIBRARY @CMAKE_MSVC_RUNTIME_LIBRARY@)
 
 set(LLVM_USE_SPLIT_DWARF @LLVM_USE_SPLIT_DWARF@)
+set(LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN @LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN@)
 
 set(LLVM_COMMON_DEPENDS @LLVM_COMMON_DEPENDS@)
 
diff --git a/llvm/docs/CMake.rst b/llvm/docs/CMake.rst
index 6a70a82a6e438..8a666b6afc0e2 100644
--- a/llvm/docs/CMake.rst
+++ b/llvm/docs/CMake.rst
@@ -808,6 +808,13 @@ its enabled sub-projects. Nearly all of these variable names begin with
   library ID control variables (e.g., ``CMAKE_INSTALL_NAME_DIR``) are being
   set to non-standard values.
 
+**LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN**:BOOL
+  Defaults to ``ON``. If set to ``ON``, Darwin shared libraries built through
+  LLVM's CMake helpers use versioned dylib filenames and install names, matching
+  the behavior on other Unix platforms more closely. If set to ``OFF``, Darwin
+  keeps the legacy unversioned dylib install name, for compatibility with
+  existing consumers that expect ``@rpath/libLLVM.dylib``.
+
 **LLVM_OPTIMIZED_TABLEGEN**:BOOL
   If enabled and building a debug or assert build, the CMake build system will
   generate a Release build tree to build a fully optimized tablegen for use
diff --git a/llvm/tools/llvm-shlib/CMakeLists.txt b/llvm/tools/llvm-shlib/CMakeLists.txt
index 53003d90160fe..acf10b8a515b4 100644
--- a/llvm/tools/llvm-shlib/CMakeLists.txt
+++ b/llvm/tools/llvm-shlib/CMakeLists.txt
@@ -96,9 +96,7 @@ if(LLVM_BUILD_LLVM_DYLIB)
   endif()
 
   if (APPLE)
-    set_property(TARGET LLVM APPEND_STRING PROPERTY
-                LINK_FLAGS
-                " -compatibility_version 1 -current_version ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
+    llvm_set_macho_current_version(LLVM ${LLVM_VERSION_MAJOR})
   endif()
 
   if(TARGET libLLVMExports)
@@ -140,9 +138,10 @@ if(LLVM_BUILD_LLVM_C_DYLIB AND NOT MSVC)
   target_link_libraries(LLVM-C PUBLIC LLVM)
   add_dependencies(LLVM-C libLLVMCExports)
 
+  llvm_set_macho_current_version(LLVM-C ${LLVM_VERSION_MAJOR})
   set_property(TARGET LLVM-C APPEND_STRING PROPERTY
               LINK_FLAGS
-              " -compatibility_version 1 -current_version ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH} -Wl,-reexport_library ${LIB_PATH}")
+              " -Wl,-reexport_library ${LIB_PATH}")
 endif()
 
 if(LLVM_BUILD_LLVM_C_DYLIB AND MSVC)
diff --git a/llvm/tools/lto/CMakeLists.txt b/llvm/tools/lto/CMakeLists.txt
index bc0952b1980b6..179853e2962fd 100644
--- a/llvm/tools/lto/CMakeLists.txt
+++ b/llvm/tools/lto/CMakeLists.txt
@@ -45,9 +45,12 @@ if(LLVM_ENABLE_PIC)
     if(LLVM_LTO_VERSION_OFFSET)
       math(EXPR LTO_VERSION "${LLVM_VERSION_MAJOR} + ${LLVM_LTO_VERSION_OFFSET}")
     endif()
-    set_property(TARGET LTO APPEND_STRING PROPERTY
-                LINK_FLAGS
-                " -compatibility_version 1 -current_version ${LTO_VERSION}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
+    if(LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN)
+      set_target_properties(LTO PROPERTIES
+        SOVERSION ${LTO_VERSION}.${LLVM_VERSION_MINOR}${LLVM_VERSION_SUFFIX}
+        VERSION ${LTO_VERSION}.${LLVM_VERSION_MINOR}${LLVM_VERSION_SUFFIX})
+    endif()
+    llvm_set_macho_current_version(LTO ${LTO_VERSION})
     if(LLVM_USE_SANITIZER)
       execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=lib
                       OUTPUT_VARIABLE clang_lib_dir)
diff --git a/llvm/tools/remarks-shlib/CMakeLists.txt b/llvm/tools/remarks-shlib/CMakeLists.txt
index bc4bd67e2c9ec..1b14827e68cd3 100644
--- a/llvm/tools/remarks-shlib/CMakeLists.txt
+++ b/llvm/tools/remarks-shlib/CMakeLists.txt
@@ -25,10 +25,7 @@ if(LLVM_ENABLE_PIC)
     COMPONENT Remarks)
 
   if (APPLE)
-    set(REMARKS_VERSION ${LLVM_VERSION_MAJOR})
-    set_property(TARGET Remarks APPEND_STRING PROPERTY
-                 LINK_FLAGS
-                 " -compatibility_version 1 -current_version ${REMARKS_VERSION}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
+    llvm_set_macho_current_version(Remarks ${LLVM_VERSION_MAJOR})
   endif()
 
 endif()



More information about the cfe-commits mailing list