[clang] [llvm] [CMake] Version Darwin dylib identities (PR #189004)
Tamir Duberstein via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 2 12:00:58 PDT 2026
https://github.com/tamird updated https://github.com/llvm/llvm-project/pull/189004
>From 7e0be8d6d09635766f917408f8a9720132c13aef 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] [CMake] Version Darwin dylib identities
Make Darwin shared libraries built through AddLLVM use versioned
dylib names and install names by default, and add an 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. libclang and libLTO keep dedicated Darwin escape
hatches so they can remain unversioned by default even when Darwin
versioned dylib identities are enabled. Export the new default
through LLVMConfig.cmake as well so in-tree and out-of-tree
consumers see the same behavior, and pass the relevant options
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 | 3 +++
clang/tools/libclang/CMakeLists.txt | 9 +++++++++
llvm/CMakeLists.txt | 24 ++++++++++++++++++++++++
llvm/cmake/modules/AddLLVM.cmake | 2 +-
llvm/cmake/modules/LLVMConfig.cmake.in | 3 +++
llvm/docs/CMake.rst | 15 +++++++++++++++
llvm/tools/lto/CMakeLists.txt | 9 +++++++++
7 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt
index b3bc56209fc9e..40506fc8a1546 100644
--- a/clang/CMakeLists.txt
+++ b/clang/CMakeLists.txt
@@ -724,6 +724,9 @@ if (CLANG_ENABLE_BOOTSTRAP)
LLVM_VERSION_MAJOR
LLVM_VERSION_MINOR
LLVM_VERSION_PATCH
+ LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN
+ LLVM_UNVERSIONED_LIBCLANG_ON_DARWIN
+ LLVM_UNVERSIONED_LIBLTO_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 9b7ee51bb0c24..5fdfc474332f7 100644
--- a/clang/tools/libclang/CMakeLists.txt
+++ b/clang/tools/libclang/CMakeLists.txt
@@ -170,6 +170,15 @@ if(ENABLE_SHARED)
# implicitly be exported from libclang.
target_compile_definitions(libclang PRIVATE CLANG_BUILD_STATIC)
elseif(APPLE)
+ if(LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN)
+ set_target_properties(libclang PROPERTIES
+ VERSION ${LIBCLANG_LIBRARY_VERSION}
+ ${LIBCLANG_SOVERSION_ARG})
+ if(LLVM_UNVERSIONED_LIBCLANG_ON_DARWIN)
+ set_property(TARGET libclang PROPERTY SOVERSION)
+ set_property(TARGET libclang PROPERTY VERSION)
+ endif()
+ endif()
llvm_set_macho_current_version(libclang ${LLVM_VERSION_MAJOR})
else()
set_target_properties(libclang
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index 359d1591925b1..da012596cca93 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -16,6 +16,30 @@ 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)
+# At the time of writing (2026-04-01),
+# https://github.com/llvm/llvm-project/pull/189004#issuecomment-4171272082
+# claims that Xcode uses libclang for indexing and can load additional
+# toolchains, so keeping libclang.dylib unversioned avoids breaking that
+# compatibility by default. If this ever changes, audit Darwin libclang users
+# first and verify that Xcode and downstream toolchains accept a versioned
+# libclang install name before changing this default.
+option(LLVM_UNVERSIONED_LIBCLANG_ON_DARWIN "If set, keep libclang's Darwin dylib identity unversioned when Darwin versioned dylib names are enabled" ON)
+mark_as_advanced(LLVM_UNVERSIONED_LIBCLANG_ON_DARWIN)
+# At the time of writing (2026-04-01),
+# https://github.com/llvm/llvm-project/pull/189004#issuecomment-4165730721
+# claims that the macOS linker requires libLTO.dylib to keep that stable name
+# for LTO builds. If this ever changes, audit Darwin LTO users first and
+# verify that ld64 and downstream toolchains accept a versioned libLTO install
+# name before changing this default.
+option(LLVM_UNVERSIONED_LIBLTO_ON_DARWIN "If set, keep libLTO's Darwin dylib identity unversioned when Darwin versioned dylib names are enabled" ON)
+mark_as_advanced(LLVM_UNVERSIONED_LIBLTO_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 7b2424bf67e7d..0730ba2f529ed 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -803,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..23933e882ecec 100644
--- a/llvm/cmake/modules/LLVMConfig.cmake.in
+++ b/llvm/cmake/modules/LLVMConfig.cmake.in
@@ -17,6 +17,9 @@ 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_UNVERSIONED_LIBCLANG_ON_DARWIN @LLVM_UNVERSIONED_LIBCLANG_ON_DARWIN@)
+set(LLVM_UNVERSIONED_LIBLTO_ON_DARWIN @LLVM_UNVERSIONED_LIBLTO_ON_DARWIN@)
set(LLVM_COMMON_DEPENDS @LLVM_COMMON_DEPENDS@)
diff --git a/llvm/docs/CMake.rst b/llvm/docs/CMake.rst
index 6a70a82a6e438..7a73dd7f1e0f4 100644
--- a/llvm/docs/CMake.rst
+++ b/llvm/docs/CMake.rst
@@ -808,6 +808,21 @@ 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_UNVERSIONED_{LIBLTO,LIBCLANG}_ON_DARWIN**:BOOL
+ Default to ``ON``. When ``LLVM_VERSIONED_DYLIB_NAME_ON_DARWIN`` is ``ON``,
+ these keep ``libLTO`` and ``libclang``'s Darwin dylib identities
+ unversioned. Set ``LLVM_UNVERSIONED_LIBLTO_ON_DARWIN`` to ``OFF`` to
+ version ``libLTO`` using its Darwin ``LTO_VERSION`` policy instead. Set
+ ``LLVM_UNVERSIONED_LIBCLANG_ON_DARWIN`` to ``OFF`` to version
+ ``libclang`` using its existing ABI version policy instead.
+
**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/lto/CMakeLists.txt b/llvm/tools/lto/CMakeLists.txt
index 6be458dca7aac..5d13bf5e1e80d 100644
--- a/llvm/tools/lto/CMakeLists.txt
+++ b/llvm/tools/lto/CMakeLists.txt
@@ -45,6 +45,15 @@ if(LLVM_ENABLE_PIC)
if(LLVM_LTO_VERSION_OFFSET)
math(EXPR LTO_VERSION "${LLVM_VERSION_MAJOR} + ${LLVM_LTO_VERSION_OFFSET}")
endif()
+ 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})
+ if(LLVM_UNVERSIONED_LIBLTO_ON_DARWIN)
+ set_property(TARGET LTO PROPERTY SOVERSION)
+ set_property(TARGET LTO PROPERTY VERSION)
+ endif()
+ endif()
llvm_set_macho_current_version(LTO ${LTO_VERSION})
if(LLVM_USE_SANITIZER)
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=lib
More information about the llvm-commits
mailing list