This commit is contained in:
Matthias Koefferlein 2020-11-22 09:12:39 +01:00
commit d8ff77dd88
10 changed files with 1508 additions and 1327 deletions

11
.gitignore vendored
View File

@ -37,6 +37,8 @@ build-*
bin-*
mkqtdecl.tmp
testtmp
*build.macos*
*bin.macos*
# private data
private
@ -54,3 +56,12 @@ src/klayout.pro.user
*.egg-info/
build/
dist/
# IDEs
.vscode
# Macos artifacts
*.dmg
*.dmg.md5

View File

@ -3,10 +3,10 @@
GITCOMMIT := $(shell git rev-parse --short HEAD)
KLAYOUT_VERSION := $(shell source version.sh && echo $$KLAYOUT_VERSION)
ifndef PYTHON_VERSION
PYTHON_VERSION := B37
PYTHON_VERSION := HB38
endif
ifndef MACOS_VERSION
MACOS_VERSION := HighSierra
MACOS_VERSION := Catalina
endif
.ONESHELL:
@ -15,11 +15,11 @@ default: help
help:
@echo "For Mac OS only"
@echo "make build PYTHON_VERSION=B37"
@echo "make deploy PYTHON_VERSION=B37"
@echo "make build PYTHON_VERSION=HB38"
@echo "make deploy PYTHON_VERSION=HB38"
@echo "make test MACOS_VERSION=HighSierra"
@echo "Valid Mac OS Versions: [Yosemite, ElCapitan, Sierra, HighSierra]"
@echo "Valid Python Version: [nil, Sys, B37]"
@echo "Valid Mac OS Versions: [Yosemite, ElCapitan, Sierra, HighSierra, Mojave, Catalina]"
@echo "Valid Python Version: [nil, Sys, HB38]"
build:
@echo "Building for Mac $(GITCOMMIT)"
@ -29,11 +29,11 @@ build:
deploy:
@echo "Deploying 4 Mac $(GITCOMMIT)"
./build4mac.py -p $(PYTHON_VERSION) -q Qt5Brew -y
test:
@echo "Testing 4 Mac $(GITCOMMIT)"
qt5.pkg.macos-$(MACOS_VERSION)-release/klayout.app/Contents/MacOS/klayout -b -r test-pylib-script.py; \
cd qt5.build.macos-$(MACOS_VERSION)-release; \
PIP_REQUIRE_VIRTUALENV="false" HW-qt5Brew.pkg.macos-$(MACOS_VERSION)-release-RsysPhb38/klayout.app/Contents/MacOS/klayout -b -r test-pylib-script.py; \
cd qt5Brew.build.macos-$(MACOS_VERSION)-release-RsysPhb38; \
ln -s klayout.app/Contents/MacOS/klayout klayout; \
export TESTTMP=testtmp; \
export TESTSRC=..; \
@ -41,18 +41,24 @@ test:
./ut_runner -h || true; \
cd ..
dmg-template:
mkdir -p testtemplate/klayout.app
./makeDMG4mac.py -p testtemplate -m -z -t klayoutDMGTemplate.dmg
cp -a klayoutDMGTemplate.dmg* macbuild/Resources/
rm -Rf testtemplate
dropbox-deploy:
@echo "Preparing for dropbox deployment $(MACOS_VERSION) $(GITCOMMIT)"
mkdir -p deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION); \
pwd; \
ls -lah; \
touch build.txt; \
cp build.txt deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).log.txt; \
hdiutil convert macbuild/Resources/klayoutDMGTemplate.dmg -format UDRW -o work-KLayout.dmg; \
hdiutil resize -size 500m work-KLayout.dmg; \
hdiutil attach work-KLayout.dmg -readwrite -noverify -quiet -mountpoint tempKLayout -noautoopen; \
cp -a qt5.pkg.macos-$(MACOS_VERSION)-release/ tempKLayout/; \
hdiutil detach tempKLayout; \
hdiutil convert work-KLayout.dmg -format UDZO -imagekey zlib-level=9 -o deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg; \
md5 -q deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg > deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg.md5; \
mkdir -p deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)
pwd
ls -lah
touch build.txt
cp build.txt deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).log.txt
hdiutil convert macbuild/Resources/klayoutDMGTemplate.dmg -ov -format UDRW -o work-KLayout.dmg
hdiutil resize -size 500m work-KLayout.dmg
hdiutil attach -readwrite -noverify -quiet -mountpoint tempKLayout -noautoopen work-KLayout.dmg
cp -a HW-qt5Brew.pkg.macos-$(MACOS_VERSION)-release-RsysPhb38/ tempKLayout/
hdiutil detach tempKLayout
hdiutil convert work-KLayout.dmg -ov -format UDZO -imagekey zlib-level=9 -o deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg
md5 -q deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg > deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg.md5
rm work-KLayout.dmg

View File

