WIP: Parametrizing macbuild to make custom installations easier (#680)

* Changing indentation to 4 spaces

* squash

* removing more global variables (squash)

* | tee always exits with 0

* parameter is a dictionary now

* Changing default Makefile to HB38 and adding -rbinc2 option for Catalina

* Catalina building...

* macQAT fixed

* run_build_command depends on parameteres dict alone

* Adding options to macbuild/makeDMG4mac.py

In particular, we can now specify a -u (unsafe) option, and
specify the target dmg file with -t target.dmg
This commit is contained in:
Thomas Ferreira de Lima 2020-11-21 16:07:11 -05:00 committed by Matthias Koefferlein
parent beae26ec2e
commit b37ce4e130
10 changed files with 1508 additions and 1327 deletions

11
.gitignore vendored
View File

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

View File

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

View File

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

1
macbuild/.gitignore vendored
View File

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

View File

@ -26,6 +26,12 @@
------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------
on run (volumeName) -- most likely, the volume name is "KLayout" on run (volumeName) -- most likely, the volume name is "KLayout"
tell application "Finder" 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) tell disk (volumeName as string)
-- [1] Open the volume -- [1] Open the volume
open open

View File

@ -27,33 +27,35 @@ from build4mac_util import *
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
## To set global variables including present directory and platform info. ## To set global variables including present directory and platform info.
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
def SetGlobals(): def get_default_config():
global ProjectDir # project directory where "build.sh" exists """
global Usage # string on usage Returns a dictionary containing the default configuration for the macOS build.
global BuildBash # the main build Bash script """
global Platform # platform # global ProjectDir # project directory where "build.sh" exists
global ModuleQt # Qt module to be used # global Usage # string on usage
global ModuleRuby # Ruby module to be used # global BuildBash # the main build Bash script
global ModulePython # Python module to be used # global Platform # platform
global NonOSStdLang # True if non-OS-standard language is chosen # global ModuleQt # Qt module to be used
global NoQtBindings # True if not creating Qt bindings for Ruby scripts # global ModuleRuby # Ruby module to be used
global MakeOptions # options passed to `make` # global ModulePython # Python module to be used
global DebugMode # True if debug mode build # global NonOSStdLang # True if non-OS-standard language is chosen
global CheckComOnly # True if only for checking the command line parameters to "build.sh" # global NoQtBindings # True if not creating Qt bindings for Ruby scripts
global DeploymentF # True if fully (including Qt's Frameworks) deploy the binaries for bundles # global MakeOptions # options passed to `make`
global DeploymentP # True if partially deploy the binaries excluding Qt's Frameworks # global DebugMode # True if debug mode build
global PackagePrefix # the package prefix: 'ST-', 'LW-', 'HW-', or 'EX-' # global CheckComOnly # True if only for checking the command line parameters to "build.sh"
global DeployVerbose # -verbose=<0-3> level passed to 'macdeployqt' tool # global DeploymentF # True if fully (including Qt's Frameworks) deploy the binaries for bundles
global Version # KLayout's version # global DeploymentP # True if partially deploy the binaries excluding Qt's Frameworks
global ModuleSet # (Qt, Ruby, Python)-tuple # global PackagePrefix # the package prefix: 'ST-', 'LW-', 'HW-', or 'EX-'
# auxiliary variables on platform # global DeployVerbose # -verbose=<0-3> level passed to 'macdeployqt' tool
global System # 6-tuple from platform.uname() # global Version # KLayout's version
global Node # - do - # global ModuleSet # (Qt, Ruby, Python)-tuple
global Release # - do - # # auxiliary variables on platform
global Version # - do - # global System # 6-tuple from platform.uname()
global Machine # - do - # global Node # - do -
global Processor # - do - # global Release # - do -
global Bit # machine bit-size # global Version # - do -
# global Machine # - do -
# global Processor # - do -
Usage = "\n" Usage = "\n"
Usage += "---------------------------------------------------------------------------------------------------------\n" Usage += "---------------------------------------------------------------------------------------------------------\n"
@ -99,7 +101,7 @@ def SetGlobals():
ProjectDir = os.getcwd() ProjectDir = os.getcwd()
BuildBash = "./build.sh" BuildBash = "./build.sh"
(System, Node, Release, Version, Machine, Processor) = platform.uname() (System, Node, Release, MacVersion, Machine, Processor) = platform.uname()
if not System == "Darwin": if not System == "Darwin":
print("") print("")
@ -108,7 +110,9 @@ def SetGlobals():
sys.exit(1) sys.exit(1)
release = int( Release.split(".")[0] ) # take the first of ['19', '0', '0'] release = int( Release.split(".")[0] ) # take the first of ['19', '0', '0']
if release == 19: if release == 20:
Platform = "BigSur"
elif release == 19:
Platform = "Catalina" Platform = "Catalina"
elif release == 18: elif release == 18:
Platform = "Mojave" Platform = "Mojave"
@ -164,25 +168,56 @@ def SetGlobals():
Version = GetKLayoutVersionFrom( "./version.sh" ) Version = GetKLayoutVersionFrom( "./version.sh" )
ModuleSet = ( 'qt5MP', 'Sys', 'Sys' ) ModuleSet = ( 'qt5MP', 'Sys', 'Sys' )
config = dict()
config['ProjectDir'] = ProjectDir # project directory where "build.sh" exists
config['Usage'] = Usage # string on usage
config['BuildBash'] = BuildBash # the main build Bash script
config['Platform'] = Platform # platform
config['ModuleQt'] = ModuleQt # Qt module to be used
config['ModuleRuby'] = ModuleRuby # Ruby module to be used
config['ModulePython'] = ModulePython # Python module to be used
config['NonOSStdLang'] = NonOSStdLang # True if non-OS-standard language is chosen
config['NoQtBindings'] = NoQtBindings # True if not creating Qt bindings for Ruby scripts
config['MakeOptions'] = MakeOptions # options passed to `make`
config['DebugMode'] = DebugMode # True if debug mode build
config['CheckComOnly'] = CheckComOnly # True if only for checking the command line parameters to "build.sh"
config['DeploymentF'] = DeploymentF # True if fully (including Qt's Frameworks) deploy the binaries for bundles
config['DeploymentP'] = DeploymentP # True if partially deploy the binaries excluding Qt's Frameworks
config['PackagePrefix'] = PackagePrefix # the package prefix: 'ST-', 'LW-', 'HW-', or 'EX-'
config['DeployVerbose'] = DeployVerbose # -verbose=<0-3> level passed to 'macdeployqt' tool
config['Version'] = Version # KLayout's version
config['ModuleSet'] = ModuleSet # (Qt, Ruby, Python)-tuple
# auxiliary variables on platform
config['System'] = System # 6-tuple from platform.uname()
config['Node'] = Node # - do -
config['Release'] = Release # - do -
config['MacVersion'] = MacVersion # - do -
config['Machine'] = Machine # - do -
config['Processor'] = Processor # - do -
return config
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
## To get command line parameters ## To get command line parameters
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
def ParseCommandLineArguments(): def parse_cli_args(config):
global Usage Usage = config['Usage'] #
global Platform Platform = config['Platform'] #
global ModuleQt Release = config['Release'] #
global ModuleRuby Machine = config['Machine'] #
global ModulePython ModuleQt = config['ModuleQt'] #
global NonOSStdLang ModuleRuby = config['ModuleRuby'] #
global NoQtBindings ModulePython = config['ModulePython'] #
global MakeOptions NonOSStdLang = config['NonOSStdLang'] #
global DebugMode NoQtBindings = config['NoQtBindings'] #
global CheckComOnly MakeOptions = config['MakeOptions'] #
global DeploymentF DebugMode = config['DebugMode'] #
global DeploymentP CheckComOnly = config['CheckComOnly'] #
global PackagePrefix DeploymentF = config['DeploymentF'] #
global DeployVerbose DeploymentP = config['DeploymentP'] #
global ModuleSet PackagePrefix = config['PackagePrefix'] #
DeployVerbose = config['DeployVerbose'] #
ModuleSet = config['ModuleSet'] #
p = optparse.OptionParser( usage=Usage ) p = optparse.OptionParser( usage=Usage )
p.add_option( '-q', '--qt', p.add_option( '-q', '--qt',
@ -404,7 +439,7 @@ def ParseCommandLineArguments():
message = "### You are going to make " message = "### You are going to make "
if DeploymentP: if DeploymentP:
PackagePrefix = "LW-" PackagePrefix = "LW-"
message += "a llightweight (LW-) package excluding Qt5, Ruby, and Python..." message += "a lightweight (LW-) package excluding Qt5, Ruby, and Python..."
elif DeploymentF: elif DeploymentF:
if (ModuleRuby in RubySys) and (ModulePython in PythonSys): if (ModuleRuby in RubySys) and (ModulePython in PythonSys):
PackagePrefix = "ST-" PackagePrefix = "ST-"
@ -421,138 +456,214 @@ def ParseCommandLineArguments():
if CheckComOnly: if CheckComOnly:
sys.exit(0) sys.exit(0)
config['Usage'] = Usage #
config['Platform'] = Platform #
config['ModuleQt'] = ModuleQt #
config['ModuleRuby'] = ModuleRuby #
config['ModulePython'] = ModulePython #
config['NonOSStdLang'] = NonOSStdLang #
config['NoQtBindings'] = NoQtBindings #
config['MakeOptions'] = MakeOptions #
config['DebugMode'] = DebugMode #
config['CheckComOnly'] = CheckComOnly #
config['DeploymentF'] = DeploymentF #
config['DeploymentP'] = DeploymentP #
config['PackagePrefix'] = PackagePrefix #
config['DeployVerbose'] = DeployVerbose #
config['ModuleSet'] = ModuleSet #
return config
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
## To run the main Bash script "build.sh" with appropriate options ## To run the main Bash script "build.sh" with appropriate options
# #
# @return 0 on success; non-zero on failure # @return 0 on success; non-zero on failure
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
def RunMainBuildBash(): def get_build_parameters(config):
global ProjectDir ProjectDir = config['ProjectDir'] #
global Platform Platform = config['Platform'] #
global BuildBash BuildBash = config['BuildBash'] #
global ModuleQt ModuleQt = config['ModuleQt'] #
global ModuleRuby ModuleRuby = config['ModuleRuby'] #
global ModulePython ModulePython = config['ModulePython'] #
global ModuleSet ModuleSet = config['ModuleSet'] #
global NoQtBindings NoQtBindings = config['NoQtBindings'] #
global MakeOptions MakeOptions = config['MakeOptions'] #
global DebugMode DebugMode = config['DebugMode'] #
global CheckComOnly CheckComOnly = config['CheckComOnly'] #
global DeploymentF DeploymentF = config['DeploymentF'] #
global DeploymentP DeploymentP = config['DeploymentP'] #
global PackagePrefix PackagePrefix = config['PackagePrefix'] #
global MacPkgDir # relative path to package directory
global MacBinDir # relative path to binary directory
global MacBuildDir # relative path to build directory
global MacBuildDirQAT # relative path to build directory for QATest
global MacBuildLog # relative path to build log file
global AbsMacPkgDir # absolute path to package directory
global AbsMacBinDir # absolute path to binary directory
global AbsMacBuildDir # absolute path to build directory
global AbsMacBuildDirQAT # absolute path to build directory for QATest
global AbsMacBuildLog # absolute path to build log file
#----------------------------------------------------- #-----------------------------------------------------
# [1] Set parameters passed to the main Bash script # [1] Set parameters passed to the main Bash script
#----------------------------------------------------- #-----------------------------------------------------
parameters = "" parameters = dict()
parameters['build_cmd'] = BuildBash
parameters['check_cmd_only'] = CheckComOnly
# (A) debug or release # (A) debug or release
if DebugMode: parameters['debug_mode'] = DebugMode # True if debug, False if release
if parameters["debug_mode"]:
mode = "debug" mode = "debug"
parameters += " -debug"
else: else:
mode = "release" mode = "release"
parameters += " -release"
# (B) Modules # (B) Modules
(qt, ruby, python) = ModuleSet # ( 'qt5MP', 'Sys', 'Sys' ) (qt, ruby, python) = ModuleSet # ( 'qt5MP', 'Sys', 'Sys' )
ruby_python = "R%sP%s" % ( ruby.lower(), python.lower() ) ruby_python = "R%sP%s" % ( ruby.lower(), python.lower() )
# (C) Target directories and files # (C) Target directories and files
MacPkgDir = "./%s%s.pkg.macos-%s-%s-%s" % (PackagePrefix, qt, Platform, mode, ruby_python) MacPkgDir = "%s%s.pkg.macos-%s-%s-%s" % (PackagePrefix, qt, Platform, mode, ruby_python)
MacBinDir = "./%s.bin.macos-%s-%s-%s" % ( qt, Platform, mode, ruby_python) MacBinDir = "%s.bin.macos-%s-%s-%s" % ( qt, Platform, mode, ruby_python)
MacBuildDir = "./%s.build.macos-%s-%s-%s" % ( qt, Platform, mode, ruby_python) MacBuildDir = "%s.build.macos-%s-%s-%s" % ( qt, Platform, mode, ruby_python)
MacBuildLog = "./%s.build.macos-%s-%s-%s.log" % ( qt, Platform, mode, ruby_python) MacBuildLog = "%s.build.macos-%s-%s-%s.log" % ( qt, Platform, mode, ruby_python)
AbsMacPkgDir = "%s/%s%s.pkg.macos-%s-%s-%s" % (ProjectDir, PackagePrefix, qt, Platform, mode, ruby_python) # AbsMacPkgDir = "%s/%s%s.pkg.macos-%s-%s-%s" % (ProjectDir, PackagePrefix, qt, Platform, mode, ruby_python)
AbsMacBinDir = "%s/%s.bin.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python) # AbsMacBinDir = "%s/%s.bin.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python)
AbsMacBuildDir = "%s/%s.build.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python) # AbsMacBuildDir = "%s/%s.build.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python)
AbsMacBuildLog = "%s/%s.build.macos-%s-%s-%s.log" % (ProjectDir, qt, Platform, mode, ruby_python) # AbsMacBuildLog = "%s/%s.build.macos-%s-%s-%s.log" % (ProjectDir, qt, Platform, mode, ruby_python)
# AbsMacPkgDir = "%s/%s" % (ProjectDir, MacPkgDir)
# AbsMacBinDir = "%s/%s" % (ProjectDir, MacBinDir)
# AbsMacBuildDir = "%s/%s" % (ProjectDir, MacBuildDir)
# AbsMacBuildLog = "%s/%s" % (ProjectDir, MacBuildLog)
MacBuildDirQAT = MacBuildDir + ".macQAT" MacBuildDirQAT = MacBuildDir + ".macQAT"
AbsMacBuildDirQAT = AbsMacBuildDir + ".macQAT" parameters['logfile'] = MacBuildLog
# (D) Qt5 # (D) Qt5
if ModuleQt == 'Qt5MacPorts': if ModuleQt == 'Qt5MacPorts':
parameters += " \\\n -qt5" parameters['qmake'] = Qt5MacPorts['qmake']
parameters += " \\\n -qmake %s" % Qt5MacPorts['qmake'] parameters['deploy_tool'] = Qt5MacPorts['deploy']
parameters += " \\\n -bin %s" % MacBinDir
parameters += " \\\n -build %s" % MacBuildDir
elif ModuleQt == 'Qt5Brew': elif ModuleQt == 'Qt5Brew':
parameters += " \\\n -qt5" parameters['qmake'] = Qt5Brew['qmake']
parameters += " \\\n -qmake %s" % Qt5Brew['qmake'] parameters['deploy_tool'] = Qt5Brew['deploy']
parameters += " \\\n -bin %s" % MacBinDir
parameters += " \\\n -build %s" % MacBuildDir
elif ModuleQt == 'Qt5Ana3': elif ModuleQt == 'Qt5Ana3':
parameters += " \\\n -qt5" parameters['qmake'] = Qt5Ana3['qmake']
parameters += " \\\n -qmake %s" % Qt5Ana3['qmake'] parameters['deploy_tool'] = Qt5Ana3['deploy']
parameters += " \\\n -bin %s" % MacBinDir
parameters += " \\\n -build %s" % MacBuildDir parameters['bin'] = MacBinDir
parameters += " \\\n -rpath %s" % "@executable_path/../Frameworks" parameters['build'] = MacBuildDir
parameters['rpath'] = "@executable_path/../Frameworks"
# (E) want Qt bindings with Ruby scripts? # (E) want Qt bindings with Ruby scripts?
if NoQtBindings: parameters['no_qt_bindings'] = NoQtBindings
parameters += " \\\n -without-qtbinding"
else:
parameters += " \\\n -with-qtbinding"
# (F) options to `make` tool # (F) options to `make` tool
if not MakeOptions == "": if not MakeOptions == "":
parameters += " \\\n -option %s" % MakeOptions parameters['make_options'] = MakeOptions
# (G) about Ruby # (G) about Ruby
if ModuleRuby == "nil": if ModuleRuby != "nil":
parameters += " \\\n -noruby" parameters['ruby'] = RubyDictionary[ModuleRuby]['exe']
else: parameters['rbinc'] = RubyDictionary[ModuleRuby]['inc']
parameters += " \\\n -ruby %s" % RubyDictionary[ModuleRuby]['exe'] parameters['rblib'] = RubyDictionary[ModuleRuby]['lib']
parameters += " \\\n -rbinc %s" % RubyDictionary[ModuleRuby]['inc'] if 'inc2' in RubyDictionary[ModuleRuby]:
parameters += " \\\n -rblib %s" % RubyDictionary[ModuleRuby]['lib'] parameters['rbinc2'] = RubyDictionary[ModuleRuby]['inc2']
# (H) about Python # (H) about Python
if ModulePython == "nil": if ModulePython != "nil":
parameters += " \\\n -nopython" parameters['python'] = PythonDictionary[ModulePython]['exe']
parameters['pyinc'] = PythonDictionary[ModulePython]['inc']
parameters['pylib'] = PythonDictionary[ModulePython]['lib']
config['MacPkgDir'] = MacPkgDir # relative path to package directory
config['MacBinDir'] = MacBinDir # relative path to binary directory
config['MacBuildDir'] = MacBuildDir # relative path to build directory
config['MacBuildDirQAT'] = MacBuildDirQAT # relative path to build directory for QATest
config['MacBuildLog'] = MacBuildLog # relative path to build log file
# config['AbsMacPkgDir'] = AbsMacPkgDir # absolute path to package directory
# config['AbsMacBinDir'] = AbsMacBinDir # absolute path to binary directory
# config['AbsMacBuildDir'] = AbsMacBuildDir # absolute path to build directory
# config['AbsMacBuildDirQAT'] = AbsMacBuildDirQAT # absolute path to build directory for QATest
# config['AbsMacBuildLog'] = AbsMacBuildLog # absolute path to build log file
# Extra parameteres needed for deployment
parameters['project_dir'] = ProjectDir
return parameters
def run_build_command(parameters):
#-----------------------------------------------------
# [1] Set parameters passed to the main Bash script
#-----------------------------------------------------
cmd_args = ""
# (A) debug or release
if parameters["debug_mode"]:
mode = "debug"
cmd_args += " -debug"
else: else:
parameters += " \\\n -python %s" % PythonDictionary[ModulePython]['exe'] mode = "release"
parameters += " \\\n -pyinc %s" % PythonDictionary[ModulePython]['inc'] cmd_args += " -release"
parameters += " \\\n -pylib %s" % PythonDictionary[ModulePython]['lib']
# (C) Target directories and files
MacBuildDirQAT = parameters['build'] + ".macQAT"
# (D) Qt5
cmd_args += " \\\n -qt5"
cmd_args += " \\\n -qmake %s" % parameters['qmake']
cmd_args += " \\\n -bin %s" % parameters['bin']
cmd_args += " \\\n -build %s" % parameters['build']
cmd_args += " \\\n -rpath %s" % parameters['rpath']
# (E) want Qt bindings with Ruby scripts?
if parameters['no_qt_bindings']:
cmd_args += " \\\n -without-qtbinding"
else:
cmd_args += " \\\n -with-qtbinding"
# (F) options to `make` tool
if 'make_options' in parameters:
cmd_args += " \\\n -option %s" % parameters['make_options']
# (G) about Ruby
if 'ruby' in parameters:
cmd_args += " \\\n -ruby %s" % parameters['ruby']
cmd_args += " \\\n -rbinc %s" % parameters['rbinc']
cmd_args += " \\\n -rblib %s" % parameters['rblib']
if 'rbinc2' in parameters:
cmd_args += " \\\n -rbinc2 %s" % parameters['rbinc2']
else:
cmd_args += " \\\n -noruby"
# (H) about Python
if 'python' in parameters:
cmd_args += " \\\n -python %s" % parameters['python']
cmd_args += " \\\n -pyinc %s" % parameters['pyinc']
cmd_args += " \\\n -pylib %s" % parameters['pylib']
else:
cmd_args += " \\\n -nopython"
#----------------------------------------------------- #-----------------------------------------------------
# [2] Make the consolidated command line # [2] Make the consolidated command line
#----------------------------------------------------- #-----------------------------------------------------
command = "time" command = "time"
command += " \\\n %s" % BuildBash command += " \\\n %s" % parameters['build_cmd']
command += parameters command += cmd_args
command += " 2>&1 | tee %s" % MacBuildLog command += " 2>&1 | tee %s; \\\n" % parameters['logfile']
if CheckComOnly: command += "test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
if parameters['check_cmd_only']:
print(command) print(command)
sys.exit(0) sys.exit(0)
#----------------------------------------------------- #-----------------------------------------------------
# [3] Invoke the main Bash script; takes time:-) # [3] Invoke the main Bash script; takes time:-)
#----------------------------------------------------- #-----------------------------------------------------
if DeploymentF:
return 0 myscript = os.path.basename(__file__)
elif DeploymentP: ret = subprocess.call( command, shell=True )
return 0 if ret != 0:
else:
myscript = "build4mac.py"
if subprocess.call( command, shell=True ) != 0:
print( "", file=sys.stderr ) print( "", file=sys.stderr )
print( "-------------------------------------------------------------", file=sys.stderr ) print( "-------------------------------------------------------------", file=sys.stderr )
print( "!!! <%s>: failed to build KLayout" % myscript, file=sys.stderr ) print( "!!! <%s>: failed to build KLayout" % myscript, file=sys.stderr )
print( "-------------------------------------------------------------", file=sys.stderr ) print( "-------------------------------------------------------------", file=sys.stderr )
print( "", file=sys.stderr ) print( "", file=sys.stderr )
return 1 return 1
else:
print( "", file=sys.stderr ) print( "", file=sys.stderr )
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr ) print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
print( "### <%s>: successfully built KLayout" % myscript, file=sys.stderr ) print( "### <%s>: successfully built KLayout" % myscript, file=sys.stderr )
@ -567,7 +678,7 @@ def RunMainBuildBash():
if os.path.isdir( MacBuildDirQAT ): if os.path.isdir( MacBuildDirQAT ):
shutil.rmtree( MacBuildDirQAT ) shutil.rmtree( MacBuildDirQAT )
os.chdir( MacBuildDir ) os.chdir( parameters['build'] )
tarFile = "../macQATest.tar" tarFile = "../macQATest.tar"
tarCmdC = "tar cf %s ." % tarFile tarCmdC = "tar cf %s ." % tarFile
if subprocess.call( tarCmdC, shell=True ) != 0: if subprocess.call( tarCmdC, shell=True ) != 0:
@ -608,24 +719,25 @@ def RunMainBuildBash():
# #
# @return 0 on success; non-zero on failure # @return 0 on success; non-zero on failure
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
def DeployBinariesForBundle(): def DeployBinariesForBundle(config, parameters):
global ProjectDir NonOSStdLang = config['NonOSStdLang']
global ModuleQt DeploymentF = config['DeploymentF']
global NonOSStdLang DeploymentP = config['DeploymentP']
global DeploymentF MacPkgDir = config['MacPkgDir']
global DeploymentP Version = config['Version']
global MacPkgDir DeployVerbose = config['DeployVerbose']
global MacBinDir ModuleRuby = config['ModuleRuby']
global MacBuildDir ModulePython = config['ModulePython']
global MacBuildDirQAT
global MacBuildLog ProjectDir = parameters['project_dir']
global AbsMacPkgDir MacBinDir = parameters['bin']
global AbsMacBinDir MacBuildDir = parameters['build']
global AbsMacBuildDir MacBuildLog = parameters['logfile']
global AbsMacBuildDirQAT
global AbsMacBuildLog AbsMacPkgDir = "%s/%s" % (ProjectDir, MacPkgDir)
global Version AbsMacBinDir = "%s/%s" % (ProjectDir, MacBinDir)
global DeployVerbose AbsMacBuildDir = "%s/%s" % (ProjectDir, MacBuildDir)
AbsMacBuildLog = "%s/%s" % (ProjectDir, MacBuildLog)
print("") print("")
print( "##### Started deploying libraries and executables for <klayout.app> #####" ) print( "##### Started deploying libraries and executables for <klayout.app> #####" )
@ -641,13 +753,13 @@ def DeployBinariesForBundle():
print( " Consider using <-Y|--DEPLOY> instead", file=sys.stderr ) print( " Consider using <-Y|--DEPLOY> instead", file=sys.stderr )
#return 1 #return 1
if not os.path.isfile(MacBuildLog): if not os.path.isfile(MacBuildLog):
print( "!!! Build log file <%s> does not present !!!" % MacBuildLog, file=sys.stderr ) print( "!!! Build log file <%s> is not present !!!" % MacBuildLog, file=sys.stderr )
return 1 return 1
if not os.path.isdir(MacBuildDir): if not os.path.isdir(MacBuildDir):
print( "!!! Build directory <%s> does not present !!!" % MacBuildDir, file=sys.stderr ) print( "!!! Build directory <%s> is not present !!!" % MacBuildDir, file=sys.stderr )
return 1 return 1
if not os.path.isdir(MacBinDir): if not os.path.isdir(MacBinDir):
print( "!!! Binary directory <%s> does not present !!!" % MacBinDir, file=sys.stderr ) print( "!!! Binary directory <%s> is not present !!!" % MacBinDir, file=sys.stderr )
return 1 return 1
@ -902,18 +1014,9 @@ def DeployBinariesForBundle():
# [8] Deploy Qt Frameworks # [8] Deploy Qt Frameworks
#------------------------------------------------------------- #-------------------------------------------------------------
verbose = " -verbose=%d" % DeployVerbose verbose = " -verbose=%d" % DeployVerbose
if ModuleQt == 'Qt5MacPorts':
deploytool = Qt5MacPorts['deploy']
app_bundle = "klayout.app"
options = macdepQtOpt + verbose
elif ModuleQt == 'Qt5Brew':
deploytool = Qt5Brew['deploy']
app_bundle = "klayout.app"
options = macdepQtOpt + verbose
elif ModuleQt == 'Qt5Ana3':
deploytool = Qt5Ana3['deploy']
app_bundle = "klayout.app" app_bundle = "klayout.app"
options = macdepQtOpt + verbose options = macdepQtOpt + verbose
deploytool = parameters['deploy_tool']
# Without the following, the plugin cocoa would not be found properly. # Without the following, the plugin cocoa would not be found properly.
shutil.copy2( sourceDir2 + "/qt.conf", targetDirM ) shutil.copy2( sourceDir2 + "/qt.conf", targetDirM )
@ -1107,14 +1210,19 @@ def DeployBinariesForBundle():
## The main function ## The main function
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
def main(): def main():
SetGlobals() import pprint
ParseCommandLineArguments() pp = pprint.PrettyPrinter(indent=4)
config = get_default_config()
parse_cli_args(config)
#---------------------------------------------------------- #----------------------------------------------------------
# [The main build stage] # [The main build stage]
#---------------------------------------------------------- #----------------------------------------------------------
ret = RunMainBuildBash() parameters = get_build_parameters(config)
if not DeploymentF and not DeploymentP: pp.pprint(parameters)
if not config['DeploymentF'] and not config['DeploymentP']:
ret = run_build_command(parameters)
pp.pprint(config)
if not ret == 0: if not ret == 0:
sys.exit(1) sys.exit(1)
else: else:
@ -1123,7 +1231,7 @@ def main():
# Deployment of dynamic link libraries, executables and # Deployment of dynamic link libraries, executables and
# resources to make the main "klayout.app" bundle # resources to make the main "klayout.app" bundle
#---------------------------------------------------------- #----------------------------------------------------------
ret = DeployBinariesForBundle() ret = DeployBinariesForBundle(config, parameters)
if not ret == 0: if not ret == 0:
sys.exit(1) sys.exit(1)

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! # !!! 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. # Hence, we need to refer to the Ruby header file in "Xcode.app" directly.
# [Key Type Name] = 'Sys' # [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', RubyCatalina = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/bin/ruby',
'inc': '%s/System/Library/Frameworks/Ruby.framework/Headers' % CatalinaSDK, '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' '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 '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 *+*+*+ # Python 3.8 bundled with anaconda3 installed under /Applications/anaconda3/ *+*+*+ EXPERIMENTAL *+*+*+
# The standard installation deploys the tool under $HOME/opt/anaconda3/. # The standard installation deploys the tool under $HOME/opt/anaconda3/.
# If so, you need to make a symbolic link: /Applications/anaconda3 ---> $HOME/opt/anaconda3/ # If so, you need to make a symbolic link: /Applications/anaconda3 ---> $HOME/opt/anaconda3/

