Enhanced the build script to properly set the library IDs

This fix assigns proper library IDs and load paths for the dependent
libraries even if they are distributed among several directories.

This is in particular important for the stream and tool plugins
which exist in a folder next to the application but have to refer
to libraries from the Frameworks folder.

The fix consists of extending the library analysis within build4mac.py
and supplying an additional directory listing the target directories.
This commit is contained in:
Matthias Koefferlein 2018-10-02 18:57:04 -07:00
parent f7c4aa0348
commit d8b1808234
2 changed files with 64 additions and 32 deletions

View File

@ -637,6 +637,7 @@ def DeployBinariesForBundle():
os.chdir( targetDirF )
dynamicLinkLibs = glob.glob( os.path.join( AbsMacBinDir, "*.dylib" ) )
depDicOrdinary = {} # inter-library dependency dictionary
pathDic = {} # paths to insert for each library
for item in dynamicLinkLibs:
if os.path.isfile(item) and not os.path.islink(item):
#-------------------------------------------------------------------
@ -650,13 +651,54 @@ def DeployBinariesForBundle():
os.chmod( nameStyle3, 0o0755 )
#-------------------------------------------------------------------
# (B) Then get inter-library dependencies
# Note that will pull all dependencies and sort them out later
# dropping those which don't have a path entry
#-------------------------------------------------------------------
otoolCm = "otool -L %s | grep libklayout" % nameStyle3
otoolCm = "otool -L %s | grep dylib" % nameStyle3
otoolOut = os.popen( otoolCm ).read()
dependDic = DecomposeLibraryDependency(otoolOut)
depDicOrdinary.update(dependDic)
#-------------------------------------------------------------------
# (C) This library goes into Frameworks, hence record it's path there
#-------------------------------------------------------------------
pathDic[nameStyle3] = "@executable_path/../Frameworks/" + nameStyle3
os.chdir(ProjectDir)
#-------------------------------------------------------------------
# copy the contents of the plugin directories to a place next to the application
# binary
#-------------------------------------------------------------------
for piDir in [ "db_plugins", "lay_plugins" ]:
os.makedirs( os.path.join( targetDirM, piDir ), exist_ok = True )
dynamicLinkLibs = glob.glob( os.path.join( MacBinDir, piDir, "*.dylib" ) )
for item in dynamicLinkLibs:
if os.path.isfile(item) and not os.path.islink(item):
#-------------------------------------------------------------------
# (A) Copy an ordinary *.dylib file here by changing the name
# to style (3) and set its mode to 0755 (sanity check).
#-------------------------------------------------------------------
fullName = os.path.basename(item).split('.')
# e.g. [ 'libklayout_lay', '0', '25', '0', 'dylib' ]
nameStyle3 = fullName[0] + "." + fullName[1] + ".dylib"
destPath = os.path.join( targetDirM, piDir, nameStyle3 )
shutil.copy2( item, destPath )
os.chmod( destPath, 0o0755 )
#-------------------------------------------------------------------
# (B) Then get inter-library dependencies
# Note that will pull all dependencies and sort them out later
# dropping those which don't have a path entry
#-------------------------------------------------------------------
otoolCm = "otool -L %s | grep 'dylib'" % destPath
otoolOut = os.popen( otoolCm ).read()
dependDic = DecomposeLibraryDependency(otoolOut)
depDicOrdinary.update(dependDic)
#-------------------------------------------------------------------
# (C) This library goes into the plugin dir
#-------------------------------------------------------------------
pathDic[nameStyle3] = "@executable_path/" + piDir + "/" + nameStyle3
'''
PrintLibraryDependencyDictionary( depDicOrdinary, "Style (3)" )
PrintLibraryDependencyDictionary( depDicOrdinary, pathDic, "Style (3)" )
exit()
'''
@ -666,7 +708,8 @@ def DeployBinariesForBundle():
# and make the library aware of the locations of libraries
# on which it depends; that is, inter-library dependency
#-------------------------------------------------------------
ret = SetChangeIdentificationNameOfDyLib( depDicOrdinary )
os.chdir( targetDirF )
ret = SetChangeIdentificationNameOfDyLib( depDicOrdinary, pathDic )
if not ret == 0:
msg = "!!! Failed to set and change to new identification names !!!"
print(msg)
@ -695,23 +738,6 @@ def DeployBinariesForBundle():
shutil.copy2( sourceDir1 + "/klayout", targetDirM )
shutil.copy2( sourceDir2 + "/klayout.icns", targetDirR )
# copy the contents of the plugin directories to a place next to the application
# binary
for piDir in [ "db_plugins", "lay_plugins" ]:
os.makedirs( os.path.join( targetDirM, piDir ), exist_ok = True )
dynamicLinkLibs = glob.glob( os.path.join( sourceDir3, piDir, "*.dylib" ) )
for item in dynamicLinkLibs:
if os.path.isfile(item) and not os.path.islink(item):
#-------------------------------------------------------------------
# (A) Copy an ordinary *.dylib file here by changing the name
# to style (3) and set its mode to 0755 (sanity check).
#-------------------------------------------------------------------
fullName = os.path.basename(item).split('.')
# e.g. [ 'libklayout_lay', '0', '25', '0', 'dylib' ]
nameStyle3 = os.path.join( targetDirM, piDir, fullName[0] + "." + fullName[1] + ".dylib" )
shutil.copy2( item, nameStyle3 )
os.chmod( nameStyle3, 0o0755 )
os.chmod( targetDir0 + "/PkgInfo", 0o0644 )
os.chmod( targetDir0 + "/Info.plist", 0o0644 )
os.chmod( targetDirM + "/klayout", 0o0755 )

