[clang] [llvm] [libclang][Cygwin] Provide unversioned DLL file alongside versioned one (PR #147132)
Tomohiro Kashiwada via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 11 07:48:42 PDT 2025
https://github.com/kikairoya updated https://github.com/llvm/llvm-project/pull/147132
>From 9198e98e6dd7a02c5c5b65e400d788b6bac3a3c3 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 28 Jun 2025 13:11:42 +0900
Subject: [PATCH 1/6] [libclang][Cygwin] Put unversioned DLL file aside of
versioned DLL file
On Cygwin, a shared library target generates a versioned DLL file like
"cyg${OUTPUT_NAME}-${VERSION}.dll" and an import library
"lib${OUTPUT_NAME}.dll.a", but it does *not* generate the expected
unversioned symlink "cyg${OUTPUT_NAME}.dll" as is typical on other Unix-like platforms.
However, `dlopen()` calls typically use the unversioned form (e.g. "cygclang.dll"),
and this is consistent with usage on other platforms. In particular, `clang-python`
relies on this behavior. Although the Cygwin runtime can resolve other forms like
"libclang.so" or "libclang.dll", a symlink alone won't suffice here, as `dlopen()`
ultimately calls `LoadLibraryExW`, which does not follow Cygwin-style symlinks.
Therefore, this patch installs an unversioned copy of the DLL without the version
suffix to improve compatibility with `dlopen()` and tools like `clang-python`.
---
clang/tools/libclang/CMakeLists.txt | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt
index ac7a9a8db37c0..9c5ca26aab099 100644
--- a/clang/tools/libclang/CMakeLists.txt
+++ b/clang/tools/libclang/CMakeLists.txt
@@ -157,15 +157,28 @@ if(ENABLE_STATIC)
endif()
if(ENABLE_SHARED)
- if(WIN32)
+ if(WIN32 OR CYGWIN)
set_target_properties(libclang
PROPERTIES
VERSION ${LIBCLANG_LIBRARY_VERSION}
DEFINE_SYMBOL _CINDEX_LIB_)
- # Avoid declaring clang c++ symbols that are statically linked into libclang as dllimport'ed.
- # If llvm/libclang-cpp dll is also being built for windows clang c++ symbols will still be
- # implicitly be exported from libclang.
- target_compile_definitions(libclang PRIVATE CLANG_BUILD_STATIC)
+ if (CYGWIN)
+ # On Cygwin environment, a library target generates "cyg${OUTPUT_NAME}-${VERSION}.dll" and "lib${OUTPUT_NAME}.dll.a" but
+ # don't provide link "cyg${OUTPUT_NAME}.dll" differs from expected as other Unix platforms.
+ # Although, to dlopen(), usually "cyg${OUTPUT_NAME}.dll" will be passed (or "lib${OUTPUT_NAME}.dll" and "lib${OUTPUT_NAME}.so"
+ # are also viable as Cygwin runtime replaces those prefix and suffix), which is same manner to other Unix platforms,
+ # and clang-python does so.
+ # Thus, put a copy of dll named without version suffix to convinience to use of dlopen(). A symbolic link can't be
+ # viable here as the path passed to dlopen() will be passed directly to LoadLibraryExW, so it must be a real file.
+ set(UNPAINTED_TARGET_NAME "$<TARGET_FILE_DIR:libclang>/$<TARGET_FILE_PREFIX:libclang>clang$<TARGET_FILE_SUFFIX:libclang>")
+ add_custom_command(TARGET libclang POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:libclang>" "${UNPAINTED_TARGET_NAME}")
+ install(FILES "${UNPAINTED_TARGET_NAME}" DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT libclang)
+ endif()
+ # Avoid declaring clang c++ symbols that are statically linked into libclang as dllimport'ed.
+ # If llvm/libclang-cpp dll is also being built for windows clang c++ symbols will still be
+ # 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}")
>From 64e727aa96fbe69b0d637e243895fcd43dbf8701 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 5 Jul 2025 22:01:59 +0900
Subject: [PATCH 2/6] rewrite comment
---
clang/tools/libclang/CMakeLists.txt | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt
index 9c5ca26aab099..d3214104e6e0d 100644
--- a/clang/tools/libclang/CMakeLists.txt
+++ b/clang/tools/libclang/CMakeLists.txt
@@ -163,13 +163,15 @@ if(ENABLE_SHARED)
VERSION ${LIBCLANG_LIBRARY_VERSION}
DEFINE_SYMBOL _CINDEX_LIB_)
if (CYGWIN)
- # On Cygwin environment, a library target generates "cyg${OUTPUT_NAME}-${VERSION}.dll" and "lib${OUTPUT_NAME}.dll.a" but
- # don't provide link "cyg${OUTPUT_NAME}.dll" differs from expected as other Unix platforms.
- # Although, to dlopen(), usually "cyg${OUTPUT_NAME}.dll" will be passed (or "lib${OUTPUT_NAME}.dll" and "lib${OUTPUT_NAME}.so"
- # are also viable as Cygwin runtime replaces those prefix and suffix), which is same manner to other Unix platforms,
- # and clang-python does so.
- # Thus, put a copy of dll named without version suffix to convinience to use of dlopen(). A symbolic link can't be
- # viable here as the path passed to dlopen() will be passed directly to LoadLibraryExW, so it must be a real file.
+ # On Cygwin, a shared library target generates "cyg${OUTPUT_NAME}-${VERSION}.dll"
+ # and "lib${OUTPUT_NAME}.dll.a", but does not generate an unversioned symlink
+ # "cyg${OUTPUT_NAME}.dll" as is common on other Unix platforms.
+ # However, tools like clang-python or direct dlopen() calls usually expect the
+ # unversioned form (e.g. "cygclang.dll"). While Cygwin can resolve some alternate
+ # names (e.g. "libclang.so", "libclang.dll"), LoadLibraryExW used under the hood
+ # doesn't follow Cygwin-style symlinks, so a real file is required.
+ # This copies the versioned DLL to an unversioned name to improve compatibility
+ # with such tools.
set(UNPAINTED_TARGET_NAME "$<TARGET_FILE_DIR:libclang>/$<TARGET_FILE_PREFIX:libclang>clang$<TARGET_FILE_SUFFIX:libclang>")
add_custom_command(TARGET libclang POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:libclang>" "${UNPAINTED_TARGET_NAME}")
>From 15003b15c9b14326736df46abecfdd7704c7920f Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Mon, 7 Jul 2025 07:11:10 +0900
Subject: [PATCH 3/6] use a symlink, don't copy
---
clang/tools/libclang/CMakeLists.txt | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt
index d3214104e6e0d..49c56aa701d73 100644
--- a/clang/tools/libclang/CMakeLists.txt
+++ b/clang/tools/libclang/CMakeLists.txt
@@ -167,14 +167,12 @@ if(ENABLE_SHARED)
# and "lib${OUTPUT_NAME}.dll.a", but does not generate an unversioned symlink
# "cyg${OUTPUT_NAME}.dll" as is common on other Unix platforms.
# However, tools like clang-python or direct dlopen() calls usually expect the
- # unversioned form (e.g. "cygclang.dll"). While Cygwin can resolve some alternate
- # names (e.g. "libclang.so", "libclang.dll"), LoadLibraryExW used under the hood
- # doesn't follow Cygwin-style symlinks, so a real file is required.
- # This copies the versioned DLL to an unversioned name to improve compatibility
- # with such tools.
+ # unversioned form (e.g. "cygclang.dll").
+ # Therefore, we create a symlink named without the version suffix to
+ # improve compatibility.
set(UNPAINTED_TARGET_NAME "$<TARGET_FILE_DIR:libclang>/$<TARGET_FILE_PREFIX:libclang>clang$<TARGET_FILE_SUFFIX:libclang>")
add_custom_command(TARGET libclang POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:libclang>" "${UNPAINTED_TARGET_NAME}")
+ COMMAND ${CMAKE_COMMAND} -E create_symlink "$<TARGET_FILE:libclang>" "${UNPAINTED_TARGET_NAME}")
install(FILES "${UNPAINTED_TARGET_NAME}" DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT libclang)
endif()
# Avoid declaring clang c++ symbols that are statically linked into libclang as dllimport'ed.
>From f28f49f21b715525b549e3505b17510714d19424 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Mon, 7 Jul 2025 19:05:49 +0900
Subject: [PATCH 4/6] link to relative path
---
clang/tools/libclang/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt
index 49c56aa701d73..5b544985faa52 100644
--- a/clang/tools/libclang/CMakeLists.txt
+++ b/clang/tools/libclang/CMakeLists.txt
@@ -172,7 +172,7 @@ if(ENABLE_SHARED)
# improve compatibility.
set(UNPAINTED_TARGET_NAME "$<TARGET_FILE_DIR:libclang>/$<TARGET_FILE_PREFIX:libclang>clang$<TARGET_FILE_SUFFIX:libclang>")
add_custom_command(TARGET libclang POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E create_symlink "$<TARGET_FILE:libclang>" "${UNPAINTED_TARGET_NAME}")
+ COMMAND ${CMAKE_COMMAND} -E create_symlink "$<TARGET_FILE_NAME:libclang>" "${UNPAINTED_TARGET_NAME}")
install(FILES "${UNPAINTED_TARGET_NAME}" DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT libclang)
endif()
# Avoid declaring clang c++ symbols that are statically linked into libclang as dllimport'ed.
>From a23926924d25bb7f67f1d84f3717a9a073fed201 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Fri, 11 Jul 2025 23:22:14 +0900
Subject: [PATCH 5/6] apply widely
---
clang/tools/libclang/CMakeLists.txt | 13 +++----------
llvm/cmake/modules/AddLLVM.cmake | 10 +++++++++-
llvm/tools/llvm-shlib/CMakeLists.txt | 5 ++++-
3 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt
index 5b544985faa52..01ce019e40262 100644
--- a/clang/tools/libclang/CMakeLists.txt
+++ b/clang/tools/libclang/CMakeLists.txt
@@ -163,17 +163,10 @@ if(ENABLE_SHARED)
VERSION ${LIBCLANG_LIBRARY_VERSION}
DEFINE_SYMBOL _CINDEX_LIB_)
if (CYGWIN)
- # On Cygwin, a shared library target generates "cyg${OUTPUT_NAME}-${VERSION}.dll"
- # and "lib${OUTPUT_NAME}.dll.a", but does not generate an unversioned symlink
- # "cyg${OUTPUT_NAME}.dll" as is common on other Unix platforms.
- # However, tools like clang-python or direct dlopen() calls usually expect the
- # unversioned form (e.g. "cygclang.dll").
- # Therefore, we create a symlink named without the version suffix to
- # improve compatibility.
- set(UNPAINTED_TARGET_NAME "$<TARGET_FILE_DIR:libclang>/$<TARGET_FILE_PREFIX:libclang>clang$<TARGET_FILE_SUFFIX:libclang>")
+ # cygclang.dll is needed in build-tree for testsuite of python bindings.
add_custom_command(TARGET libclang POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E create_symlink "$<TARGET_FILE_NAME:libclang>" "${UNPAINTED_TARGET_NAME}")
- install(FILES "${UNPAINTED_TARGET_NAME}" DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT libclang)
+ COMMAND ${CMAKE_COMMAND} -E create_symlink "$<TARGET_FILE_NAME:libclang>"
+ "$<TARGET_FILE_DIR:libclang>/$<TARGET_FILE_PREFIX:libclang>clang$<TARGET_FILE_SUFFIX:libclang>")
endif()
# Avoid declaring clang c++ symbols that are statically linked into libclang as dllimport'ed.
# If llvm/libclang-cpp dll is also being built for windows clang c++ symbols will still be
diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
index 83772ed8d2b13..60ec7ea178e66 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -750,12 +750,20 @@ function(llvm_add_library name)
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)
+ if(UNIX)
llvm_install_library_symlink(${api_name} ${library_name} SHARED
COMPONENT ${name})
llvm_install_library_symlink(${output_name} ${library_name} SHARED
COMPONENT ${name})
endif()
+ elseif(CYGWIN)
+ 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_MINOR}${LLVM_VERSION_SUFFIX})
+ llvm_install_library_symlink(${output_name} ${library_name} SHARED
+ COMPONENT ${name})
endif()
endif()
diff --git a/llvm/tools/llvm-shlib/CMakeLists.txt b/llvm/tools/llvm-shlib/CMakeLists.txt
index 9a2015f61f2bf..f6089c9eb1ae9 100644
--- a/llvm/tools/llvm-shlib/CMakeLists.txt
+++ b/llvm/tools/llvm-shlib/CMakeLists.txt
@@ -33,12 +33,15 @@ if(LLVM_BUILD_LLVM_DYLIB)
if (LLVM_LINK_LLVM_DYLIB)
set(INSTALL_WITH_TOOLCHAIN INSTALL_WITH_TOOLCHAIN)
endif()
- if (WIN32 OR CYGWIN)
+ if (WIN32)
add_llvm_library(LLVM SHARED DISABLE_LLVM_LINK_LLVM_DYLIB SONAME ${INSTALL_WITH_TOOLCHAIN} ${SOURCES})
else()
add_llvm_library(LLVM SHARED DISABLE_LLVM_LINK_LLVM_DYLIB OUTPUT_NAME LLVM ${INSTALL_WITH_TOOLCHAIN} ${SOURCES})
# Add symlink for backwards compatibility with old library name
llvm_install_library_symlink(LLVM-${LLVM_VERSION_MAJOR}${LLVM_VERSION_SUFFIX} $<TARGET_FILE_NAME:LLVM> SHARED FULL_DEST COMPONENT LLVM)
+ if (CYGWIN)
+ llvm_install_library_symlink(LLVM-${LLVM_VERSION_MAJOR}${LLVM_VERSION_SUFFIX} $<TARGET_FILE_NAME:LLVM> IMPORT FULL_DEST COMPONENT LLVM)
+ endif()
endif()
list(REMOVE_DUPLICATES LIB_NAMES)
>From 3fb0a800ac6d5a69f1d317e4152f8d5f36de5896 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Fri, 11 Jul 2025 23:48:28 +0900
Subject: [PATCH 6/6] fix link target
---
llvm/tools/llvm-shlib/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/tools/llvm-shlib/CMakeLists.txt b/llvm/tools/llvm-shlib/CMakeLists.txt
index f6089c9eb1ae9..521387a7d2aa5 100644
--- a/llvm/tools/llvm-shlib/CMakeLists.txt
+++ b/llvm/tools/llvm-shlib/CMakeLists.txt
@@ -40,7 +40,7 @@ if(LLVM_BUILD_LLVM_DYLIB)
# Add symlink for backwards compatibility with old library name
llvm_install_library_symlink(LLVM-${LLVM_VERSION_MAJOR}${LLVM_VERSION_SUFFIX} $<TARGET_FILE_NAME:LLVM> SHARED FULL_DEST COMPONENT LLVM)
if (CYGWIN)
- llvm_install_library_symlink(LLVM-${LLVM_VERSION_MAJOR}${LLVM_VERSION_SUFFIX} $<TARGET_FILE_NAME:LLVM> IMPORT FULL_DEST COMPONENT LLVM)
+ llvm_install_library_symlink(LLVM-${LLVM_VERSION_MAJOR}${LLVM_VERSION_SUFFIX} $<TARGET_LINKER_FILE_NAME:LLVM> IMPORT FULL_DEST COMPONENT LLVM)
endif()
endif()
More information about the llvm-commits
mailing list