View File

@ -23,6 +23,7 @@ import platform
import optparse import optparse
import subprocess import subprocess
import hashlib import hashlib
import string
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
## To import global dictionaries of different modules and utility functions ## To import global dictionaries of different modules and utility functions
@ -41,6 +42,7 @@ def SetGlobals():
global GenOSName # generic OS name global GenOSName # generic OS name
global Platform # platform global Platform # platform
global PkgDir # the package directory where "klayout.app" exists global PkgDir # the package directory where "klayout.app" exists
global UnsafePkg # flags whether to proceed to making "invalid" dmg
global OpClean # 'clean' operation global OpClean # 'clean' operation
global OpMake # 'make' operation global OpMake # 'make' operation
global DefaultBundleName # the default bundle name 'klayout.app' 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 += " : <-c|--clean> and <-m|--make> are mutually exclusive | \n"
Usage += " [-b|--bundle <name>] : forcibly use this bundle name in the DMG | '' \n" Usage += " [-b|--bundle <name>] : forcibly use this bundle name in the DMG | '' \n"
Usage += " [-s|--serial <num>] : DMG serial number | 1 \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 += " [-?|--?] : print this usage and exit | disabled \n"
Usage += "-------------------------------------------------------------------------------------+------------------\n" Usage += "-------------------------------------------------------------------------------------+------------------\n"
@ -131,6 +135,7 @@ def SetGlobals():
sys.exit(1) sys.exit(1)
PkgDir = "" PkgDir = ""
UnsafePkg = False
OpClean = False OpClean = False
OpMake = False OpMake = False
DefaultBundleName = "klayout.app" DefaultBundleName = "klayout.app"
@ -189,6 +194,8 @@ def SetGlobals():
# on failure, -1 # on failure, -1
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
def CheckPkgDirectory(): def CheckPkgDirectory():
global PkgDir
global UnsafePkg
global Platform global Platform
global OpClean global OpClean
global OpMake global OpMake
@ -229,6 +236,9 @@ def CheckPkgDirectory():
regQRP = re.compile(patQRP) regQRP = re.compile(patQRP)
if not regQRP.match(PkgDir): if not regQRP.match(PkgDir):
print( "! Cannot identify (Qt, Ruby, Python) from the package directory name" ) print( "! Cannot identify (Qt, Ruby, Python) from the package directory name" )
if UnsafePkg:
print( "! Ignoring..." )
else:
print( "" ) print( "" )
return -1 return -1
else: else:
@ -337,6 +347,7 @@ def ParseCommandLineArguments():
global OpMake global OpMake
global BundleName global BundleName
global DMGSerialNum global DMGSerialNum
global UnsafePkg
global PackagePrefix global PackagePrefix
global QtIdentification global QtIdentification
global RubyPythonID global RubyPythonID
@ -369,6 +380,16 @@ def ParseCommandLineArguments():
dest='dmg_serial', dest='dmg_serial',
help="DMG serial number" ) 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( '-?', '--??', p.add_option( '-?', '--??',
action='store_true', action='store_true',
dest='checkusage', dest='checkusage',
@ -379,7 +400,9 @@ def ParseCommandLineArguments():
operation_clean = False, operation_clean = False,
operation_make = False, operation_make = False,
bundle_name = "", bundle_name = "",
target_dmg = "",
dmg_serial = "1", dmg_serial = "1",
unsafe = False,
checkusage = False ) checkusage = False )
#----------------------------------------------------------- #-----------------------------------------------------------
@ -394,6 +417,7 @@ def ParseCommandLineArguments():
OpClean = opt.operation_clean OpClean = opt.operation_clean
OpMake = opt.operation_make OpMake = opt.operation_make
DMGSerialNum = int(opt.dmg_serial) DMGSerialNum = int(opt.dmg_serial)
UnsafePkg = opt.unsafe
if not opt.bundle_name == "": if not opt.bundle_name == "":
base, ext = os.path.splitext( os.path.basename(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 # [2] Check the PKG directory to set QtIdentification, RubyPythonID, and BundleName
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
OccupiedDS = CheckPkgDirectory() OccupiedDS = CheckPkgDirectory()
if not 0 < OccupiedDS: if not 0 < OccupiedDS and not UnsafePkg:
print( "! Failed to check the PKG directory" ) print( "! Failed to check the PKG directory" )
print( "" ) print( "" )
quit() quit()
if opt.target_dmg != "":
TargetDMG = opt.target_dmg
else: else:
TargetDMG = "%s-klayout-%s-%s-%s-%d-%s-%s.dmg" \ TargetDMG = "%s-klayout-%s-%s-%s-%d-%s-%s.dmg" \
% (PackagePrefix, KLVersion, GenOSName, Platform, DMGSerialNum, QtIdentification, RubyPythonID) % (PackagePrefix, KLVersion, GenOSName, Platform, DMGSerialNum, QtIdentification, RubyPythonID)
@ -663,7 +690,8 @@ def CleanUp(msg=""):
os.chdir(ProjectDir) os.chdir(ProjectDir)
dmgs = glob.glob( "*.dmg*" ) dmgs = glob.glob( "*.dmg*" )
for item in dmgs: 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 # [3] Clean up AppleScript if any