View File

@ -59,15 +59,18 @@ def DecomposeLibraryDependency( depstr ):
# @param[in] depdic dictionary
# @param[in] namedic dictionary name
#------------------------------------------------------------------------------
def PrintLibraryDependencyDictionary( depdic, namedic ):
def PrintLibraryDependencyDictionary( depdic, pathdic, namedic ):
keys = depdic.keys()
print("")
print("##### Contents of <%s> #####:" % namedic )
for key in keys:
supporters = depdic[key]
print( " %s:" % key )
keyName = os.path.basename(key)
print( " %s: (%s)" % (key, pathdic[keyName]) )
for item in supporters:
print( " %s" % item )
itemName = os.path.basename(item)
if itemName != keyName and (itemName in pathdic):
print( " %s (%s)" % (item, pathdic[itemName]) )
#------------------------------------------------------------------------------
## To set and change identification name of KLayout's dylib
@ -76,7 +79,7 @@ def PrintLibraryDependencyDictionary( depdic, namedic ):
#
# @return 0 on success; non-zero on failure
#------------------------------------------------------------------------------
def SetChangeIdentificationNameOfDyLib( libdic ):
def SetChangeIdentificationNameOfDyLib( libdic, pathDic ):
cmdNameId = XcodeToolChain['nameID']
cmdNameChg = XcodeToolChain['nameCH']
dependentLibs = libdic.keys()
@ -86,7 +89,8 @@ def SetChangeIdentificationNameOfDyLib( libdic ):
# [1] Set the identification name of each dependent library
#-----------------------------------------------------------
nameOld = "%s" % lib
nameNew = "@executable_path/../Frameworks/%s" % lib
libName = os.path.basename(lib)
nameNew = pathDic[libName]
command = "%s %s %s" % ( cmdNameId, nameNew, nameOld )
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to set the new identification name to <%s> !!!"
@ -98,13 +102,15 @@ def SetChangeIdentificationNameOfDyLib( libdic ):
#-------------------------------------------------------------------------
supporters = libdic[lib]
for sup in supporters:
nameOld = "%s" % sup
nameNew = "@executable_path/../Frameworks/%s" % sup
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, lib )
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to make the library aware of the new identification name <%s> of supporter <%s> !!!"
print( msg % (nameNew, sup), file=sys.stderr )
return 1
supName = os.path.basename(sup)
if libName != supName and (supName in pathDic):
nameOld = "%s" % sup
nameNew = pathDic[supName]
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, lib )
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to make the library aware of the new identification name <%s> of supporter <%s> !!!"
print( msg % (nameNew, sup), file=sys.stderr )
return 1
# for-lib
return 0