From 98dda3860b08872fb6827cafff2c23919662019c Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Thu, 4 Sep 2025 15:22:30 -0400 Subject: [PATCH 1/5] Initial refactor to un-pollute $APP/usr/lib --- cmake/linux/LinuxDeploy.cmake | 63 ++--------------------- cmake/linux/apprun-hooks/usr-lib-hooks.sh | 7 +-- 2 files changed, 6 insertions(+), 64 deletions(-) diff --git a/cmake/linux/LinuxDeploy.cmake b/cmake/linux/LinuxDeploy.cmake index f2530a10f24..7b1c6d179eb 100644 --- a/cmake/linux/LinuxDeploy.cmake +++ b/cmake/linux/LinuxDeploy.cmake @@ -89,7 +89,7 @@ endforeach() # Copy Suil modules if(CPACK_SUIL_MODULES) - set(SUIL_MODULES_TARGET "${APP}/usr/lib/${CPACK_SUIL_MODULES_PREFIX}") + set(SUIL_MODULES_TARGET "${APP}/usr/lib/suil-0") file(MAKE_DIRECTORY "${SUIL_MODULES_TARGET}") file(COPY ${CPACK_SUIL_MODULES} DESTINATION "${SUIL_MODULES_TARGET}") endif() @@ -125,47 +125,19 @@ file(COPY "${APP}/usr/share/icons/hicolor/256x256/apps/${lmms}.png" DESTINATION file(RENAME "${APP}/${lmms}.png" "${APP}/.DirIcon") file(COPY "${APP}/usr/share/icons/hicolor/256x256/apps/${lmms}.png" DESTINATION "${APP}") -# Build list of libraries to inform linuxdeploy about -# e.g. --library=foo.so --library=bar.so -file(GLOB LIBS "${APP}/usr/lib/${lmms}/*.so") - -# Inform linuxdeploy about LADSPA plugins; may depend on bundled fftw3f, etc. -file(GLOB LADSPA "${APP}/usr/lib/${lmms}/ladspa/*.so") - -# Inform linuxdeploy about remote plugins -file(GLOB REMOTE_PLUGINS "${APP}/usr/lib/${lmms}/*Remote*") - # Inform linuxdeploy-plugin-qt about wayland plugin set(ENV{EXTRA_PLATFORM_PLUGINS} "libqwayland-generic.so") set(ENV{EXTRA_QT_MODULES} "waylandcompositor") -# Collect, sort and dedupe all libraries -list(APPEND LIBS ${LADSPA}) -list(APPEND LIBS ${REMOTE_PLUGINS}) -list(APPEND LIBS ${CPACK_SUIL_MODULES}) -list(REMOVE_DUPLICATES LIBS) -list(SORT LIBS) - -# Handle non-relinkable files (e.g. RemoveVstPlugin[32|64], but not NativeLinuxRemoteVstPlugin) -list(FILTER LIBS EXCLUDE REGEX "\\/RemoteVst") - -# Construct linuxdeploy parameters -foreach(_lib IN LISTS LIBS) - if(EXISTS "${_lib}") - list(APPEND LIBRARIES "--library=${_lib}") - endif() -endforeach() - -list(APPEND SKIP_LIBRARIES "--exclude-library=*libgallium*") - # Call linuxdeploy message(STATUS "Calling ${LINUXDEPLOY_BIN} --appdir \"${APP}\" ... [... libraries].") execute_process(COMMAND "${LINUXDEPLOY_BIN}" --appdir "${APP}" --desktop-file "${DESKTOP_FILE}" --plugin qt - ${LIBRARIES} - ${SKIP_LIBRARIES} + --deploy-deps-only "${APP}/usr/lib/${lmms}/" + --deploy-deps-only "${APP}/usr/lib/${lmms}/ladspa/" + --exclude-library "*libgallium*" --verbosity ${VERBOSITY} WORKING_DIRECTORY "${CPACK_CURRENT_BINARY_DIR}" ${OUTPUT_QUIET} @@ -189,33 +161,6 @@ foreach(_lib IN LISTS EXCLUDE_LIBS) endif() endforeach() -# FIXME: Remove when linuxdeploy supports subfolders https://github.com/linuxdeploy/linuxdeploy/issues/305 -foreach(_lib IN LISTS LIBS) - if(EXISTS "${_lib}") - file(REMOVE "${_lib}") - endif() -endforeach() -# Move RemotePlugins into to LMMS_PLUGIN_DIR -file(GLOB WINE_VST_LIBS - "${APP}/usr/lib/${lmms}/RemoteVstPlugin*" - "${APP}/usr/lib/${lmms}/32") -foreach(_file IN LISTS WINE_VST_LIBS) - if(EXISTS "${_file}") - get_filename_component(_name "${_file}" NAME) - file(RENAME "${_file}" "${APP}/usr/lib/${_name}") - endif() -endforeach() -file(GLOB WINE_32_LIBS - "${APP}/usr/lib/${lmms}/RemoteVstPlugin*") -foreach(_lib IN LISTS WINE_64_LIBS) - if(EXISTS "${_lib}") - get_filename_component(_file "${_lib}" NAME) - file(RENAME "${_lib}" "${APP}/usr/lib/${_file}") - endif() -endforeach() - -file(REMOVE_RECURSE "${SUIL_MODULES_TARGET}" "${APP}/usr/lib/${lmms}/ladspa/") - # Copy "exclude-list" lib(s) into specified location macro(copy_excluded ldd_target name_match destination relocated_lib) execute_process(COMMAND ldd diff --git a/cmake/linux/apprun-hooks/usr-lib-hooks.sh b/cmake/linux/apprun-hooks/usr-lib-hooks.sh index d33b8a22db7..97f62d7502a 100644 --- a/cmake/linux/apprun-hooks/usr-lib-hooks.sh +++ b/cmake/linux/apprun-hooks/usr-lib-hooks.sh @@ -1,8 +1,5 @@ #!/usr/bin/env bash -# Workaround libraries being incorrectly placed in usr/lib (e.g. instead of usr/lib/lmms, etc) -# FIXME: Remove when linuxdeploy supports subfolders https://github.com/linuxdeploy/linuxdeploy/issues/305 +# Paths for plugin systems to pick-up DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" -export LMMS_PLUGIN_DIR="$DIR/usr/lib/" -export LADSPA_PATH="$DIR/usr/lib/" -export SUIL_MODULE_DIR="$DIR/usr/lib/" +export SUIL_MODULE_DIR="$DIR/usr/lib/suil-0/" # See also ${SUIL_MODULES_TARGET} From 83960507689f71170e11b5ea8148ee70d7cc10c0 Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Thu, 4 Sep 2025 16:38:30 -0400 Subject: [PATCH 2/5] Add usr/lib/suil-0 and usr/lib/lmms/32 to --deploy-deps-only flags --- cmake/linux/LinuxDeploy.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/linux/LinuxDeploy.cmake b/cmake/linux/LinuxDeploy.cmake index 7b1c6d179eb..305c0879362 100644 --- a/cmake/linux/LinuxDeploy.cmake +++ b/cmake/linux/LinuxDeploy.cmake @@ -136,6 +136,8 @@ execute_process(COMMAND "${LINUXDEPLOY_BIN}" --desktop-file "${DESKTOP_FILE}" --plugin qt --deploy-deps-only "${APP}/usr/lib/${lmms}/" + --deploy-deps-only "${APP}/usr/lib/${lmms}/32/" + --deploy-deps-only "${APP}/usr/lib/suil-0/" --deploy-deps-only "${APP}/usr/lib/${lmms}/ladspa/" --exclude-library "*libgallium*" --verbosity ${VERBOSITY} @@ -201,7 +203,7 @@ endmacro() copy_excluded("${APP}/usr/bin/${lmms}" "libjack.so" "${APP}/usr/lib/jack" relocated_jack) if(relocated_jack) # libdb's not excluded however we'll re-use the macro as a convenient path calculation - # See https://github.com/LMMS/lmms/issues/7689s + # See https://github.com/LMMS/lmms/issues/7689 copy_excluded("${relocated_jack}" "libdb-" "${APP}/usr/lib/jack" relocated_libdb) get_filename_component(libdb_name "${relocated_libdb}" NAME) if(relocated_libdb AND EXISTS "${APP}/usr/lib/${libdb_name}") From 2d93cf87430777818e823fc971121af9275a20d2 Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Fri, 5 Sep 2025 12:51:07 -0400 Subject: [PATCH 3/5] Conditionalize --deploy-deps-only; simplify libjack handling --- cmake/linux/LinuxDeploy.cmake | 76 +++++++++--------------------- cmake/modules/CopyDependency.cmake | 76 ++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 55 deletions(-) create mode 100644 cmake/modules/CopyDependency.cmake diff --git a/cmake/linux/LinuxDeploy.cmake b/cmake/linux/LinuxDeploy.cmake index 305c0879362..dd961d535c4 100644 --- a/cmake/linux/LinuxDeploy.cmake +++ b/cmake/linux/LinuxDeploy.cmake @@ -49,6 +49,7 @@ endif() include(DownloadBinary) include(CreateSymlink) +include(CopyDependency) # Cleanup CPack "External" json, txt files, old AppImage files file(GLOB cleanup "${CPACK_BINARY_DIR}/${lmms}-*.json" @@ -87,11 +88,29 @@ foreach(_file ${files}) endif() endforeach() +# Gather deps +list(APPEND DEPLOY_DEPS + --deploy-deps-only "${APP}/usr/lib/${lmms}/" + --deploy-deps-only "${APP}/usr/lib/${lmms}/ladspa/" +) + +# If usr/bin/lmms is hard-linked to libjack, copy it to a new location +# See https://github.com/LMMS/lmms/issues/7689 +copy_dependency("${APP}/usr/bin/lmms" "libjack.so" "${APP}/usr/lib/jack" JACK_LIB_RELOC) +if(JACK_LIB_RELOC) + list(APPEND DEPLOY_DEPS --deploy-deps-only "${JACK_LIB_RELOC}") +endif() + +if(CPACK_HAVE_VST_32) + list(APPEND DEPLOY_DEPS --deploy-deps-only "${APP}/usr/lib/${lmms}/32/") +endif() + # Copy Suil modules if(CPACK_SUIL_MODULES) - set(SUIL_MODULES_TARGET "${APP}/usr/lib/suil-0") + set(SUIL_MODULES_TARGET "${APP}/usr/lib/suil-0/") file(MAKE_DIRECTORY "${SUIL_MODULES_TARGET}") file(COPY ${CPACK_SUIL_MODULES} DESTINATION "${SUIL_MODULES_TARGET}") + list(APPEND DEPLOY_DEPS --deploy-deps-only "${APP}/usr/lib/suil-0/") endif() # Copy stk/rawwaves @@ -135,10 +154,7 @@ execute_process(COMMAND "${LINUXDEPLOY_BIN}" --appdir "${APP}" --desktop-file "${DESKTOP_FILE}" --plugin qt - --deploy-deps-only "${APP}/usr/lib/${lmms}/" - --deploy-deps-only "${APP}/usr/lib/${lmms}/32/" - --deploy-deps-only "${APP}/usr/lib/suil-0/" - --deploy-deps-only "${APP}/usr/lib/${lmms}/ladspa/" + ${DEPLOY_DEPS} --exclude-library "*libgallium*" --verbosity ${VERBOSITY} WORKING_DIRECTORY "${CPACK_CURRENT_BINARY_DIR}" @@ -163,56 +179,6 @@ foreach(_lib IN LISTS EXCLUDE_LIBS) endif() endforeach() -# Copy "exclude-list" lib(s) into specified location -macro(copy_excluded ldd_target name_match destination relocated_lib) - execute_process(COMMAND ldd - "${ldd_target}" - OUTPUT_VARIABLE ldd_output - OUTPUT_STRIP_TRAILING_WHITESPACE - COMMAND_ECHO ${COMMAND_ECHO} - COMMAND_ERROR_IS_FATAL ANY) - - # escape periods to avoid double-escaping - string(REPLACE "." "\\." name_match "${name_match}") - - # cli output --> list - string(REPLACE "\n" ";" ldd_list "${ldd_output}") - - foreach(line ${ldd_list}) - if(line MATCHES "${name_match}") - # Assumes format "libname.so.0 => /lib/location/libname.so.0 (0x00007f48d0b0e000)" - string(REPLACE " " ";" parts "${line}") - list(LENGTH parts len) - math(EXPR index "${len}-2") - list(GET parts ${index} lib) - # Resolve any possible symlinks - file(REAL_PATH "${lib}" libreal) - get_filename_component(symname "${lib}" NAME) - get_filename_component(realname "${libreal}" NAME) - file(MAKE_DIRECTORY "${destination}") - # Copy, but with original symlink name - file(COPY "${libreal}" DESTINATION "${destination}") - file(RENAME "${destination}/${realname}" "${destination}/${symname}") - set("${relocated_lib}" "${destination}/${symname}") - break() - endif() - endforeach() -endmacro() - -# copy libjack -copy_excluded("${APP}/usr/bin/${lmms}" "libjack.so" "${APP}/usr/lib/jack" relocated_jack) -if(relocated_jack) - # libdb's not excluded however we'll re-use the macro as a convenient path calculation - # See https://github.com/LMMS/lmms/issues/7689 - copy_excluded("${relocated_jack}" "libdb-" "${APP}/usr/lib/jack" relocated_libdb) - get_filename_component(libdb_name "${relocated_libdb}" NAME) - if(relocated_libdb AND EXISTS "${APP}/usr/lib/${libdb_name}") - # assume a copy already resides in usr/lib and symlink - file(REMOVE "${relocated_libdb}") - create_symlink("${APP}/usr/lib/${libdb_name}" "${relocated_libdb}") - endif() -endif() - # cleanup empty directories file(REMOVE_RECURSE "${APP}/usr/lib/${lmms}/optional/") diff --git a/cmake/modules/CopyDependency.cmake b/cmake/modules/CopyDependency.cmake new file mode 100644 index 00000000000..24f1118ae4c --- /dev/null +++ b/cmake/modules/CopyDependency.cmake @@ -0,0 +1,76 @@ +# Copy source_lib's dependency matching 'name_match' into specified location +# Sets variable named in relocated_lib to the destination +macro(copy_dependency source_lib name_match destination relocated_lib) + if(NOT COMMAND_ECHO OR "${COMMAND_ECHO}" STREQUAL "NONE") + set(_command_echo NONE) + else() + set(_command_echo "${COMMAND_ECHO}") + endif() + + execute_process(COMMAND file -b --mime-type ${source_lib} OUTPUT_VARIABLE file_type) + + set(_is_linux_lib false) + set(_is_mac_lib false) + + if("${file_type}" MATCHES "application/x-pie-executable") + # Linux ELF binary + set(_is_linux_lib true) + list(APPEND _lib_command ldd) + elseif("${file_type}" MATCHES "application/x-mach-binary") + # macOS Mach-O binary + set(_is_mac_lib true) + list(APPEND _lib_command otool -L) + else() + message(FATAL_ERROR "Copying dependencies for ${file_type} are not yet supported") + endif() + + execute_process(COMMAND ${_lib_command} + "${source_lib}" + OUTPUT_VARIABLE raw_output + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ECHO ${_command_echo} + COMMAND_ERROR_IS_FATAL ANY) + + # escape periods to avoid double-escaping + string(REPLACE "." "\\." name_match "${name_match}") + + # cli output --> list + string(REPLACE "\n" ";" raw_list "${raw_output}") + + foreach(line ${raw_list}) + if(line MATCHES "${name_match}") + if(_is_linux_lib) + # Assumes format "libname.so.0 => /lib/location/libname.so.0 (0x00007f48d0b0e000)" + string(REGEX MATCH "=> ([^\\(]+)" dummy_var "${line}") + # Trim leading/trailing whitespace and add to our list + string(STRIP "${CMAKE_MATCH_1}" lib) + elseif(_is_mac_lib) + # Assumes format "@loader_path/../Frameworks/libname-0.0.dylib (compatibility version 0.0.0, current version 0.24.26)" + string(REGEX MATCH "^[ \t]+(.*) \\(" dummy_var "${line}") + string(STRIP "${CMAKE_MATCH_1}" lib) + get_filename_component(loader_path ${source_lib} DIRECTORY) + string(REPLACE "@loader_path" "${loader_path}" resolved_lib "${lib}") + string(REPLACE "@rpath" "${loader_path}" resolved_lib "${lib}") + # Special handling for '@executable_path' + if(line MATCHES "@executable_path") + # Find the position of '/Contents/' + string(FIND "${APP_PATH}" "/Contents/" APP_CONTENTS_POS) + # Extract the base path up to '/Contents/' + string(SUBSTRING "${loader_path}" 0 "${APP_CONTENTS_POS}" app_base_path) + string(REPLACE "@executable_path" "${app_base_path}/Contents/MacOS" resolved_lib "${lib}") + endif() + endif() + + # Resolve any possible symlinks + file(REAL_PATH "${lib}" libreal) + get_filename_component(symname "${lib}" NAME) + get_filename_component(realname "${libreal}" NAME) + file(MAKE_DIRECTORY "${destination}") + # Copy, but with original symlink name + file(COPY "${libreal}" DESTINATION "${destination}") + file(RENAME "${destination}/${realname}" "${destination}/${symname}") + set("${relocated_lib}" "${destination}/${symname}") + break() + endif() + endforeach() +endmacro() \ No newline at end of file From cf9315f2ae3554d8c650f93200556b7b7eb31ebb Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Fri, 5 Sep 2025 14:31:54 -0400 Subject: [PATCH 4/5] Minor formatting --- cmake/modules/CopyDependency.cmake | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/modules/CopyDependency.cmake b/cmake/modules/CopyDependency.cmake index 24f1118ae4c..c356bd68da7 100644 --- a/cmake/modules/CopyDependency.cmake +++ b/cmake/modules/CopyDependency.cmake @@ -7,7 +7,7 @@ macro(copy_dependency source_lib name_match destination relocated_lib) set(_command_echo "${COMMAND_ECHO}") endif() - execute_process(COMMAND file -b --mime-type ${source_lib} OUTPUT_VARIABLE file_type) + execute_process(COMMAND file -b --mime-type "${source_lib}" OUTPUT_VARIABLE file_type) set(_is_linux_lib false) set(_is_mac_lib false) @@ -25,11 +25,11 @@ macro(copy_dependency source_lib name_match destination relocated_lib) endif() execute_process(COMMAND ${_lib_command} - "${source_lib}" - OUTPUT_VARIABLE raw_output - OUTPUT_STRIP_TRAILING_WHITESPACE - COMMAND_ECHO ${_command_echo} - COMMAND_ERROR_IS_FATAL ANY) + "${source_lib}" + OUTPUT_VARIABLE raw_output + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ECHO ${_command_echo} + COMMAND_ERROR_IS_FATAL ANY) # escape periods to avoid double-escaping string(REPLACE "." "\\." name_match "${name_match}") From 2ffabfec031d4077a9b16f09ddaaf812781e545f Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Wed, 10 Sep 2025 09:58:38 -0400 Subject: [PATCH 5/5] Remove outdated LMMS_EXCLUDE_LADSPA entry (carla no longer shares a parent folder with LADSPA plugins) This reverts commit 8b160c4e7a2444ff428f423f0ca51db1c8eb992e. --- cmake/linux/apprun-hooks/carla-hook.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/linux/apprun-hooks/carla-hook.sh b/cmake/linux/apprun-hooks/carla-hook.sh index 8cbe43d0230..6f082d140dc 100644 --- a/cmake/linux/apprun-hooks/carla-hook.sh +++ b/cmake/linux/apprun-hooks/carla-hook.sh @@ -25,7 +25,6 @@ if command -v carla > /dev/null 2>&1; then else echo "[$ME] Carla does not appear to be installed, we'll remove it from the plugin listing." >&2 export "LMMS_EXCLUDE_PLUGINS=libcarla,${LMMS_EXCLUDE_PLUGINS}" - export "LMMS_EXCLUDE_LADSPA=libcarla,${LMMS_EXCLUDE_LADSPA}" fi # Additional workarounds for library conflicts