Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Rewrite CMake dependency installation
Replaces the hard-coded library paths by a method based on CMake's
GetPrerequisites module which recursively finds a binary file's linked
libraries. Advantage: Potentially works on any system without adaption as
long as CMake supports it, so it could be used to create portable Linux
packages as well. Disadvantage: "Potentially".

Co-Authored-By: Hyunjin Song <tteu.ingog@gmail.com>
  • Loading branch information
lukas-w and PhysSong committed Aug 31, 2019
commit 4fd8e08f3bd02f173e97bb721a30565f17cd1dbc
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ IF(COMMAND CMAKE_POLICY)
CMAKE_POLICY(SET CMP0050 OLD)
ENDIF()
CMAKE_POLICY(SET CMP0020 NEW)
CMAKE_POLICY(SET CMP0057 NEW)
ENDIF(COMMAND CMAKE_POLICY)

INCLUDE(CheckSubmodules)
Expand Down Expand Up @@ -565,8 +566,8 @@ ADD_SUBDIRECTORY(tests)
ADD_SUBDIRECTORY(data)
ADD_SUBDIRECTORY(doc)

# post-install tasks
ADD_SUBDIRECTORY(cmake/postinstall)
# install tasks
ADD_SUBDIRECTORY(cmake/install)

ADD_CUSTOM_COMMAND(OUTPUT "${CMAKE_BINARY_DIR}/lmms.1.gz"
COMMAND gzip -c ${CMAKE_SOURCE_DIR}/doc/lmms.1 > ${CMAKE_BINARY_DIR}/lmms.1.gz
Expand Down
125 changes: 125 additions & 0 deletions cmake/install/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@

FUNCTION(GET_COMPILER_SEARCH_DIR VAR)
SET(results "")
IF(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang|AppleClang)")
EXECUTE_PROCESS(
COMMAND ${CMAKE_CXX_COMPILER} --print-search-dirs
OUTPUT_VARIABLE out
)
STRING(REPLACE "\n" ";" out "${out}")
FOREACH(line ${out})
IF(line MATCHES "^.+:")
STRING(REPLACE " " ";" line "${line}")
LIST(GET line 1 paths)
# Remove "=" prefix
STRING(REGEX REPLACE "^=" "" paths "${paths}")
STRING(REPLACE ":" ";" paths "${paths}")
FOREACH(path ${paths})
LIST(APPEND results ${path})
ENDFOREACH()
ENDIF()
ENDFOREACH()
ENDIF()

SET(paths "")
FOREACH(result ${results})
GET_FILENAME_COMPONENT(result ${result} REALPATH)
IF(IS_DIRECTORY "${result}")
LIST(APPEND paths ${result})
ENDIF()
ENDFOREACH()
LIST(REMOVE_DUPLICATES paths)

SET(${VAR} ${paths} PARENT_SCOPE)
ENDFUNCTION()

SET(PLUGIN_FILES "")
IF(LMMS_BUILD_WIN32)
INSTALL(FILES $<TARGET_FILE:Qt5::QWindowsIntegrationPlugin> DESTINATION platforms)
ENDIF()

IF(LMMS_BUILD_WIN32 OR LMMS_INSTALL_DEPENDENCIES)
# Collect directories to search for DLLs
GET_FILENAME_COMPONENT(QTBIN_DIR "${QT_QMAKE_EXECUTABLE}" PATH)
set(LIB_DIRS "${QTBIN_DIR}")

GET_PROPERTY(PLUGINS_BUILT GLOBAL PROPERTY PLUGINS_BUILT)

foreach(target lmms ${PLUGINS_BUILT})
get_target_property(target_libs ${target} LINK_LIBRARIES)

foreach(lib ${target_libs})
if(TARGET ${lib} OR NOT IS_ABSOLUTE ${lib})
continue()
endif()

get_filename_component(lib_dir ${lib} PATH)
list(APPEND LIB_DIRS ${lib_dir})
if(lib MATCHES ".(lib|dll.a)$")
if(IS_DIRECTORY ${lib_dir}/../bin)
list(APPEND LIB_DIRS ${lib_dir}/../bin)
endif()
if(IS_DIRECTORY ${lib_dir}/bin)
list(APPEND LIB_DIRS ${lib_dir}/bin)
endif()
endif()
endforeach()
endforeach()

GET_COMPILER_SEARCH_DIR(COMPILER_SEARCH_DIRS)
LIST(APPEND LIB_DIRS ${COMPILER_SEARCH_DIRS})

LIST(REMOVE_DUPLICATES LIB_DIRS)

# Collect plugin files to inspect
FOREACH(PLUGIN ${PLUGINS_BUILT})
LIST(APPEND DEPLOY_TARGETS "$<TARGET_FILE:${PLUGIN}>")
ENDFOREACH()
# Create the list of files using file(GENERATE)
SET(DEPLOY_LIST_FILE "${CMAKE_CURRENT_BINARY_DIR}/filelist.txt")
FILE(GENERATE OUTPUT "${DEPLOY_LIST_FILE}" CONTENT "${DEPLOY_TARGETS}")

IF(LMMS_BUILD_LINUX)
FILE(DOWNLOAD "https://raw.githubusercontent.com/AppImage/AppImages/master/excludelist"
"${CMAKE_BINARY_DIR}/excludelist")
SET(additional_args INCLUDE_SYSTEM IGNORE_LIBS_FILE ${CMAKE_BINARY_DIR}/excludelist)
ELSEIF(LMMS_BUILD_WIN32)
SET(additional_args IGNORE_CASE IGNORE_LIBS_FILE ${CMAKE_CURRENT_LIST_DIR}/excludelist-win)
IF(CMAKE_CROSSCOMPILING)
SET(additional_args "${additional_args}" GP_TOOL objdump)
ENDIF()
ENDIF()

IF(LMMS_BUILD_WIN32)
SET(LMMS_DEP_DESTINATION ${BIN_DIR})
SET(PLUGIN_DEP_DESTINATION ${BIN_DIR})
ELSE()
SET(LMMS_DEP_DESTINATION ${LIB_DIR})
SET(PLUGIN_DEP_DESTINATION ${LIB_DIR})
ENDIF()

INSTALL(CODE "
INCLUDE(\"${CMAKE_SOURCE_DIR}/cmake/modules/InstallDependencies.cmake\")
# Install dependencies of lmms
INSTALL_DEPENDENCIES(
FILES ${BIN_DIR}/lmms${CMAKE_EXECUTABLE_SUFFIX}
DESTINATION ${LMMS_DEP_DESTINATION}
LIB_DIRS ${LIB_DIRS}
${additional_args}
)
# Install dependencies of plugins
FILE(READ \"${DEPLOY_LIST_FILE}\" DEPLOY_FILES)
INSTALL_DEPENDENCIES(
FILES \"\${DEPLOY_FILES}\"
DESTINATION \"${PLUGIN_DEP_DESTINATION}\"
LIB_DIRS ${LIB_DIRS} \"${BIN_DIR}\" \"${PLUGIN_DIR}\"
SEARCH_PATHS \"${BIN_DIR}\" \"${PLUGIN_DIR}\"
${additional_args}
)
")
ENDIF()

IF(LMMS_BUILD_APPLE)
INSTALL(CODE "EXECUTE_PROCESS(COMMAND chmod u+x ${CMAKE_BINARY_DIR}/install_apple.sh)")
INSTALL(CODE "EXECUTE_PROCESS(COMMAND ${CMAKE_BINARY_DIR}/install_apple.sh)")
ENDIF()
23 changes: 23 additions & 0 deletions cmake/install/excludelist-win
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# List of DLLs considered to be system libraries.
# This is needed when cross-compiling for Windows.
ADVAPI32.dll
COMCTL32.dll
comdlg32.dll
dwmapi.dll
GDI32.dll
IMM32.dll
KERNEL32.dll
MPR.DLL
msvcrt.dll
ole32.dll
OLEAUT32.dll
OPENGL32.DLL
SHELL32.dll
USER32.dll
UxTheme.dll
VERSION.dll
WINMM.DLL
WS2_32.dll
RPCRT4.dll
dsound.dll
SETUPAPI.dll
8 changes: 7 additions & 1 deletion cmake/modules/BuildPlugin.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ MACRO(BUILD_PLUGIN PLUGIN_NAME)
TARGET_LINK_LIBRARIES(${PLUGIN_NAME} lmms)
ENDIF(LMMS_BUILD_WIN32)

INSTALL(TARGETS ${PLUGIN_NAME} DESTINATION "${PLUGIN_DIR}")
INSTALL(TARGETS ${PLUGIN_NAME}
LIBRARY DESTINATION "${PLUGIN_DIR}"
RUNTIME DESTINATION "${PLUGIN_DIR}"
)

IF(LMMS_BUILD_APPLE)
IF ("${PLUGIN_LINK}" STREQUAL "SHARED")
Expand All @@ -89,5 +92,8 @@ MACRO(BUILD_PLUGIN PLUGIN_NAME)
TARGET_INCLUDE_DIRECTORIES(${PLUGIN_NAME}
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
)

SET_PROPERTY(GLOBAL APPEND PROPERTY PLUGINS_BUILT ${PLUGIN_NAME})
GET_PROPERTY(PLUGINS_BUILT GLOBAL PROPERTY PLUGINS_BUILT)
ENDMACRO(BUILD_PLUGIN)

184 changes: 184 additions & 0 deletions cmake/modules/InstallDependencies.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
include(GetPrerequisites)
include(CMakeParseArguments)

CMAKE_POLICY(SET CMP0011 NEW)
CMAKE_POLICY(SET CMP0057 NEW)

function(make_absolute var)
get_filename_component(abs "${${var}}" ABSOLUTE BASE_DIR "${CMAKE_INSTALL_PREFIX}")
set(${var} ${abs} PARENT_SCOPE)
endfunction()

# Reads lines of a file into a list, skipping '#' comment lines
function(READ_LIST_FILE FILE VAR)
file(STRINGS "${FILE}" list)

set(result "")
foreach(item ${list})
string(STRIP "${item}" item)
if(item STREQUAL "" OR item MATCHES "^\#")
continue()
endif()
list(APPEND result "${item}")
endforeach()

set(${VAR} ${result} PARENT_SCOPE)
endfunction()

function(make_all_absolute list_var)
set(result "")
foreach(file ${${list_var}})
make_absolute(file)
list(APPEND result ${file})
endforeach()
set(${list_var} ${result} PARENT_SCOPE)
endfunction()

if(CMAKE_BINARY_DIR)
set(tmp_lib_dir "${CMAKE_BINARY_DIR}/bundled-libraries")
elseif(CMAKE_HOST_UNIX)
set(tmp_lib_dir "/tmp/bundled-libraries")
elseif(DEFINED ENV{TEMP})
set(tmp_lib_dir "$ENV{TMP}/bundled-libraries")
else()
message(FATAL_ERROR "Can't find a temp dir for libraries")
endif()

# Like file(INSTALL), but resolves symlinks
function(install_file_resolved file destination)

get_filename_component(file_name "${file}" NAME)
if(IS_SYMLINK "${file}")
get_filename_component(real_path "${file}" REALPATH)
get_filename_component(real_name "${real_path}" NAME)
file(COPY "${real_path}" DESTINATION "${tmp_lib_dir}")
file(RENAME "${tmp_lib_dir}/${real_name}" "${tmp_lib_dir}/${file_name}")
set(file_path "${tmp_lib_dir}/${file_name}")
else()
set(file_path "${file}")
endif()

file(INSTALL "${file_path}" DESTINATION "${destination}")
endfunction()

function(install_resolved)
cmake_parse_arguments("" "" "DESTINATION" "FILES" ${ARGN})
foreach(file ${_FILES})
install_file_resolved("${file}" "${_DESTINATION}")
endforeach()
endfunction()

if(CMAKE_CROSSCOMPILING)
# If we're cross-compiling, GetPrerequisites may not be able to find system libraries such as kernel32.dll because
# they're supplied by the toolchain. To suppress thousands of lines of warnings being printed to the console, we
# override gp_resolved_file_type to return "system" for any library in ${IGNORE_LIBS} without trying to resolve the
# file first.
# GetPrerequisites supports using an override function called gp_resolved_file_type_override, but it's not suited
# for our purpose because it's only called by gp_resolved_file_type *after* trying to resolve the file.
function(gp_resolved_file_type original_file file exepath dirs type_var)
set(file_find "${file}")
if(_IGNORE_CASE)
# On case-insensitive systems, convert to upper characters to respect it
string(TOUPPER "${file_find}" file_find)
endif()
SET(IGNORE_LIBS ${_IGNORE_LIBS} CACHE INTERNAL "Ignored library names" FORCE)
if(IGNORE_LIBS AND ${file_find} IN_LIST IGNORE_LIBS)
set(${type_var} system PARENT_SCOPE)
else()
#_gp_resolved_file_type(${ARGV})
_gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "${dirs}" "${type_var}" ${ARGN})
endif()
endfunction()
endif()

function(INSTALL_DEPENDENCIES)
cmake_parse_arguments("" "INCLUDE_SYSTEM;IGNORE_CASE" "GP_TOOL;DESTINATION;IGNORE_LIBS_FILE" "FILES;LIB_DIRS;SEARCH_PATHS;IGNORE_LIBS" ${ARGN})

# Make paths absolute
make_absolute(_DESTINATION)
make_all_absolute(_FILES)
make_all_absolute(_LIB_DIRS)
make_all_absolute(_SEARCH_PATHS)

if(_INCLUDE_SYSTEM)
set(EXCLUDE_SYSTEM 0)
else()
set(EXCLUDE_SYSTEM 1)
endif()

if(_IGNORE_LIBS_FILE)
READ_LIST_FILE("${_IGNORE_LIBS_FILE}" _IGNORE_LIBS)
if(_IGNORE_CASE)
# On case-insensitive systems, convert to upper characters to respect it
string(TOUPPER "${_IGNORE_LIBS}" _IGNORE_LIBS)
endif()
SET(IGNORE_LIBS ${_IGNORE_LIBS} CACHE INTERNAL "Ignored library names" FORCE)
endif()

if(_GP_TOOL)
set(gp_tool "${_GP_TOOL}")
endif()

set(prereqs "")
foreach(file ${_FILES})
get_filename_component(file_name "${file}" NAME)
message("-- Finding prerequisites of ${file_name}")
find_prerequisites("${file}" _prereqs
${EXCLUDE_SYSTEM} # exclude system files
1 # recurse
""
"${_LIB_DIRS}"
"${_SEARCH_PATHS}"
"${_IGNORE_LIBS}"
)

list(APPEND prereqs ${_prereqs})
endforeach()

list(REMOVE_DUPLICATES prereqs)

foreach(prereq ${prereqs})
get_filename_component(prereq_name "${prereq}" NAME)

foreach(rpath ${_SEARCH_PATHS})
if(EXISTS "${rpath}/${prereq_name}")
list(REMOVE_ITEM prereqs "${prereq}")
break()
endif()
endforeach()
endforeach()

#file(INSTALL ${prereqs} DESTINATION ${_DESTINATION})
install_resolved(FILES ${prereqs} DESTINATION "${_DESTINATION}")
endfunction()

# Like get_prerequisites, but returns full paths
function(FIND_PREREQUISITES target RESULT_VAR exclude_system recurse
exepath dirs rpaths)
set(RESULTS)

get_prerequisites("${target}" _prereqs ${exclude_system} ${recurse}
"" "${dirs}" "${rpaths}")

foreach(prereq ${_prereqs})
get_filename_component(prereq_name "${prereq}" NAME)
if(_IGNORE_CASE)
# Windows is case insensitive.
# Use upper characters to respect it.
string(TOUPPER "${prereq_name}" prereq_name)
endif()
if("${prereq_name}" IN_LIST IGNORE_LIBS)
continue()
endif()

gp_resolve_item("${LIB_DLL}" "${prereq}" "" "${dirs}" RESOLVED_PREREQ "${rpaths}")

if(RESOLVED_PREREQ AND IS_ABSOLUTE ${RESOLVED_PREREQ} AND EXISTS ${RESOLVED_PREREQ})
list(APPEND RESULTS ${RESOLVED_PREREQ})
else()
message(FATAL_ERROR "Can't resolve dependency ${prereq}.")
endif()
endforeach()

set(${RESULT_VAR} ${RESULTS} PARENT_SCOPE)
endfunction()
4 changes: 0 additions & 4 deletions cmake/postinstall/CMakeLists.txt

This file was deleted.

2 changes: 2 additions & 0 deletions plugins/zynaddsubfx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

ADD_EXECUTABLE(RemoteZynAddSubFx RemoteZynAddSubFx.cpp "${WINRC}")
INSTALL(TARGETS RemoteZynAddSubFx RUNTIME DESTINATION "${PLUGIN_DIR}")
# Needed to deploy dependencies of RemoteZynAddSubFx
SET_PROPERTY(GLOBAL APPEND PROPERTY PLUGINS_BUILT "RemoteZynAddSubFx")

IF(LMMS_BUILD_WIN32)
SET_TARGET_PROPERTIES(RemoteZynAddSubFx PROPERTIES LINK_FLAGS "${LINK_FLAGS} -mwindows")
Expand Down
Loading