Download dependencies from CMake and fix install names

This makes it easier to deploy new versions of Qt and other deps.
This commit is contained in:
Tobias Hieta 2015-11-25 14:42:49 +01:00
parent 9fc95e77d8
commit 4b93840a32
6 changed files with 122 additions and 284 deletions

View File

@ -1,4 +1,4 @@
set(app "@EXE@")
set(app "${CMAKE_INSTALL_PREFIX}/@EXE@")
list(APPEND BINS "Contents/Resources/updater")
list(APPEND BINS "Contents/Resources/@HELPER_NAME@")
@ -10,9 +10,18 @@ foreach(BIN ${BINS})
list(APPEND args "-executable=${app}/${BIN}")
endforeach(BIN ${BINS})
set(ENV{DYLD_LIBRARY_PATH} @QTROOT@/lib:@DEPENDENCY_ROOT@/lib)
set(ENV{DYLD_FRAMEWORK_PATH} @QTROOT@/lib:@DEPENDENCY_ROOT@/lib)
set(QTCONFCONTENT "[Paths]
Prefix=@QTROOT@
")
file(WRITE @QTROOT@/bin/qt.conf ${QTCONFCONTENT})
execute_process(
COMMAND @QTROOT@/bin/macdeployqt ${args}
WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}
WORKING_DIRECTORY @QTROOT@/bin
)
#set(ENTITLEMENTS --entitlements @SOURCE_ROOT@/bundle/osx/Konvergo.entitlements)

View File

@ -1,8 +1,12 @@
find_package(PkgConfig)
option(DISABLE_BUNDLED_DEPS "Disable the bundled deps on certain platforms" OFF)
if(APPLE AND NOT DISABLE_BUNDLED_DEPS)
set(DEFAULT_ROOT "${CMAKE_SOURCE_DIR}/dependencies/konvergo-depends-darwin-x86_64-release")
include(FetchDependencies)
if(APPLE AND NOT DISABLE_BUNDLED_DEPS)
download_deps("plexmediaplayer-dependencies" dir)
message("dependencies are: ${dir}")
set(DEFAULT_ROOT ${dir})
endif(APPLE AND NOT DISABLE_BUNDLED_DEPS)
if(WIN32)

View File

@ -0,0 +1,89 @@
set(DEP_DIR ${CMAKE_BINARY_DIR}/dependencies)
if(APPLE)
set(OS "darwin")
elseif(WIN32)
set(OS "windows")
elseif(UNIX)
set(OS "linux")
endif()
# note that hardcoding the ARCH here is not correct.
set(ARCHSTR "${OS}-x86_64")
function(download_deps depname dirpath)
file(MAKE_DIRECTORY ${DEP_DIR})
message(STATUS "Downloading ${depname}.hash.txt...")
file(
DOWNLOAD "https://nightlies.plex.tv/directdl/plex-dependencies/${depname}/latest/hash.txt" ${DEP_DIR}/${depname}-hash.txt
STATUS HASH_STATUS
)
list(GET HASH_STATUS 0 SUCCESS)
if(SUCCESS EQUAL 0)
file(STRINGS ${DEP_DIR}/${depname}-hash.txt DEP_HASH LIMIT_COUNT 1)
if(depname STREQUAL plexmediaplayer-qt)
set(DEP_DIRNAME "konvergo-qt-${ARCHSTR}-release-${DEP_HASH}")
elseif(depname STREQUAL plexmediaplayer-dependencies)
set(DEP_DIRNAME "konvergo-depends-${ARCHSTR}-release-${DEP_HASH}")
else()
set(DEP_DIRNAME "${depname}-${ARCHSTR}-release-${DEP_HASH}")
endif()
set(DEP_FILENAME ${DEP_DIRNAME}.tbz2)
set(DEP_URL "https://nightlies.plex.tv/directdl/plex-dependencies/${depname}/latest/${DEP_FILENAME}")
set(${dirpath} ${DEP_DIR}/${DEP_DIRNAME} PARENT_SCOPE)
if(NOT EXISTS ${DEP_DIR}/${DEP_DIRNAME})
message(STATUS "Downloading ${DEP_FILENAME}.sha.txt...")
file(DOWNLOAD ${DEP_URL}.sha.txt ${DEP_DIR}/${DEP_FILENAME}.sha.txt STATUS SHA_STATUS)
list(GET SHA_STATUS 0 SHASUCCESS)
if(SHASUCCESS EQUAL 0)
file(STRINGS ${DEP_DIR}/${DEP_FILENAME}.sha.txt CONTENT_HASH LIMIT_COUNT 1)
message(STATUS "Downloading ${DEP_FILENAME}...")
file(
DOWNLOAD ${DEP_URL} ${DEP_DIR}/${DEP_FILENAME}
EXPECTED_HASH SHA1=${CONTENT_HASH}
SHOW_PROGRESS
STATUS DEP_STATUS
)
list(GET DEP_STATUS 0 DEP_SUCCESS)
if(NOT DEP_SUCCESS EQUAL 0)
message(FATAL_ERROR "Failed to download ${DEP_URL}")
endif()
if(NOT EXISTS ${DEP_DIR}/${DEP_DIRNAME})
message(STATUS "Unpacking ${DEP_FILENAME}...")
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xjf ${DEP_DIR}/${DEP_FILENAME}
WORKING_DIRECTORY ${DEP_DIR}
)
message(STATUS "Fixing install library names...")
execute_process(
COMMAND ${PROJECT_SOURCE_DIR}/scripts/fix-install-names.py ${DEP_DIR}/${DEP_DIRNAME}
WORKING_DIRECTORY ${DEP_DIR}
)
message(STATUS "Done")
endif()
else(SHASUCCESS EQUAL 0)
list(GET SHA_STATUS 1 SHAERROR)
message(FATAL_ERROR "Failed to download ${DEP_FILENAME}.sha.txt error: ${SHAERROR}")
endif(SHASUCCESS EQUAL 0)
else(NOT EXISTS ${DEP_DIR}/${DEP_DIRNAME})
message(STATUS "Directory ${DEP_DIR}/${DEP_DIRNAME} already exists, remove it to redownload")
endif(NOT EXISTS ${DEP_DIR}/${DEP_DIRNAME})
else(SUCCESS EQUAL 0)
list(GET HASH_STATUS 1 HASHERROR)
message(FATAL_ERROR "Failed to download ${depname}.hash.txt error: ${HASHERROR}")
endif(SUCCESS EQUAL 0)
endfunction(download_deps depname)

