def internalCreatePackage(self, defines, seperateSymbolFiles=False, packageSymbols=False): """ create a package """ CraftCore.log.debug("packaging using the MacDMGPackager") # TODO: provide an image with dbg files if not super().internalCreatePackage( defines, seperateSymbolFiles=seperateSymbolFiles, packageSymbols=packageSymbols): return False appPath = self.getMacAppPath(defines) if not appPath: return False archive = Path(self.archiveDir()) CraftCore.log.info(f"Packaging {appPath}") CraftCore.log.info("Clean up frameworks") for framework in utils.filterDirectoryContent( archive / "lib", handleAppBundleAsFile=True, whitelist=lambda x, root: x.name.endswith(".framework"), blacklist=lambda x, root: True): rubbish = [] framework = Path(framework) rubbish += glob.glob(str(framework / "*.prl")) rubbish += glob.glob(str(framework / "Headers")) for r in rubbish: r = Path(r) if r.is_symlink(): if framework not in r.parents: raise Exception(f"Evil symlink detected: {r}") utils.deleteFile(r) r = r.resolve() if r.is_dir(): utils.rmtree(r) else: utils.deleteFile(r) targetLibdir = os.path.join(appPath, "Contents", "Frameworks") utils.createDir(targetLibdir) moveTargets = [ (archive / "lib/plugins", appPath / "Contents/PlugIns"), (archive / "plugins", appPath / "Contents/PlugIns"), (archive / "share", appPath / "Contents/Resources"), (archive / "qml", appPath / "Contents/Resources/qml"), (archive / "translations", appPath / "Contents/Resources/Translations"), (archive / "bin", appPath / "Contents/MacOS"), (archive / "libexec", appPath / "Contents/MacOS"), (archive / "lib/libexec/kf5", appPath / "Contents/MacOS"), (archive / "lib/libexec", appPath / "Contents/MacOS"), (archive / "lib", targetLibdir), ] if archive not in appPath.parents: moveTargets += [(os.path.join(archive, "bin"), os.path.join(appPath, "Contents", "MacOS"))] for src, dest in moveTargets: if os.path.exists(src): if not utils.mergeTree(src, dest): return False dylibbundler = MacDylibBundler(appPath) with utils.ScopedEnv({ 'DYLD_FALLBACK_LIBRARY_PATH': targetLibdir + ":" + os.path.join(CraftStandardDirs.craftRoot(), "lib") }): CraftCore.log.info("Bundling main binary dependencies...") mainBinary = Path(appPath, "Contents", "MacOS", defines['appname']) if not dylibbundler.bundleLibraryDependencies(mainBinary): return False binaries = list( utils.filterDirectoryContent( os.path.join(appPath, "Contents", "MacOS"), whitelist=lambda x, root: utils.isBinary( x.path) and x.name != defines["appname"], blacklist=lambda x, root: True)) for binary in binaries: CraftCore.log.info(f"Bundling dependencies for {binary}...") binaryPath = Path(binary) if not dylibbundler.bundleLibraryDependencies(binaryPath): return False # Fix up the library dependencies of files in Contents/Frameworks/ CraftCore.log.info("Bundling library dependencies...") if not dylibbundler.fixupAndBundleLibsRecursively( "Contents/Frameworks"): return False CraftCore.log.info("Bundling plugin dependencies...") if not dylibbundler.fixupAndBundleLibsRecursively( "Contents/PlugIns"): return False macdeployqt_multiple_executables_command = [ "macdeployqt", appPath, "-always-overwrite", "-verbose=1" ] for binary in binaries: macdeployqt_multiple_executables_command.append( f"-executable={binary}") if "qmldirs" in self.defines.keys() and isinstance( self.defines["qmldirs"], list): for qmldir in self.defines["qmldirs"]: macdeployqt_multiple_executables_command.append( f"-qmldir={qmldir}") if not utils.system(macdeployqt_multiple_executables_command): return False # macdeployqt might just have added some explicitly blacklisted files blackList = Path(self.packageDir(), "mac_blacklist.txt") if blackList.exists(): pattern = [self.read_blacklist(str(blackList))] # use it as whitelist as we want only matches, ignore all others matches = utils.filterDirectoryContent( appPath, whitelist=lambda x, root: utils.regexFileFilter( x, root, pattern), blacklist=lambda x, root: True) for f in matches: CraftCore.log.info(f"Remove blacklisted file: {f}") utils.deleteFile(f) # macdeployqt adds some more plugins so we fix the plugins after calling macdeployqt dylibbundler.checkedLibs = set( ) # ensure we check all libs again (but # we should not need to make any changes) CraftCore.log.info( "Fixing plugin dependencies after macdeployqt...") if not dylibbundler.fixupAndBundleLibsRecursively( "Contents/PlugIns"): return False CraftCore.log.info( "Fixing library dependencies after macdeployqt...") if not dylibbundler.fixupAndBundleLibsRecursively( "Contents/Frameworks"): return False # Finally sanity check that we don't depend on absolute paths from the builder CraftCore.log.info( "Checking for absolute library paths in package...") found_bad_dylib = False # Don't exit immeditately so that we log all the bad libraries before failing: if not dylibbundler.areLibraryDepsOkay(mainBinary): found_bad_dylib = True CraftCore.log.error( "Found bad library dependency in main binary %s", mainBinary) for binary in binaries: binaryPath = Path(binary) if not dylibbundler.areLibraryDepsOkay(binaryPath): found_bad_dylib = True CraftCore.log.error( "Found bad library dependency in binary %s", binaryPath) if not dylibbundler.checkLibraryDepsRecursively( "Contents/Frameworks"): CraftCore.log.error( "Found bad library dependency in bundled libraries") found_bad_dylib = True if not dylibbundler.checkLibraryDepsRecursively( "Contents/PlugIns"): CraftCore.log.error( "Found bad library dependency in bundled plugins") found_bad_dylib = True if found_bad_dylib: CraftCore.log.error( "Cannot not create .dmg since the .app contains a bad library depenency!" ) return False return CodeSign.signMacApp(appPath)
def internalCreatePackage(self, defines, seperateSymbolFiles=False, packageSymbols=False): """ create a package """ CraftCore.log.debug("packaging using the MacDMGPackager") # TODO: provide an image with dbg files if not super().internalCreatePackage( defines, seperateSymbolFiles=seperateSymbolFiles, packageSymbols=packageSymbols): return False appPath = self.getMacAppPath(defines) if not appPath: return False archive = Path(self.archiveDir()) CraftCore.log.info(f"Packaging {appPath}") CraftCore.log.info("Clean up frameworks") for framework in utils.filterDirectoryContent( archive / "lib", handleAppBundleAsFile=True, whitelist=lambda x, root: x.name.endswith(".framework"), blacklist=lambda x, root: True): rubbish = [] framework = Path(framework) rubbish += framework.rglob("*.prl") rubbish += framework.rglob("Headers") for r in rubbish: r = Path(r) if r.is_symlink(): if framework not in r.parents: raise Exception(f"Evil symlink detected: {r}") utils.deleteFile(r) r = r.resolve() if r.is_dir(): utils.rmtree(r) else: utils.deleteFile(r) targetLibdir = os.path.join(appPath, "Contents", "Frameworks") utils.createDir(targetLibdir) moveTargets = [ (archive / "lib/plugins", appPath / "Contents/PlugIns"), (archive / "plugins", appPath / "Contents/PlugIns"), (archive / "share", appPath / "Contents/Resources"), (archive / "qml", appPath / "Contents/Resources/qml"), (archive / "translations", appPath / "Contents/Resources/Translations"), (archive / "bin", appPath / "Contents/MacOS"), (archive / "libexec", appPath / "Contents/MacOS"), (archive / "lib/libexec/kf5", appPath / "Contents/MacOS"), (archive / "lib/libexec", appPath / "Contents/MacOS"), (archive / "lib", targetLibdir), ] self._addQtConf(appPath) if archive not in appPath.parents: moveTargets += [(os.path.join(archive, "bin"), os.path.join(appPath, "Contents", "MacOS"))] for src, dest in moveTargets: if os.path.exists(src): if not utils.mergeTree(src, dest): return False dylibbundler = MacDylibBundler(appPath, self.externalLibs) CraftCore.log.info("Bundling main binary dependencies...") binaries = list( utils.filterDirectoryContent( os.path.join(appPath, "Contents"), whitelist=lambda x, root: utils.isBinary(x.path), blacklist=lambda x, root: True)) for binary in binaries: CraftCore.log.info(f"Bundling dependencies for {binary}...") binaryPath = Path(binary) if not dylibbundler.bundleLibraryDependencies(binaryPath): return False # Finally sanity check that we don't depend on absolute paths from the builder CraftCore.log.info("Checking for absolute library paths in package...") found_bad_dylib = False # Don't exit immeditately so that we log all the bad libraries before failing: for binary in binaries: binaryPath = Path(binary) if not dylibbundler.areLibraryDepsOkay(binaryPath): found_bad_dylib = True CraftCore.log.error( "Found bad library dependency in binary %s", binaryPath) if found_bad_dylib: CraftCore.log.error( "Cannot not create .dmg since the .app contains a bad library depenency!" ) return False return CodeSign.signMacApp(appPath)