@ -532,6 +532,11 @@ if [ "$BIN" = "" ]; then
BIN=$CURR_DIR/bin-$CONFIG
fi
if [ "$QMAKE_CCACHE" = 1 ]; then
echo " Compilation caching is activated."
else
echo " Compilation caching is deactivated!"
fi
echo " Installation target: $BIN"
echo " Build directory: $BUILD"

1
macbuild/.gitignore vendored
View File

@ -1 +1,2 @@
*.pyc
KLayoutDMG.applescript

View File

@ -26,6 +26,12 @@
-------------------------------------------------------------------------------------------------
on run (volumeName) -- most likely, the volume name is "KLayout"
tell application "Finder"
repeat 20 times
if (exists (disk (volumeName as string))) then
exit repeat
end if
delay 1
end repeat
tell disk (volumeName as string)
-- [1] Open the volume
open

File diff suppressed because it is too large Load Diff

View File

@ -104,9 +104,10 @@ RubyMojave = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions/2
# !!! Catalina does not allow to hack the "/System" directory; it's READ ONLY even for the super user!
# Hence, we need to refer to the Ruby header file in "Xcode.app" directly.
# [Key Type Name] = 'Sys'
CatalinaSDK = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk"
CatalinaSDK = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk"
RubyCatalina = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/bin/ruby',
'inc': '%s/System/Library/Frameworks/Ruby.framework/Headers' % CatalinaSDK,
'inc2': '%s/System/Library/Frameworks/Ruby.framework/Headers/ruby' % CatalinaSDK,
'lib': '/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/libruby.dylib'
}
@ -221,6 +222,21 @@ Python38Brew = { 'exe': '%s/Versions/3.8/bin/python3.8' % HBPython38Framework
'lib': '%s/Versions/3.8/lib/libpython3.8.dylib' % HBPython38FrameworkPath
}
# # Latest Python from Homebrew *+*+*+ EXPERIMENTAL *+*+*+
# # install with 'brew install python'
# # [Key Type Name] = 'HBAuto'
# import glob
# # In my system, there are four candidates: (python, python3, python@3, python@3.8)
# # Hard to tell which is going to be available to the user. Picking the last one
# HBAutoFrameworkPath = glob.glob("/usr/local/opt/python*/Frameworks/Python.framework/")[-1]
# # expand 3* into _py_version, there should be only one, but I am taking no chances.
# HBAutoFrameworkVersionPath, _py_version = os.path.split(glob.glob("%s/Versions/3*" % HBAutoFrameworkPath)[0])
# PythonAutoBrew = { 'exe': '%s/bin/python%s' % (HBAutoFrameworkVersionPath, _py_version),
# 'inc': '%s/include/python%s' % (HBAutoFrameworkVersionPath, _py_version),
# 'lib': glob.glob("%s/lib/*.dylib" % HBAutoFrameworkVersionPath)[0]
# }
# Python 3.8 bundled with anaconda3 installed under /Applications/anaconda3/ *+*+*+ EXPERIMENTAL *+*+*+
# The standard installation deploys the tool under $HOME/opt/anaconda3/.
# If so, you need to make a symbolic link: /Applications/anaconda3 ---> $HOME/opt/anaconda3/

View File