View File

@ -1,6 +1,15 @@
set(QTROOT "/usr/local/Qt/Qt5.5" CACHE PATH "Root of the QT binaries.")
include(FetchDependencies)
if(APPLE)
download_deps("plexmediaplayer-qt" dir)
set(QTROOT ${dir})
else()
set(QTROOT "/usr/local/Qt/Qt5.5" CACHE PATH "Root of the QT binaries.")
endif()
set(REQUIRED_QT_VERSION "5.5.0")
message(STATUS ${QTROOT})
set(QTCONFIGROOT ${QTROOT}/lib/cmake/Qt5)
set(components Core Network WebChannel Qml Quick Xml WebEngine)

View File

@ -1,278 +0,0 @@
#!/usr/bin/env python
# Sample CI usage: scripts\common\fetch-binaries.py -p windows -b release -t abc123 -n 33
# Sample desktop usage: scripts\common\fetch-binaries.py -i ..\plex-dependency-builder\output\Packages\pms-depends-windows-i386-debug-dev.bz2
import hashlib
import optparse
import ConfigParser
import os, re
import platform
import subprocess
import sys
import shutil
import urllib2
import base64
import glob
# Edit these to set a new default dependencies build
default_tag = "auto"
default_release_build_number = "107"
default_release_dir = "plexmediaplayer-dependencies"
default_branch = "master"
def sha1_for_file(path):
hash=hashlib.sha1()
fp=file(path, "rb")
while True:
data=fp.read(4096)
if not data:
break
hash.update(data)
return hash.hexdigest()
def exec_cmd(args, env={}, supress_output=False):
""" main exec_cmd function """
# forward SSH_AUTH_SOCK, so that ssh-agent works
if os.name != "nt" and "SSH_AUTH_SOCK" in os.environ:
env = os.environ
extra_env={"SSH_AUTH_SOCK":os.environ["SSH_AUTH_SOCK"]}
env.update(extra_env)
else:
env = os.environ
cmd = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, env = env)
output = ''
while True:
out = cmd.stdout.read(1)
if out == '' and cmd.poll() != None:
break
if out != '':
if not supress_output:
sys.stdout.write(out)
output += out
if cmd.wait() != 0:
raise Exception("Command failed: \"%s\"" % " ".join(args), output)
return output
platform_map={"linux-synology-i386":"synology-i686",
"linux-readynas-arm":"ubuntu-arm",
"linux-debian-4-i386":"debian-i686",
"linux-control4-arm":"control4-arm",
"linux-apm-ppc":"apm-ppc",
"linux-armada-arm7":"armada-arm7",
"linux-synology-arm":"synology-arm"}
def platform_str():
if "BUILD_TAG" in os.environ:
for (k, v) in platform_map.iteritems():
if k in os.environ["BUILD_TAG"]:
return "linux-"+v
return "linux-%s-%s"%(platform.linux_distribution()[0].strip().lower(), platform.machine())
def merge_directories(src, dest, move = False):
for src_dir, dirs, files in os.walk(src):
dst_dir = src_dir.replace(src, dest)
if not os.path.exists(dst_dir):
os.mkdir(dst_dir)
for file_ in files:
src_file = os.path.join(src_dir, file_)
dst_file = os.path.join(dst_dir, file_)
if os.path.exists(dst_file):
os.remove(dst_file)
if move:
shutil.move(src_file, dst_dir)
else:
shutil.copy(src_file, dst_dir)
if move and os.path.exists(src):
shutil.rmtree(src)
def unpack_and_install(download, inputfile, installed_filepath):
# Make paths absolute before changing directories
inputfile = os.path.abspath(inputfile)
if not os.path.exists(inputfile):
print "Input file %s does not exist" % inputfile
sys.exit(1)
shafile = "%s.sha.txt" % inputfile
installed_filepath = os.path.abspath(installed_filepath)
# Go to directory.
old_cwd = os.getcwd()
os.chdir(options.output)
# Check the SHA
if options.nochecksha:
print "-- Skipping SHA verification"
elif os.path.exists(shafile):
f = open(shafile, "r")
sha = f.readline().strip()
computed = sha1_for_file(inputfile)
if not computed == sha:
print "-- SHA didn't match: %s != %s" % (sha, computed)
sys.exit(1)
else:
print "-- SHA %s matches" % sha
f.close()
else:
print "-- ERROR - No SHA file is available to verify the file's integrity"
sys.exit(1)
# Untar the package file
inputfile_tarfriendly = inputfile
if os.name == "nt":
pattern = re.compile(r'([a-z]):\\', re.IGNORECASE)
inputfile_tarfriendly = pattern.sub('/\\1/', inputfile).replace('\\','/')
# The final destination directory is the filename without a version number
# The version number is the last element in the filename (by convention)
packagename = os.path.splitext(os.path.basename(inputfile))[0]
packagename_elements = packagename.split("-")
del packagename_elements[-1]
packagename_noversion = "-".join(packagename_elements)
if os.path.exists(packagename_noversion):
shutil.rmtree(packagename_noversion, ignore_errors=True)
os.makedirs(packagename_noversion)
print "-- Unpacking %s... to %s" % (os.path.basename(inputfile), packagename_noversion)
if os.name == "nt":
# Touch files from the package, which often arrive from the future when freshly built on our Windows build machine
exec_cmd(["tar", "xjf", inputfile_tarfriendly, "-C", packagename_noversion, "--touch", "--strip-components", "1", "--no-same-owner"])
else:
exec_cmd(["tar", "xjf", inputfile_tarfriendly, "-C", packagename_noversion, "--strip-components", "1", "--no-same-owner"])
if download and installed_filepath:
# Create the installed stamp file to note our success
open(installed_filepath, "wb")
# Restore directory.
os.chdir(old_cwd)
return packagename
if __name__=='__main__':
parser=optparse.OptionParser()
parser.add_option("-p", "--platform", action="store", type="string",
dest="platform", help="Platform identifier (e.g. windows-i386)", default=None)
parser.add_option("-b", "--buildconfig", action="store", type="string",
dest="buildconfig", help="Build configuration (release or debug). Default is release", default="release")
parser.add_option("-t", "--tag", action="store", type="string",
dest="tag", help="Build tag. Default is %s" % default_tag, default=default_tag)
parser.add_option("-n", "--buildnumber", action="store", type="string",
dest="buildnumber", help="Build number. Default is %s for release builds" % (default_release_build_number), default=None)
parser.add_option("-d", "--dir", action="store", type="string",
dest="dir", help="CI build dir. Default is %s for release builds" % (default_release_dir), default=None)
parser.add_option("-i", "--inputfile", action="store", type="string",
dest="inputfile", help="Dependencies package filename, can be supplied instead of platform, buildconfig, tag and buildnumber", default=None)
parser.add_option("-o", "--output", action="store", type="string",
dest="output", help="Output directory. Default is Dependencies",
default="Dependencies")
parser.add_option("-x", "--nochecksha", action="store_true",
dest="nochecksha", help="Don't check the SHA. Default is false",
default=False)
parser.add_option("-r", "--branch", action="store", type="string",
dest="branch", help="Git branch", default=None)
(options, args)=parser.parse_args(sys.argv)
if not os.path.exists(options.output):
os.makedirs(options.output)
# Fail early if platform is not known
download = not options.inputfile
if download and not options.platform:
print "ERROR - A platform must be specified"
sys.exit(1)
installed_filepath = None
if download:
if not options.buildnumber:
if options.buildconfig == "release":
options.buildnumber = default_release_build_number
else:
options.buildnumber = default_debug_build_number
if not options.dir:
if options.buildconfig == "release":
options.dir = default_release_dir
else:
options.dir = default_debug_dir
installed_filepath = os.path.join(options.output, "konvergo-depends-%s-%s-%s.installed" % (options.platform, options.buildconfig, options.buildnumber))
if os.path.exists(installed_filepath) and options.buildnumber != "latest":
print "The required deps bundle was already downloaded and installed."
print "You can delete %s to force a reinstall." % installed_filepath
sys.exit(0)
# Delete previous installed stamps
cont = ["-c"]
for path in glob.iglob(os.path.join(options.output, "konvergo-depends-%s-%s-*.installed") % (options.platform, options.buildconfig)):
match = re.search("-(\d+)\.installed", path, re.DOTALL)
if match:
if not match.group(1) == options.buildnumber:
cont = []
os.remove(path)
if options.tag == "auto":
req = urllib2.Request("https://nightlies.plex.tv/directdl/plex-dependencies/%s/%s/hash.txt" % (options.dir, options.buildnumber))
try:
match = urllib2.urlopen(req).read().rstrip()
except urllib2.URLError, err:
print err
print "ERROR - Download failed"
sys.exit(1)
options.tag = match
base_filename = "konvergo-depends-%s-%s-%s" % (options.platform, options.buildconfig, options.tag)
filename = "%s.tbz2" % base_filename
installed_filepath = os.path.join(options.output, "konvergo-depends-%s-%s-%s.installed" % (options.platform, options.buildconfig, options.buildnumber))
if os.path.exists(installed_filepath):
print "%s was already downloaded and installed." % filename
print "You can delete %s to force a reinstall." % installed_filepath
sys.exit(0)
url = "https://nightlies.plex.tv/directdl/plex-dependencies/%s/%s/%s" % (options.dir, options.buildnumber, filename)
inputfile = os.path.join(options.output, filename)
print "-- Downloading %s ..." % url
exec_cmd(["wget", "--no-check-certificate"] + cont + ["-O", inputfile, url])
shaurl = "%s.sha.txt" % url
shafile = "%s.sha.txt" % inputfile
print "-- Downloading %s ..." % shaurl
exec_cmd(["wget", "--no-check-certificate"] + ["-O", shafile, shaurl])
else:
inputfile = options.inputfile
# Unpack and install
packagename = unpack_and_install(download, inputfile, installed_filepath)
# On OS X, we need to postprocess the dependencies.
if platform.system() == 'Darwin':
root = os.path.realpath(os.path.join(os.getcwd()))
script = os.path.join(root, "scripts", "fix-install-names.py")
for p in ("lib", "bin", "update_installer"):
path = os.path.join(root, "Dependencies", "konvergo-depends-" + options.platform + "-" + options.buildconfig, p)
exec_cmd([script, path])
# Done!
print "-- Done with %s" % packagename

