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>
This commit is contained in:
125
cmake/install/CMakeLists.txt
Normal file
125
cmake/install/CMakeLists.txt
Normal file
@@ -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
cmake/install/excludelist-win
Normal file
23
cmake/install/excludelist-win
Normal file
@@ -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
|
||||
@@ -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")
|
||||
@@ -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
cmake/modules/InstallDependencies.cmake
Normal file
184
cmake/modules/InstallDependencies.cmake
Normal file
@@ -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()
|
||||
@@ -1,4 +0,0 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user