@ -43,15 +43,15 @@ from build4mac_env import *
# @return a dictionary
#----------------------------------------------------------------------------------------
def DecomposeLibraryDependency( depstr ):
alllines = depstr.split('\n')
numlines = len(alllines)
dependent = alllines[0].split(':')[0].strip()
supporters = []
for line in alllines[1:]:
supporter = line.strip().split(' ')[0].strip()
if not supporter == '':
supporters.append(supporter)
return { dependent: supporters }
alllines = depstr.split('\n')
numlines = len(alllines)
dependent = alllines[0].split(':')[0].strip()
supporters = []
for line in alllines[1:]:
supporter = line.strip().split(' ')[0].strip()
if not supporter == '':
supporters.append(supporter)
return { dependent: supporters }
#----------------------------------------------------------------------------------------
## To print the contents of a library dependency dictionary
@ -61,17 +61,17 @@ def DecomposeLibraryDependency( depstr ):
# @param[in] namedic dictionary name
#----------------------------------------------------------------------------------------
def PrintLibraryDependencyDictionary( depdic, pathdic, namedic ):
keys = depdic.keys()
print("")
print("##### Contents of <%s> #####:" % namedic )
for key in keys:
supporters = depdic[key]
keyName = os.path.basename(key)
print( " %s: (%s)" % (key, pathdic[keyName]) )
for item in supporters:
itemName = os.path.basename(item)
if itemName != keyName and (itemName in pathdic):
print( " %s (%s)" % (item, pathdic[itemName]) )
keys = depdic.keys()
print("")
print("##### Contents of <%s> #####:" % namedic )
for key in keys:
supporters = depdic[key]
keyName = os.path.basename(key)
print( " %s: (%s)" % (key, pathdic[keyName]) )
for item in supporters:
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
@ -81,39 +81,39 @@ def PrintLibraryDependencyDictionary( depdic, pathdic, namedic ):
# @return 0 on success; non-zero on failure
#----------------------------------------------------------------------------------------
def SetChangeIdentificationNameOfDyLib( libdic, pathDic ):
cmdNameId = XcodeToolChain['nameID']
cmdNameChg = XcodeToolChain['nameCH']
dependentLibs = libdic.keys()
cmdNameId = XcodeToolChain['nameID']
cmdNameChg = XcodeToolChain['nameCH']
dependentLibs = libdic.keys()
for lib in dependentLibs:
#-----------------------------------------------------------
# [1] Set the identification name of each dependent library
#-----------------------------------------------------------
nameOld = "%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> !!!"
print( msg % lib, file=sys.stderr )
return 1
#-------------------------------------------------------------------------
# [2] Make the library aware of the new identifications of all supporters
#-------------------------------------------------------------------------
supporters = libdic[lib]
for sup in supporters:
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 )
for lib in dependentLibs:
#-----------------------------------------------------------
# [1] Set the identification name of each dependent library
#-----------------------------------------------------------
nameOld = "%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 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
msg = "!!! Failed to set the new identification name to <%s> !!!"
print( msg % lib, file=sys.stderr )
return 1
#-------------------------------------------------------------------------
# [2] Make the library aware of the new identifications of all supporters
#-------------------------------------------------------------------------
supporters = libdic[lib]
for sup in supporters:
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
#----------------------------------------------------------------------------------------
## To set the identification names of KLayout's libraries to an executable
@ -148,38 +148,38 @@ def SetChangeIdentificationNameOfDyLib( libdic, pathDic ):
# @return 0 on success; non-zero on failure
#----------------------------------------------------------------------------------------
def SetChangeLibIdentificationName( executable, relativedir ):
cmdNameId = XcodeToolChain['nameID']
cmdNameChg = XcodeToolChain['nameCH']
otoolCm = "otool -L %s | grep libklayout" % executable
otoolOut = os.popen( otoolCm ).read()
exedepdic = DecomposeLibraryDependency( executable + ":\n" + otoolOut )
keys = exedepdic.keys()
deplibs = exedepdic[ list(keys)[0] ]
cmdNameId = XcodeToolChain['nameID']
cmdNameChg = XcodeToolChain['nameCH']
otoolCm = "otool -L %s | grep libklayout" % executable
otoolOut = os.popen( otoolCm ).read()
exedepdic = DecomposeLibraryDependency( executable + ":\n" + otoolOut )
keys = exedepdic.keys()
deplibs = exedepdic[ list(keys)[0] ]
for lib in deplibs:
#-----------------------------------------------------------
# [1] Set the identification names for the library
#-----------------------------------------------------------
nameOld = "klayout.app/Contents/Frameworks/%s" % lib
nameNew = "@executable_path/%s/%s" % ( relativedir, lib )
command = "%s %s %s" % ( cmdNameId, nameNew, nameOld )
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to set the new identification name to <%s> !!!"
print( msg % lib, file=sys.stderr )
return 1
for lib in deplibs:
#-----------------------------------------------------------
# [1] Set the identification names for the library
#-----------------------------------------------------------
nameOld = "klayout.app/Contents/Frameworks/%s" % lib
nameNew = "@executable_path/%s/%s" % ( relativedir, lib )
command = "%s %s %s" % ( cmdNameId, nameNew, nameOld )
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to set the new identification name to <%s> !!!"
print( msg % lib, file=sys.stderr )
return 1
#-----------------------------------------------------------
# [2] Make the application aware of the new identification
#-----------------------------------------------------------
nameOld = "%s" % lib
nameNew = "@executable_path/%s/%s" % ( relativedir, lib )
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, executable )
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to make the application aware of the new identification name <%s> !!!"
print( msg % nameNew, file=sys.stderr )
return 1
# for-lib
return 0
#-----------------------------------------------------------
# [2] Make the application aware of the new identification
#-----------------------------------------------------------
nameOld = "%s" % lib
nameNew = "@executable_path/%s/%s" % ( relativedir, lib )
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, executable )
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to make the application aware of the new identification name <%s> !!!"
print( msg % nameNew, file=sys.stderr )
return 1
# for-lib
return 0
#----------------------------------------------------------------------------------------
## To make a library dependency dictionary by recursively walk down the lib hierarchy
@ -191,23 +191,23 @@ def SetChangeLibIdentificationName( executable, relativedir ):
# @return a dictionary
#----------------------------------------------------------------------------------------
def WalkLibDependencyTree( dylibPath, depth=0, filter_regex=r'\t+/usr/local/opt' ):
otoolCm = 'otool -L %s | grep -E "%s"' % (dylibPath, filter_regex)
otoolOut = os.popen( otoolCm ).read()
exedepdic = DecomposeLibraryDependency( dylibPath + ":\n" + otoolOut )
keys = exedepdic.keys()
deplibs = exedepdic[ list(keys)[0] ]
otoolCm = 'otool -L %s | grep -E "%s"' % (dylibPath, filter_regex)
otoolOut = os.popen( otoolCm ).read()
exedepdic = DecomposeLibraryDependency( dylibPath + ":\n" + otoolOut )
keys = exedepdic.keys()
deplibs = exedepdic[ list(keys)[0] ]
if depth < 5:
if len(deplibs) > 0:
for idx, lib in enumerate(deplibs):
lib = str(lib)
if lib != list(keys)[0]:
deplibs[idx] = WalkLibDependencyTree(lib, depth+1, filter_regex)
if depth == 0:
return deplibs
return exedepdic
else:
raise RuntimeError( "Exceeded maximum recursion depth." )
if depth < 5:
if len(deplibs) > 0:
for idx, lib in enumerate(deplibs):
lib = str(lib)
if lib != list(keys)[0]:
deplibs[idx] = WalkLibDependencyTree(lib, depth+1, filter_regex)
if depth == 0:
return deplibs
return exedepdic
else:
raise RuntimeError( "Exceeded maximum recursion depth." )
#----------------------------------------------------------------------------------------
## To make a library dependency dictionary by recursively walk down the Framework
@ -219,27 +219,27 @@ def WalkLibDependencyTree( dylibPath, depth=0, filter_regex=r'\t+/usr/local/opt'
# @return a dictionary
#----------------------------------------------------------------------------------------
def WalkFrameworkPaths( frameworkPaths, filter_regex=r'\.(so|dylib)$',
search_path_filter=r'\t+/usr/local/opt' ):
search_path_filter=r'\t+/usr/local/opt' ):
if isinstance(frameworkPaths, str):
frameworkPathsIter = [frameworkPaths]
else:
frameworkPathsIter = frameworkPaths
if isinstance(frameworkPaths, str):
frameworkPathsIter = [frameworkPaths]
else:
frameworkPathsIter = frameworkPaths
dependency_dict = dict()
dependency_dict = dict()
for frameworkPath in frameworkPathsIter:
# print("Calling:", 'find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex))
find_grep_results = os.popen('find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex)).read().split('\n')
framework_files = filter(lambda x: x != '',
map(lambda x: x.strip(),
find_grep_results))
for frameworkPath in frameworkPathsIter:
# print("Calling:", 'find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex))
find_grep_results = os.popen('find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex)).read().split('\n')
framework_files = filter(lambda x: x != '',
map(lambda x: x.strip(),
find_grep_results))
dependency_dict[frameworkPath] = list()
for idx, file in enumerate(framework_files):
dict_file = {file: WalkLibDependencyTree(file, filter_regex=search_path_filter)}
dependency_dict[frameworkPath].append(dict_file)
return dependency_dict
dependency_dict[frameworkPath] = list()
for idx, file in enumerate(framework_files):
dict_file = {file: WalkLibDependencyTree(file, filter_regex=search_path_filter)}
dependency_dict[frameworkPath].append(dict_file)
return dependency_dict
#----------------------------------------------------------------------------------------
## To make a list of changed libraries
@ -250,32 +250,32 @@ def WalkFrameworkPaths( frameworkPaths, filter_regex=r'\.(so|dylib)$',
# @return a list
#----------------------------------------------------------------------------------------
def WalkDictTree( dependencyDict, visited_files ):
libNameChanges = list()
for lib, dependencies in dependencyDict.items():
if lib in visited_files:
continue
libNameChanges = list()
for lib, dependencies in dependencyDict.items():
if lib in visited_files:
continue
dependency_list = list()
if isinstance(dependencies, list):
for deplib in dependencies:
if isinstance(deplib, str):
dependency_list.append(deplib)
if deplib not in visited_files:
visited_files.append(deplib)
elif isinstance(deplib, dict):
dependency_list.append(next(iter(deplib)))
libNameChanges.extend(WalkDictTree(deplib, visited_files))
dependency_list = list()
if isinstance(dependencies, list):
for deplib in dependencies:
if isinstance(deplib, str):
dependency_list.append(deplib)
if deplib not in visited_files:
visited_files.append(deplib)
elif isinstance(deplib, dict):
dependency_list.append(next(iter(deplib)))
libNameChanges.extend(WalkDictTree(deplib, visited_files))
else:
#raise RuntimeError("Unexpected value: %s" % deplib)
pass
else:
#raise RuntimeError("Unexpected value: %s" % deplib)
pass
else:
raise RuntimeError("Unexpected value: %s" % dependencies)
if len(dependency_list) > 0:
libNameChanges.append((lib, dependency_list))
else:
libNameChanges.append((lib, ))
visited_files.append(lib)
return libNameChanges
raise RuntimeError("Unexpected value: %s" % dependencies)
if len(dependency_list) > 0:
libNameChanges.append((lib, dependency_list))
else:
libNameChanges.append((lib, ))
visited_files.append(lib)
return libNameChanges
#----------------------------------------------------------------------------------------
## To find the Framework name from a library name
@ -286,10 +286,10 @@ def WalkDictTree( dependencyDict, visited_files ):
# @return the path to a Framework
#----------------------------------------------------------------------------------------
def FindFramework( path, root_path ):
relPath = os.path.relpath(path, root_path)
frmPath = os.path.join(root_path, relPath.split(os.sep)[0])
#print( "###", frmPath, path, root_path )
return frmPath
relPath = os.path.relpath(path, root_path)
frmPath = os.path.join(root_path, relPath.split(os.sep)[0])
#print( "###", frmPath, path, root_path )
return frmPath
#----------------------------------------------------------------------------------------
## To resolve an executable path
@ -300,9 +300,9 @@ def FindFramework( path, root_path ):
# @return the resolved path
#----------------------------------------------------------------------------------------
def ResolveExecutablePath( path, executable_path ):
""" Transforms @executable_path into executable_path"""
p = path.replace("@executable_path", "/%s/" % executable_path)
return p
""" Transforms @executable_path into executable_path"""
p = path.replace("@executable_path", "/%s/" % executable_path)
return p
#----------------------------------------------------------------------------------------
## To detect the changed library names
@ -315,12 +315,12 @@ def ResolveExecutablePath( path, executable_path ):
# * ('lib.dylib',)
#----------------------------------------------------------------------------------------
def DetectChanges(frameworkDependencyDict):
visited_files = list()
libNameChanges = list()
for framework, libraries in frameworkDependencyDict.items():
for libraryDict in libraries:
libNameChanges.extend(WalkDictTree(libraryDict, visited_files))
return libNameChanges
visited_files = list()
libNameChanges = list()
for framework, libraries in frameworkDependencyDict.items():
for libraryDict in libraries:
libNameChanges.extend(WalkDictTree(libraryDict, visited_files))
return libNameChanges
#----------------------------------------------------------------------------------------
## To perform the required changes
@ -332,79 +332,79 @@ def DetectChanges(frameworkDependencyDict):
# @return 0 on success; > 0 on failure
#----------------------------------------------------------------------------------------
def PerformChanges( frameworkDependencyDict, replaceFromToPairs=None, executable_path="/tmp/klayout" ):
libNameChanges = DetectChanges(frameworkDependencyDict)
#print(libNameChanges)
cmdNameId = XcodeToolChain['nameID']
cmdNameChg = XcodeToolChain['nameCH']
libNameChanges = DetectChanges(frameworkDependencyDict)
#print(libNameChanges)
cmdNameId = XcodeToolChain['nameID']
cmdNameChg = XcodeToolChain['nameCH']
if replaceFromToPairs is None:
return 0
else:
for libNameChange in libNameChanges:
libNameChangeIterator = iter(libNameChange)
lib = next(libNameChangeIterator)
try:
dependencies = next(libNameChangeIterator)
except StopIteration:
dependencies = list()
for replaceFrom, replaceTo, libdir in replaceFromToPairs:
fileName = ResolveExecutablePath(lib.replace(replaceFrom, replaceTo), executable_path)
if fileName.startswith('/usr'):
# print(f'skipping fileName: {fileName}')
continue
if replaceFromToPairs is None:
return 0
else:
for libNameChange in libNameChanges:
libNameChangeIterator = iter(libNameChange)
lib = next(libNameChangeIterator)
try:
dependencies = next(libNameChangeIterator)
except StopIteration:
dependencies = list()
for replaceFrom, replaceTo, libdir in replaceFromToPairs:
fileName = ResolveExecutablePath(lib.replace(replaceFrom, replaceTo), executable_path)
if fileName.startswith('/usr'):
# print(f'skipping fileName: {fileName}')
continue
if lib.find(replaceFrom) >= 0:
if libdir:
frameworkPath = FindFramework(lib, replaceFrom)
else:
frameworkPath = lib
destFrameworkPath = frameworkPath.replace(replaceFrom, replaceTo)
destFrameworkPath = ResolveExecutablePath(destFrameworkPath, executable_path)
if lib.find(replaceFrom) >= 0:
if libdir:
frameworkPath = FindFramework(lib, replaceFrom)
else:
frameworkPath = lib
destFrameworkPath = frameworkPath.replace(replaceFrom, replaceTo)
destFrameworkPath = ResolveExecutablePath(destFrameworkPath, executable_path)
if not os.path.exists(fileName):
print( " NOT FOUND:", lib.replace(replaceFrom, replaceTo) )
print( " COPYING:", frameworkPath, " -> ", destFrameworkPath )
shutil.copytree(frameworkPath, destFrameworkPath)
if not os.path.exists(fileName):
print( " NOT FOUND:", lib.replace(replaceFrom, replaceTo) )
print( " COPYING:", frameworkPath, " -> ", destFrameworkPath )
shutil.copytree(frameworkPath, destFrameworkPath)
nameId = lib.replace(replaceFrom, replaceTo)
command = "%s %s %s" % ( cmdNameId, nameId, fileName )
if not os.access(fileName, os.W_OK):
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
# print("\t%s" % command)
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to set the new identification name to <%s> !!!"
print( msg % fileName, file=sys.stderr )
return 1
nameId = lib.replace(replaceFrom, replaceTo)
command = "%s %s %s" % ( cmdNameId, nameId, fileName )
if not os.access(fileName, os.W_OK):
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
# print("\t%s" % command)
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to set the new identification name to <%s> !!!"
print( msg % fileName, file=sys.stderr )
return 1
for dependency in dependencies:
if dependency.find(replaceFrom) >= 0:
print( " IN:", fileName )
print( " RENAMING:", dependency, " -> ", dependency.replace(replaceFrom, replaceTo) )
for dependency in dependencies:
if dependency.find(replaceFrom) >= 0:
print( " IN:", fileName )
print( " RENAMING:", dependency, " -> ", dependency.replace(replaceFrom, replaceTo) )
# Try changing id first
nameId = dependency.replace(replaceFrom, replaceTo)
command = "%s %s %s" % ( cmdNameId, nameId, fileName)
if not os.access(str(fileName), os.W_OK):
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
# print("\t%s" % command)
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to set the new identification name to <%s> !!!"
print( msg % fileName, file=sys.stderr )
return 1
# Try changing id first
nameId = dependency.replace(replaceFrom, replaceTo)
command = "%s %s %s" % ( cmdNameId, nameId, fileName)
if not os.access(str(fileName), os.W_OK):
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
# print("\t%s" % command)
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to set the new identification name to <%s> !!!"
print( msg % fileName, file=sys.stderr )
return 1
# Rename dependencies
nameOld = dependency
nameNew = dependency.replace(replaceFrom, replaceTo)
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, str(fileName) )
if not os.access(str(fileName), os.W_OK):
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
# Rename dependencies
nameOld = dependency
nameNew = dependency.replace(replaceFrom, replaceTo)
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, str(fileName) )
if not os.access(str(fileName), os.W_OK):
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
# print("\t%s" % command)
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to set the new identification name to <%s> !!!"
print( msg % fileName, file=sys.stderr )
return 1
return 0
# print("\t%s" % command)
if subprocess.call( command, shell=True ) != 0:
msg = "!!! Failed to set the new identification name to <%s> !!!"
print( msg % fileName, file=sys.stderr )
return 1
return 0
#----------------------------------------------------------------------------------------
## To get KLayout's version from a file; most likely from 'version.sh'
@ -414,25 +414,25 @@ def PerformChanges( frameworkDependencyDict, replaceFromToPairs=None, executable
# @return version string
#----------------------------------------------------------------------------------------
def GetKLayoutVersionFrom( verfile='version.h' ):
version = "?.?.?"
try:
fd = open( verfile, "r" )
contents = fd.readlines()
fd.close()
except Exception as e:
return version
version = "?.?.?"
try:
fd = open( verfile, "r" )
contents = fd.readlines()
fd.close()
except Exception as e:
return version
verReg = re.compile( u'(KLAYOUT_VERSION=\")([0-9A-Z_a-z\.]+)(\")' )
for line in contents:
m = verReg.match(line)
if m:
# print(m.group(0)) # KLAYOUT_VERSION="0.26.1"
# print(m.group(1)) # KLAYOUT_VERSION="
# print(m.group(2)) # 0.26.1
# print(m.group(3)) # "
version = m.group(2)
return version
return version
verReg = re.compile( u'(KLAYOUT_VERSION=\")([0-9A-Z_a-z\.]+)(\")' )
for line in contents:
m = verReg.match(line)
if m:
# print(m.group(0)) # KLAYOUT_VERSION="0.26.1"
# print(m.group(1)) # KLAYOUT_VERSION="
# print(m.group(2)) # 0.26.1
# print(m.group(3)) # "
version = m.group(2)
return version
return version
#----------------------------------------------------------------------------------------
## To generate the contents of "Info.plist" file from a template
@ -443,24 +443,24 @@ def GetKLayoutVersionFrom( verfile='version.h' ):
# @return generated strings
#----------------------------------------------------------------------------------------
def GenerateInfoPlist( keydic, templfile ):
val_exe = keydic['exe']
val_icon = keydic['icon']
val_bname = keydic['bname']
val_ver = keydic['ver']
val_exe = keydic['exe']
val_icon = keydic['icon']
val_bname = keydic['bname']
val_ver = keydic['ver']
try:
fd = open( templfile, "r" )
template = fd.read()
fd.close()
except Exception as e:
return "???"
try:
fd = open( templfile, "r" )
template = fd.read()
fd.close()
except Exception as e:
return "???"
t = string.Template(template)
s = t.substitute( EXECUTABLE = val_exe,
ICONFILE = val_icon,
BUNDLENAME = val_bname,
VERSION = val_ver)
return s
t = string.Template(template)
s = t.substitute( EXECUTABLE = val_exe,
ICONFILE = val_icon,
BUNDLENAME = val_bname,
VERSION = val_ver)
return s
#----------------
# End of File

View File

@ -23,6 +23,7 @@ import platform
import optparse
import subprocess
import hashlib
import string
#-------------------------------------------------------------------------------
## To import global dictionaries of different modules and utility functions
@ -41,6 +42,7 @@ def SetGlobals():
global GenOSName # generic OS name
global Platform # platform
global PkgDir # the package directory where "klayout.app" exists
global UnsafePkg # flags whether to proceed to making "invalid" dmg
global OpClean # 'clean' operation
global OpMake # 'make' operation
global DefaultBundleName # the default bundle name 'klayout.app'
@ -87,6 +89,8 @@ def SetGlobals():
Usage += " : <-c|--clean> and <-m|--make> are mutually exclusive | \n"
Usage += " [-b|--bundle <name>] : forcibly use this bundle name in the DMG | '' \n"
Usage += " [-s|--serial <num>] : DMG serial number | 1 \n"
Usage += " <-u|--unsafe> : Ignores a few checks (use with caution) | disabled \n"
Usage += " <-t|--targetdmg> : Specify output .dmg filename | chosen by script \n"
Usage += " [-?|--?] : print this usage and exit | disabled \n"
Usage += "-------------------------------------------------------------------------------------+------------------\n"
@ -131,6 +135,7 @@ def SetGlobals():
sys.exit(1)
PkgDir = ""
UnsafePkg = False
OpClean = False
OpMake = False
DefaultBundleName = "klayout.app"
@ -189,6 +194,8 @@ def SetGlobals():
# on failure, -1
#------------------------------------------------------------------------------
def CheckPkgDirectory():
global PkgDir
global UnsafePkg
global Platform
global OpClean
global OpMake
@ -229,76 +236,79 @@ def CheckPkgDirectory():
regQRP = re.compile(patQRP)
if not regQRP.match(PkgDir):
print( "! Cannot identify (Qt, Ruby, Python) from the package directory name" )
print( "" )
return -1
if UnsafePkg:
print( "! Ignoring..." )
else:
print( "" )
return -1
else:
pkgdirComponents = regQRP.match(PkgDir).groups()
PackagePrefix = pkgdirComponents[0]
QtIdentification = pkgdirComponents[2]
RubyPythonID = pkgdirComponents[5]
#-----------------------------------------------------------------------------
# [3] Check if the "LatestOS" with MacPorts / Homebrew / Anaconda3
#-----------------------------------------------------------------------------
LatestOSMacPorts = Platform == LatestOS
LatestOSMacPorts &= PackagePrefix == "LW"
LatestOSMacPorts &= QtIdentification == "qt5MP"
LatestOSMacPorts &= RubyPythonID == "Rmp26Pmp38"
#-----------------------------------------------------------------------------
# [3] Check if the "LatestOS" with MacPorts / Homebrew / Anaconda3
#-----------------------------------------------------------------------------
LatestOSMacPorts = Platform == LatestOS
LatestOSMacPorts &= PackagePrefix == "LW"
LatestOSMacPorts &= QtIdentification == "qt5MP"
LatestOSMacPorts &= RubyPythonID == "Rmp26Pmp38"
LatestOSHomebrew = Platform == LatestOS
LatestOSHomebrew &= PackagePrefix == "LW"
LatestOSHomebrew &= QtIdentification == "qt5Brew"
LatestOSHomebrew &= RubyPythonID == "Rhb27Phb38"
LatestOSHomebrew = Platform == LatestOS
LatestOSHomebrew &= PackagePrefix == "LW"
LatestOSHomebrew &= QtIdentification == "qt5Brew"
LatestOSHomebrew &= RubyPythonID == "Rhb27Phb38"
LatestOSAnaconda3 = Platform == LatestOS
LatestOSAnaconda3 &= PackagePrefix == "LW"
LatestOSAnaconda3 &= QtIdentification == "qt5Ana3"
LatestOSAnaconda3 &= RubyPythonID == "Rana3Pana3"
LatestOSAnaconda3 = Platform == LatestOS
LatestOSAnaconda3 &= PackagePrefix == "LW"
LatestOSAnaconda3 &= QtIdentification == "qt5Ana3"
LatestOSAnaconda3 &= RubyPythonID == "Rana3Pana3"
if LatestOSMacPorts:
mydic = DicLightWeight["ports"]
srcDir = PkgDir + "/" + mydic["src"]
desDir = PkgDir + "/" + mydic["des"]
if OpMake:
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
zip_ref.extractall(PkgDir)
os.rename( srcDir, desDir )
if OpClean:
if os.path.isdir(srcDir):
shutil.rmtree(srcDir)
if os.path.isdir(desDir):
shutil.rmtree(desDir)
Item3AppleScript = mydic["item3"]
if LatestOSMacPorts:
mydic = DicLightWeight["ports"]
srcDir = PkgDir + "/" + mydic["src"]
desDir = PkgDir + "/" + mydic["des"]
if OpMake:
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
zip_ref.extractall(PkgDir)
os.rename( srcDir, desDir )
if OpClean:
if os.path.isdir(srcDir):
shutil.rmtree(srcDir)
if os.path.isdir(desDir):
shutil.rmtree(desDir)
Item3AppleScript = mydic["item3"]
if LatestOSHomebrew:
mydic = DicLightWeight["brew"]
srcDir = PkgDir + "/" + mydic["src"]
desDir = PkgDir + "/" + mydic["des"]
if OpMake:
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
zip_ref.extractall(PkgDir)
os.rename( srcDir, desDir )
if OpClean:
if os.path.isdir(srcDir):
shutil.rmtree(srcDir)
if os.path.isdir(desDir):
shutil.rmtree(desDir)
Item3AppleScript = mydic["item3"]
if LatestOSHomebrew:
mydic = DicLightWeight["brew"]
srcDir = PkgDir + "/" + mydic["src"]
desDir = PkgDir + "/" + mydic["des"]
if OpMake:
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
zip_ref.extractall(PkgDir)
os.rename( srcDir, desDir )
if OpClean:
if os.path.isdir(srcDir):
shutil.rmtree(srcDir)
if os.path.isdir(desDir):
shutil.rmtree(desDir)
Item3AppleScript = mydic["item3"]
if LatestOSAnaconda3:
mydic = DicLightWeight["ana3"]
srcDir = PkgDir + "/" + mydic["src"]
desDir = PkgDir + "/" + mydic["des"]
if OpMake:
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
zip_ref.extractall(PkgDir)
os.rename( srcDir, desDir )
if OpClean:
if os.path.isdir(srcDir):
shutil.rmtree(srcDir)
if os.path.isdir(desDir):
shutil.rmtree(desDir)
Item3AppleScript = mydic["item3"]
if LatestOSAnaconda3:
mydic = DicLightWeight["ana3"]
srcDir = PkgDir + "/" + mydic["src"]
desDir = PkgDir + "/" + mydic["des"]
if OpMake:
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
zip_ref.extractall(PkgDir)
os.rename( srcDir, desDir )
if OpClean:
if os.path.isdir(srcDir):
shutil.rmtree(srcDir)
if os.path.isdir(desDir):
shutil.rmtree(desDir)
Item3AppleScript = mydic["item3"]
#------------------------------------------------------
# [4] Check the presence of the default bundle
@ -337,6 +347,7 @@ def ParseCommandLineArguments():
global OpMake
global BundleName
global DMGSerialNum
global UnsafePkg
global PackagePrefix
global QtIdentification
global RubyPythonID
@ -369,6 +380,16 @@ def ParseCommandLineArguments():
dest='dmg_serial',
help="DMG serial number" )
p.add_option( '-t', '--targetdmg',
dest='target_dmg',
help="output DMG filename" )
p.add_option( '-z', '--unsafe',
action='store_true',
dest='unsafe',
default=False,
help="If set, do not check whether pkg folder is empty" )
p.add_option( '-?', '--??',
action='store_true',
dest='checkusage',
@ -379,7 +400,9 @@ def ParseCommandLineArguments():
operation_clean = False,
operation_make = False,
bundle_name = "",
target_dmg = "",
dmg_serial = "1",
unsafe = False,
checkusage = False )
#-----------------------------------------------------------
@ -394,6 +417,7 @@ def ParseCommandLineArguments():
OpClean = opt.operation_clean
OpMake = opt.operation_make
DMGSerialNum = int(opt.dmg_serial)
UnsafePkg = opt.unsafe
if not opt.bundle_name == "":
base, ext = os.path.splitext( os.path.basename(opt.bundle_name) )
@ -410,10 +434,13 @@ def ParseCommandLineArguments():
# [2] Check the PKG directory to set QtIdentification, RubyPythonID, and BundleName
#------------------------------------------------------------------------------------
OccupiedDS = CheckPkgDirectory()
if not 0 < OccupiedDS:
if not 0 < OccupiedDS and not UnsafePkg:
print( "! Failed to check the PKG directory" )
print( "" )
quit()
if opt.target_dmg != "":
TargetDMG = opt.target_dmg
else:
TargetDMG = "%s-klayout-%s-%s-%s-%d-%s-%s.dmg" \
% (PackagePrefix, KLVersion, GenOSName, Platform, DMGSerialNum, QtIdentification, RubyPythonID)
@ -663,7 +690,8 @@ def CleanUp(msg=""):
os.chdir(ProjectDir)
dmgs = glob.glob( "*.dmg*" )
for item in dmgs:
os.system( "rm -Rf %s" % item )
print("Removing %s" % item)
os.system( "rm -Rf -- \"%s\"" % item )
#----------------------------------------------------
# [3] Clean up AppleScript if any