View File

@ -9,6 +9,9 @@ import subprocess
import sys
import shutil
exts = (".dylib", ".so")
exes = ("fc-cache", "macdeployqt", "qmake", "moc", "rcc", "qmlimportscanner")
def exec_cmd(args, env={}, supress_output=False):
cmd = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, env = env)
output = ''
@ -28,8 +31,8 @@ def fix_install_name(path):
for root, dirs, files in os.walk(path):
for f in files:
fpath = os.path.join(root, f)
if (f.endswith(".dylib") or f in ['fc-cache'] or f.endswith(".so")) and not os.path.islink(fpath) and os.path.exists(fpath):
if (f.endswith(exts) or os.path.basename(f) in exes or (".framework/Versions/" in root and os.access(fpath, os.X_OK))) and not os.path.islink(fpath) and os.path.exists(fpath):
# Fix permissions
if not os.access(fpath, os.W_OK) or not os.access(fpath, os.R_OK) or not os.access(fpath, os.X_OK):
os.chmod(fpath, 0o644)
@ -51,6 +54,8 @@ def fix_install_name(path):
# look for it further up, like in the root path:
if os.path.exists(os.path.join(path, "lib", current_basename)):
correct_lib = os.path.join(path, "lib", current_basename)
elif os.path.exists(os.path.join(path, "lib", current_lib)):
correct_lib = os.path.join(path, "lib", current_lib)
else:
print "Can't link %s" % current_lib
continue