From 96ec8ae9f7fb58f2756a9c54d9ab786eeb0b936b Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 2 Apr 2026 23:19:36 +0200 Subject: [PATCH] cmake: use readelf first to determine elf SONAME --- cmake/macros.cmake | 173 +++++++++++++++++++++++++++--------------- cmake/sdlchecks.cmake | 41 +++------- 2 files changed, 120 insertions(+), 94 deletions(-) diff --git a/cmake/macros.cmake b/cmake/macros.cmake index e64f0b4d39..8dcd0abd4b 100644 --- a/cmake/macros.cmake +++ b/cmake/macros.cmake @@ -101,13 +101,13 @@ function(SDL_detect_linker) endfunction() function(read_absolute_symlink DEST PATH) - file(READ_SYMLINK "${PATH}" p) - if(NOT IS_ABSOLUTE "${p}") + file(READ_SYMLINK "${PATH}" target) + if(NOT IS_ABSOLUTE "${target}") get_filename_component(pdir "${PATH}" DIRECTORY) - set(p "${pdir}/${p}") + set(target "${pdir}/${target}") endif() - get_filename_component(p "${p}" ABSOLUTE) - set("${DEST}" "${p}" PARENT_SCOPE) + get_filename_component(target "${target}" ABSOLUTE) + set("${DEST}" "${target}" PARENT_SCOPE) endfunction() function(win32_implib_identify_dll DEST IMPLIB) @@ -181,8 +181,89 @@ function(get_actual_target) set("${dst}" "${target}" PARENT_SCOPE) endfunction() +function(elf_read_soname SONAME LIBRARY) + # Parse SONAME from library using `readelf` + set(result "${SONAME}-NOTFOUND") + if(EXISTS "${LIBRARY}") + find_program(READELF_BIN NAMES readelf) + if(READELF_BIN) + execute_process(COMMAND "${READELF_BIN}" -d "${LIBRARY}" RESULTS_VARIABLE readelf_result OUTPUT_VARIABLE readelf_output) + if(readelf_result EQUAL 0 AND readelf_output) + string(REGEX MATCH "\\(SONAME\\).*\\[([0-9A-Za-z_.-]+)\\]" soname "${readelf_output}") + if(soname) + set(result "${CMAKE_MATCH_1}") + endif() + endif() + endif() + endif() + message(DEBUG "elf_read_soname(\"${LIBRARY}\") -> ${SONAME}") + set("${SONAME}" "${result}" PARENT_SCOPE) +endfunction() + +function(library_soname_from_symlink SONAME LIBRARY) + # 1. Find the target library a file might be symbolic linking to + # 2. find all other files in the same folder that symbolic link to it + # 3. sort all these files, and select the 1st item on Linux, and last on macOS + set(result "${SONAME}-NOTFOUND") + if(EXISTS "${LIBRARY}") + get_filename_component(abs_library "${LIBRARY}" ABSOLUTE) + while(IS_SYMLINK "${abs_library}") + read_absolute_symlink(abs_library "${abs_library}") + endwhile() + if(APPLE) + set(valid_shared_library_regex "\\.[0-9]+\\.dylib$") + else() + set(valid_shared_library_regex "\\.so\\.([0-9.]+)?[0-9]$") + endif() + get_filename_component(libdir "${abs_library}" DIRECTORY) + file(GLOB subfiles "${libdir}/*") + set(similar_files "${abs_library}") + foreach(subfile ${subfiles}) + if(IS_SYMLINK "${subfile}") + read_absolute_symlink(subfile_target "${subfile}") + while(IS_SYMLINK "${subfile_target}") + read_absolute_symlink(subfile_target "${subfile_target}") + endwhile() + get_filename_component(subfile_target "${subfile_target}" ABSOLUTE) + if(subfile_target STREQUAL abs_library AND subfile MATCHES "${valid_shared_library_regex}") + list(APPEND similar_files "${subfile}") + endif() + endif() + endforeach() + list(SORT similar_files) + if(APPLE) + list(REVERSE similar_files) + endif() + message(DEBUG "files that are similar to \"${abs_library}\": ${similar_files}") + list(GET similar_files 0 item) + get_filename_component(result "${item}" NAME) + endif() + message(DEBUG "library_soname_from_symlink(${LIBRARY}) -> ${result}") + set(${SONAME} "${result}" PARENT_SCOPE) +endfunction() + +function(library_soname_from_path DEST LIBRARY) + set(result "${DEST}-NOTFOUND") + if(WIN32) + win32_implib_identify_dll(result "${LIBRARY}") + else() + # 1. On elf platforms, if readelf is available, parse the output of `readelf -d` and return the "(SONAME)" line + # 2. Else: + # 1. Find the target library a file might be symbolic linking to + # 2. find all other files in the same folder that symbolic link to it + # 3. sort all these files, and select the 1st item on Linux, and last on macOS + if(UNIX AND NOT APPLE) + elf_read_soname(result "${LIBRARY}") + endif() + if(NOT result) + library_soname_from_symlink(result "${LIBRARY}") + endif() + endif() + set("${DEST}" "${result}" PARENT_SCOPE) +endfunction() + function(target_get_dynamic_library DEST TARGET) - set(result) + set(result "${DEST}-NOTFOUND") get_actual_target(TARGET) if(WIN32) # Use the target dll of the import library @@ -200,17 +281,13 @@ function(target_get_dynamic_library DEST TARGET) endforeach() foreach(prop_to_check ${props_to_check}) - if(NOT result) - get_target_property(propvalue "${TARGET}" ${prop_to_check}) - if(propvalue AND EXISTS "${propvalue}") - win32_implib_identify_dll(result "${propvalue}" NOTFATAL) - endif() + get_target_property(propvalue "${TARGET}" ${prop_to_check}) + win32_implib_identify_dll(result "${propvalue}" NOTFATAL) + if(result) + break() endif() endforeach() else() - if(UNIX AND NOT APPLE) - find_program(READELF_BIN NAMES readelf) - endif() # 1. find the target library a file might be symbolic linking to # 2. if readelf is available, parse the output of `readelf -d` and output the "(SONAME)" line # 3. Else: @@ -223,57 +300,29 @@ function(target_get_dynamic_library DEST TARGET) foreach (config_type ${CMAKE_CONFIGURATION_TYPES} RELEASE DEBUG RELWITHDEBINFO MINSIZEREL) list(APPEND location_properties IMPORTED_LOCATION_${config_type}) endforeach() - if(APPLE) - set(valid_shared_library_regex "\\.[0-9]+\\.dylib$") - else() - set(valid_shared_library_regex "\\.so\\.([0-9.]+)?[0-9]") - endif() - foreach(location_property ${location_properties}) - if(NOT result) + if(UNIX AND NOT APPLE) + foreach(location_property ${location_properties}) get_target_property(library_path "${TARGET}" ${location_property}) - message(DEBUG "get_target_property(${TARGET} ${location_property}) -> ${library_path}") - if(EXISTS "${library_path}") - if(READELF_BIN) - execute_process(COMMAND "${READELF_BIN}" -d "${library_path}" RESULTS_VARIABLE readelf_result OUTPUT_VARIABLE readelf_output) - if(readelf_output) - string(REGEX MATCH "\\(SONAME\\).*\\[([0-9A-Za-z_.-]+)\\]" soname "${readelf_output}") - if(soname) - set(result "${CMAKE_MATCH_1}") - endif() - endif() - endif() - if(NOT result) - get_filename_component(library_path "${library_path}" ABSOLUTE) - while (IS_SYMLINK "${library_path}") - read_absolute_symlink(library_path "${library_path}") - endwhile() - message(DEBUG "${TARGET} -> ${library_path}") - get_filename_component(libdir "${library_path}" DIRECTORY) - file(GLOB subfiles "${libdir}/*") - set(similar_files "${library_path}") - foreach(subfile ${subfiles}) - if(IS_SYMLINK "${subfile}") - read_absolute_symlink(subfile_target "${subfile}") - while(IS_SYMLINK "${subfile_target}") - read_absolute_symlink(subfile_target "${subfile_target}") - endwhile() - get_filename_component(subfile_target "${subfile_target}" ABSOLUTE) - if(subfile_target STREQUAL library_path AND subfile MATCHES "${valid_shared_library_regex}") - list(APPEND similar_files "${subfile}") - endif() - endif() - endforeach() - list(SORT similar_files) - message(DEBUG "files that are similar to \"${library_path}\"=${similar_files}") - if(APPLE) - list(REVERSE similar_files) - endif() - list(GET similar_files 0 item) - get_filename_component(result "${item}" NAME) + if(library_path AND EXISTS "${library_path}") + elf_read_soname(result "${library_path}") + if(result) + break() endif() endif() - endif() - endforeach() + endforeach() + endif() + if(NOT result) + foreach(location_property ${location_properties}) + get_target_property(library_path "${TARGET}" ${location_property}) + if(library_path AND EXISTS "${library_path}") + library_soname_from_symlink(result "${library_path}") + message(DEBUG "result=${result}") + if(result) + break() + endif() + endif() + endforeach() + endif() endif() if(result) string(TOLOWER "${result}" result_lower) diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake index 055781dde3..cb45d1f557 100644 --- a/cmake/sdlchecks.cmake +++ b/cmake/sdlchecks.cmake @@ -5,7 +5,7 @@ macro(check_c_source_compiles_static SOURCE VAR) set(CMAKE_TRY_COMPILE_TARGET_TYPE "${saved_CMAKE_TRY_COMPILE_TARGET_TYPE}") endmacro() -macro(FindLibraryAndSONAME _LIB) +function(FindLibraryAndSONAME _LIB) cmake_parse_arguments(_FLAS "" "" "LIBDIRS" ${ARGN}) string(TOUPPER ${_LIB} _UPPERLNAME) @@ -15,39 +15,18 @@ macro(FindLibraryAndSONAME _LIB) # FIXME: fail FindLibraryAndSONAME when library is not shared. if(${_LNAME}_LIB MATCHES ".*\\${CMAKE_SHARED_LIBRARY_SUFFIX}.*" AND NOT ${_LNAME}_LIB MATCHES ".*\\${CMAKE_STATIC_LIBRARY_SUFFIX}.*") - set(${_LNAME}_SHARED TRUE) + set(${_LNAME}_SHARED TRUE PARENT_SCOPE) + library_soname_from_path(soname "${${_LNAME}_LIB}") else() - set(${_LNAME}_SHARED FALSE) - endif() - - if(${_LNAME}_LIB) - # reduce the library name for shared linking - - get_filename_component(_LIB_REALPATH ${${_LNAME}_LIB} REALPATH) # resolves symlinks - get_filename_component(_LIB_LIBDIR ${_LIB_REALPATH} DIRECTORY) - get_filename_component(_LIB_JUSTNAME ${_LIB_REALPATH} NAME) - - if(APPLE) - string(REGEX REPLACE "(\\.[0-9]*)\\.[0-9\\.]*dylib$" "\\1.dylib" _LIB_REGEXD "${_LIB_JUSTNAME}") - else() - string(REGEX REPLACE "(\\.[0-9]*)\\.[0-9\\.]*$" "\\1" _LIB_REGEXD "${_LIB_JUSTNAME}") - endif() - - if(NOT EXISTS "${_LIB_LIBDIR}/${_LIB_REGEXD}") - set(_LIB_REGEXD "${_LIB_JUSTNAME}") - endif() - set(${_LNAME}_LIBDIR "${_LIB_LIBDIR}") - - message(STATUS "dynamic lib${_LIB} -> ${_LIB_REGEXD}") - set(${_LNAME}_LIB_SONAME ${_LIB_REGEXD}) + set(${_LNAME}_SHARED FALSE PARENT_SCOPE) + set(soname "${_LNAME}_LIB_SONAME-NOTFOUND" PARENT_SCOPE) endif() + set(${_LNAME}_LIB_SONAME "${soname}" PARENT_SCOPE) + message(DEBUG "DYNLIB soname: ${soname}") message(DEBUG "DYNLIB OUTPUTVAR: ${_LIB} ... ${_LNAME}_LIB") - message(DEBUG "DYNLIB ORIGINAL LIB: ${_LIB} ... ${${_LNAME}_LIB}") - message(DEBUG "DYNLIB REALPATH LIB: ${_LIB} ... ${_LIB_REALPATH}") - message(DEBUG "DYNLIB JUSTNAME LIB: ${_LIB} ... ${_LIB_JUSTNAME}") - message(DEBUG "DYNLIB SONAME LIB: ${_LIB} ... ${_LIB_REGEXD}") -endmacro() + message(DEBUG "DYNLIB SONAME LIB: ${_LIB} ... $soname}") +endfunction() macro(CheckDLOPEN) check_symbol_exists(dlopen "dlfcn.h" HAVE_DLOPEN_IN_LIBC) @@ -121,8 +100,6 @@ macro(CheckALSA) endif() endif() if(NOT HAVE_ALSA_SHARED) - #FIXME: remove this line and property generate sdl3.pc - list(APPEND SDL_PC_PRIVATE_REQUIRES alsa) sdl_link_dependency(alsa LIBS ALSA::ALSA CMAKE_MODULE ALSA PKG_CONFIG_SPECS "${ALSA_PKG_CONFIG_SPEC}") endif() set(HAVE_SDL_AUDIO TRUE)