2022-05-05 22:01:40 +02:00
|
|
|
#!/usr/bin/env python3
|
2021-07-17 15:26:55 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
#===============================================================================
|
|
|
|
|
# File: "macbuild/build4mac.py"
|
|
|
|
|
#
|
|
|
|
|
# The top Python script for building KLayout (http://www.klayout.de/index.php)
|
2025-01-18 23:51:02 +01:00
|
|
|
# version 0.29.11 or later on different Apple Mac OSX platforms.
|
2021-07-17 15:26:55 +02:00
|
|
|
#===============================================================================
|
|
|
|
|
import sys
|
|
|
|
|
import os
|
2023-11-23 07:13:41 +01:00
|
|
|
import re
|
2022-10-10 04:36:50 +02:00
|
|
|
import codecs
|
2021-07-17 15:26:55 +02:00
|
|
|
import shutil
|
|
|
|
|
import glob
|
|
|
|
|
import platform
|
|
|
|
|
import optparse
|
|
|
|
|
import subprocess
|
|
|
|
|
import pprint
|
|
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
## To import global dictionaries of different modules and utility functions
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
mydir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
sys.path.append( mydir + "/macbuild" )
|
|
|
|
|
from build4mac_env import *
|
|
|
|
|
from build4mac_util import *
|
|
|
|
|
|
2021-11-15 22:38:47 +01:00
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
## To generate the OS-wise usage strings and the default module set
|
|
|
|
|
#
|
|
|
|
|
# @param[in] platform platform name
|
|
|
|
|
#
|
|
|
|
|
# @return (usage, moduleset)-tuple
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
def GenerateUsage(platform):
|
2024-09-23 23:36:16 +02:00
|
|
|
if platform.upper() in [ "SEQUOIA", "SONOMA", "VENTURA", "MONTEREY" ]: # with Xcode [13.1 .. ]
|
2024-02-16 22:51:08 +01:00
|
|
|
myQt56 = "qt5macports"
|
|
|
|
|
myRuby = "sys"
|
|
|
|
|
myPython = "sys"
|
|
|
|
|
moduleset = ('Qt5MacPorts', 'Sys', 'Sys')
|
2023-11-23 07:13:41 +01:00
|
|
|
else: # too obsolete
|
|
|
|
|
raise Exception( "! Too obsolete platform <%s>" % platform )
|
2021-11-15 22:38:47 +01:00
|
|
|
|
|
|
|
|
usage = "\n"
|
2024-09-23 23:36:16 +02:00
|
|
|
usage += "-----------------------------------------------------------------------------------------------------------\n"
|
2021-11-15 22:38:47 +01:00
|
|
|
usage += "<< Usage of 'build4mac.py' >>\n"
|
2025-01-18 23:51:02 +01:00
|
|
|
usage += " for building KLayout 0.29.11 or later on different Apple macOS platforms.\n"
|
2021-11-15 22:38:47 +01:00
|
|
|
usage += "\n"
|
2021-11-16 15:06:24 +01:00
|
|
|
usage += "$ [python] ./build4mac.py\n"
|
2024-09-23 23:36:16 +02:00
|
|
|
usage += " option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details) | default value\n"
|
|
|
|
|
usage += " ----------------------------------------------------------------------------------------+---------------\n"
|
|
|
|
|
usage += " [-q|--qt <type>] : case-insensitive type=['Qt5MacPorts', 'Qt5Brew', 'Qt5Ana3', | %s\n" % myQt56
|
|
|
|
|
usage += " : 'Qt6MacPorts', 'Qt6Brew'] |\n"
|
|
|
|
|
usage += " : Qt5MacPorts: use Qt5 from MacPorts |\n"
|
|
|
|
|
usage += " : Qt5Brew: use Qt5 from Homebrew |\n"
|
|
|
|
|
usage += " : Qt5Ana3: use Qt5 from Anaconda3 |\n"
|
|
|
|
|
usage += " : Qt6MacPorts: use Qt6 from MacPorts (*) |\n"
|
|
|
|
|
usage += " : Qt6Brew: use Qt6 from Homebrew (*) |\n"
|
|
|
|
|
usage += " : (*) migration to Qt6 is ongoing |\n"
|
2025-01-18 23:51:02 +01:00
|
|
|
usage += " [-r|--ruby <type>] : case-insensitive type=['nil', 'Sys', 'MP33', 'HB34', 'Ana3'] | %s\n" % myRuby
|
2024-09-23 23:36:16 +02:00
|
|
|
usage += " : nil: don't bind Ruby |\n"
|
|
|
|
|
usage += " : Sys: use [Sequoia|Sonoma|Ventura|Monterey]-bundled Ruby 2.6 |\n"
|
|
|
|
|
usage += " : MP33: use Ruby 3.3 from MacPorts |\n"
|
2025-01-18 23:51:02 +01:00
|
|
|
usage += " : HB34: use Ruby 3.4 from Homebrew |\n"
|
2024-09-23 23:36:16 +02:00
|
|
|
usage += " : Ana3: use Ruby 3.2 from Anaconda3 |\n"
|
|
|
|
|
usage += " [-p|--python <type>] : case-insensitive type=['nil', 'Sys', 'MP312', 'HB312', 'Ana3', | %s\n" % myPython
|
|
|
|
|
usage += " : 'MP311', 'HB311', 'HBAuto'] |\n"
|
|
|
|
|
usage += " : nil: don't bind Python |\n"
|
|
|
|
|
usage += " : Sys: use [Sequoia|Sonoma|Ventura|Monterey]-bundled Python 3.9 |\n"
|
|
|
|
|
usage += " : MP312: use Python 3.12 from MacPorts |\n"
|
|
|
|
|
usage += " : HB312: use Python 3.12 from Homebrew |\n"
|
|
|
|
|
usage += " : Ana3: use Python 3.12 from Anaconda3 |\n"
|
|
|
|
|
usage += " : MP311: use Python 3.11 from MacPorts |\n"
|
|
|
|
|
usage += " : HB311: use Python 3.11 from Homebrew (+) |\n"
|
|
|
|
|
usage += " : (+) required to provide the legacy pip in HW-*.dmg |\n"
|
|
|
|
|
usage += " : HBAuto: use the latest Python 3.x auto-detected from Homebrew |\n"
|
|
|
|
|
usage += " [-P|--buildPymod] : build and deploy Pymod (*.whl) for LW-*.dmg | disabled\n"
|
|
|
|
|
usage += " [-n|--noqtbinding] : don't create Qt bindings for ruby scripts | disabled\n"
|
|
|
|
|
usage += " [-u|--noqtuitools] : don't include uitools in Qt binding | disabled\n"
|
|
|
|
|
usage += " [-g|--nolibgit2] : don't include libgit2 for Git package support | disabled\n"
|
|
|
|
|
usage += " [-m|--make <option>] : option passed to 'make' | '--jobs=4'\n"
|
|
|
|
|
usage += " [-d|--debug] : enable debug mode build; AddressSanitizer (ASAN) is linked | disabled\n"
|
|
|
|
|
usage += " [-c|--checkcom] : check command-line and exit without building | disabled\n"
|
|
|
|
|
usage += " [-y|--deploy] : deploy executables and dylibs, including Qt's Frameworks | disabled\n"
|
|
|
|
|
usage += " [-Y|--DEPLOY] : deploy executables and dylibs for those who built KLayout | disabled\n"
|
|
|
|
|
usage += " : from the source code and use the tools in the same machine |\n"
|
|
|
|
|
usage += " : ! After confirmation of the successful build of 'klayout.app', |\n"
|
|
|
|
|
usage += " : rerun this script with BOTH: |\n"
|
|
|
|
|
usage += " : 1) the same options used for building AND |\n"
|
|
|
|
|
usage += " : 2) <-y|--deploy> OR <-Y|--DEPLOY> |\n"
|
|
|
|
|
usage += " : optionally with [-v|--verbose <0-3>] |\n"
|
|
|
|
|
usage += " [-v|--verbose <0-3>] : verbose level of `macdeployqt' (effective with -y only) | 1\n"
|
|
|
|
|
usage += " : 0 = no output, 1 = error/warning (default), |\n"
|
|
|
|
|
usage += " : 2 = normal, 3 = debug |\n"
|
|
|
|
|
usage += " [-?|--?] : print this usage and exit; in zsh, quote like '-?' or '--?' | disabled\n"
|
|
|
|
|
usage += "-------------------------------------------------------------------------------------------+---------------\n"
|
2021-11-15 22:38:47 +01:00
|
|
|
return (usage, moduleset)
|
|
|
|
|
|
2021-07-17 15:26:55 +02:00
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
## To get the default configurations
|
|
|
|
|
#
|
2024-04-01 10:59:06 +02:00
|
|
|
# @return a dictionary containing the default configurations for the macOS build
|
2021-07-17 15:26:55 +02:00
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
def Get_Default_Config():
|
|
|
|
|
ProjectDir = os.getcwd()
|
|
|
|
|
BuildBash = "./build.sh"
|
|
|
|
|
(System, Node, Release, MacVersion, Machine, Processor) = platform.uname()
|
|
|
|
|
|
|
|
|
|
if not System == "Darwin":
|
|
|
|
|
print("")
|
|
|
|
|
print( "!!! Sorry. Your system <%s> looks like non-Mac" % System, file=sys.stderr )
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
2023-11-23 07:13:41 +01:00
|
|
|
release = int( Release.split(".")[0] ) # take the first of ['21', '0', '0']
|
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
|
# Dropped [ElCapitan - BigSur] (2023-10-24).
|
|
|
|
|
# See 415b5aa2efca04928f1148a69e77efd5d76f8c1d for the previous states.
|
|
|
|
|
#----------------------------------------------------------------------------
|
2024-09-23 23:36:16 +02:00
|
|
|
if release == 24:
|
|
|
|
|
Platform = "Sequoia"
|
|
|
|
|
elif release == 23:
|
2023-11-23 07:13:41 +01:00
|
|
|
Platform = "Sonoma"
|
|
|
|
|
elif release == 22:
|
2023-01-16 23:13:28 +01:00
|
|
|
Platform = "Ventura"
|
|
|
|
|
elif release == 21:
|
2021-11-15 22:38:47 +01:00
|
|
|
Platform = "Monterey"
|
2021-07-17 15:26:55 +02:00
|
|
|
else:
|
|
|
|
|
Platform = ""
|
|
|
|
|
print("")
|
|
|
|
|
print( "!!! Sorry. Unsupported major OS release <%d>" % release, file=sys.stderr )
|
2021-11-15 22:38:47 +01:00
|
|
|
print( GenerateUsage("")[0] )
|
2021-07-17 15:26:55 +02:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
if not Machine == "x86_64":
|
2024-09-23 23:36:16 +02:00
|
|
|
# with an Apple Silicon Chip?
|
|
|
|
|
if Machine == "arm64" and Platform in ["Sequoia", "Sonoma", "Ventura", "Monterey"]:
|
2021-07-17 15:26:55 +02:00
|
|
|
print("")
|
|
|
|
|
print( "### Your Mac equips an Apple Silicon Chip ###" )
|
2023-11-23 07:13:41 +01:00
|
|
|
print( " Setting QMAKE_APPLE_DEVICE_ARCHS=arm64\n")
|
|
|
|
|
os.environ['QMAKE_APPLE_DEVICE_ARCHS'] = 'arm64'
|
2021-07-17 15:26:55 +02:00
|
|
|
else:
|
|
|
|
|
print("")
|
|
|
|
|
print( "!!! Sorry. Only x86_64/arm64 architecture machine is supported but found <%s>" % Machine, file=sys.stderr )
|
2021-11-15 22:38:47 +01:00
|
|
|
print( GenerateUsage("")[0] )
|
2021-07-17 15:26:55 +02:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
2021-11-15 22:38:47 +01:00
|
|
|
# Set the OS-wise usage and module set
|
|
|
|
|
Usage, ModuleSet = GenerateUsage(Platform)
|
|
|
|
|
|
2023-10-04 15:08:11 +02:00
|
|
|
# developer's debug level list for this tool
|
|
|
|
|
ToolDebug = list()
|
|
|
|
|
|
2021-07-17 15:26:55 +02:00
|
|
|
# Set the default modules
|
2024-09-23 23:36:16 +02:00
|
|
|
if Platform == "Sequoia":
|
|
|
|
|
ModuleQt = "Qt5MacPorts"
|
|
|
|
|
ModuleRuby = "Sys"
|
|
|
|
|
ModulePython = "Sys"
|
|
|
|
|
elif Platform == "Sonoma":
|
2024-02-16 22:51:08 +01:00
|
|
|
ModuleQt = "Qt5MacPorts"
|
|
|
|
|
ModuleRuby = "Sys"
|
|
|
|
|
ModulePython = "Sys"
|
2023-11-23 07:13:41 +01:00
|
|
|
elif Platform == "Ventura":
|
2024-02-16 22:51:08 +01:00
|
|
|
ModuleQt = "Qt5MacPorts"
|
|
|
|
|
ModuleRuby = "Sys"
|
|
|
|
|
ModulePython = "Sys"
|
2023-11-23 07:13:41 +01:00
|
|
|
elif Platform == "Monterey":
|
2024-02-16 22:51:08 +01:00
|
|
|
ModuleQt = "Qt5MacPorts"
|
|
|
|
|
ModuleRuby = "Sys"
|
|
|
|
|
ModulePython = "Sys"
|
2021-07-17 15:26:55 +02:00
|
|
|
else:
|
2024-02-16 22:51:08 +01:00
|
|
|
ModuleQt = "Qt5MacPorts"
|
2021-07-17 15:26:55 +02:00
|
|
|
ModuleRuby = "nil"
|
|
|
|
|
ModulePython = "nil"
|
|
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
BuildPymodWhl = False
|
2021-07-17 15:26:55 +02:00
|
|
|
NonOSStdLang = False
|
|
|
|
|
NoQtBindings = False
|
|
|
|
|
NoQtUiTools = False
|
2023-11-23 07:13:41 +01:00
|
|
|
NoLibGit2 = False
|
2021-07-17 15:26:55 +02:00
|
|
|
MakeOptions = "--jobs=4"
|
|
|
|
|
DebugMode = False
|
|
|
|
|
CheckComOnly = False
|
|
|
|
|
DeploymentF = False
|
|
|
|
|
DeploymentP = False
|
|
|
|
|
PackagePrefix = ""
|
|
|
|
|
DeployVerbose = 1
|
|
|
|
|
Version = GetKLayoutVersionFrom( "./version.sh" )
|
2024-09-23 23:36:16 +02:00
|
|
|
OSPython3FW = None # system Python3 frameworks in [ None, MontereyPy3FW, VenturaPy3FW, SonomaPy3FW, SequoiaPy3FW ]
|
2024-04-01 10:59:06 +02:00
|
|
|
EmbedQt = False
|
|
|
|
|
EmbedPython3 = False
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
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
|
2024-04-01 10:59:06 +02:00
|
|
|
config['BuildPymodWhl'] = BuildPymodWhl # True to build and deploy "Pymod (*.whl)"
|
2021-07-17 15:26:55 +02:00
|
|
|
config['NonOSStdLang'] = NonOSStdLang # True if non-OS-standard language is chosen
|
|
|
|
|
config['NoQtBindings'] = NoQtBindings # True if not creating Qt bindings for Ruby scripts
|
|
|
|
|
config['NoQtUiTools'] = NoQtUiTools # True if not to include QtUiTools in Qt binding
|
2023-11-23 07:13:41 +01:00
|
|
|
config['NoLibGit2'] = NoLibGit2 # True if not to include libgit2 for Git package support
|
2021-07-17 15:26:55 +02:00
|
|
|
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
|
2023-10-04 15:08:11 +02:00
|
|
|
config['ToolDebug'] = ToolDebug # debug level list for this tool
|
2024-09-23 23:36:16 +02:00
|
|
|
config['OSPython3FW'] = OSPython3FW # system Python3 frameworks in [ None, MontereyPy3FW, VenturaPy3FW, SonomaPy3FW, SequoiaPy3FW ]
|
2024-04-01 10:59:06 +02:00
|
|
|
config['EmbedQt'] = EmbedQt # True if Qt is embedded
|
|
|
|
|
config['EmbedPython3'] = EmbedPython3 # True if Python3 is embedded
|
2021-07-17 15:26:55 +02:00
|
|
|
# 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 parse the command line parameters
|
|
|
|
|
#
|
|
|
|
|
# @param[in] config dictionary containing the default configuration
|
|
|
|
|
#
|
|
|
|
|
# @return the configuration dictionary updated with the CLI parameters
|
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
|
def Parse_CLI_Args(config):
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
# [1] Retrieve the configuration
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
Usage = config['Usage']
|
|
|
|
|
Platform = config['Platform']
|
|
|
|
|
Release = config['Release']
|
|
|
|
|
Machine = config['Machine']
|
|
|
|
|
ModuleQt = config['ModuleQt']
|
|
|
|
|
ModuleRuby = config['ModuleRuby']
|
|
|
|
|
ModulePython = config['ModulePython']
|
2024-04-01 10:59:06 +02:00
|
|
|
BuildPymodWhl = config['BuildPymodWhl']
|
2021-07-17 15:26:55 +02:00
|
|
|
NonOSStdLang = config['NonOSStdLang']
|
|
|
|
|
NoQtBindings = config['NoQtBindings']
|
|
|
|
|
NoQtUiTools = config['NoQtUiTools']
|
2023-11-23 07:13:41 +01:00
|
|
|
NoLibGit2 = config['NoLibGit2']
|
2021-07-17 15:26:55 +02:00
|
|
|
MakeOptions = config['MakeOptions']
|
|
|
|
|
DebugMode = config['DebugMode']
|
|
|
|
|
CheckComOnly = config['CheckComOnly']
|
|
|
|
|
DeploymentF = config['DeploymentF']
|
|
|
|
|
DeploymentP = config['DeploymentP']
|
|
|
|
|
PackagePrefix = config['PackagePrefix']
|
|
|
|
|
DeployVerbose = config['DeployVerbose']
|
|
|
|
|
ModuleSet = config['ModuleSet']
|
2023-10-04 15:08:11 +02:00
|
|
|
ToolDebug = config['ToolDebug']
|
2024-02-16 22:51:08 +01:00
|
|
|
OSPython3FW = config['OSPython3FW']
|
2024-04-01 10:59:06 +02:00
|
|
|
EmbedQt = config['EmbedQt']
|
|
|
|
|
EmbedPython3 = config['EmbedPython3']
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
# [2] Parse the CLI arguments
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
p = optparse.OptionParser(usage=Usage)
|
|
|
|
|
p.add_option( '-q', '--qt',
|
|
|
|
|
dest='type_qt',
|
2022-10-10 04:36:50 +02:00
|
|
|
help="Qt type=['Qt5MacPorts', 'Qt5Brew', 'Qt5Ana3', 'Qt6MacPorts', 'Qt6Brew']" )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
p.add_option( '-r', '--ruby',
|
|
|
|
|
dest='type_ruby',
|
2025-01-18 23:51:02 +01:00
|
|
|
help="Ruby type=['nil', 'Sys', 'MP33', 'HB34', 'Ana3']" )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
p.add_option( '-p', '--python',
|
|
|
|
|
dest='type_python',
|
2024-09-23 23:36:16 +02:00
|
|
|
help="Python type=['nil', 'Sys', 'MP312', 'HB312', 'Ana3', 'MP311', 'HB311', 'HBAuto']" )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2022-05-10 20:25:30 +02:00
|
|
|
p.add_option( '-P', '--buildPymod',
|
2022-05-05 22:01:40 +02:00
|
|
|
action='store_true',
|
2024-04-01 10:59:06 +02:00
|
|
|
dest='build_pymod_whl',
|
2022-05-05 22:01:40 +02:00
|
|
|
default=False,
|
2024-04-01 10:59:06 +02:00
|
|
|
help="build and deploy Pymod (*.whl) (disabled)" )
|
2022-05-05 22:01:40 +02:00
|
|
|
|
2021-07-17 15:26:55 +02:00
|
|
|
p.add_option( '-n', '--noqtbinding',
|
|
|
|
|
action='store_true',
|
|
|
|
|
dest='no_qt_binding',
|
|
|
|
|
default=False,
|
|
|
|
|
help="do not create Qt bindings for Ruby scripts" )
|
|
|
|
|
|
|
|
|
|
p.add_option( '-u', '--noqtuitools',
|
|
|
|
|
action='store_true',
|
|
|
|
|
dest='no_qt_uitools',
|
|
|
|
|
default=False,
|
|
|
|
|
help="don't include uitools in Qt binding" )
|
|
|
|
|
|
2023-11-23 07:13:41 +01:00
|
|
|
p.add_option( '-g', '--nolibgit2',
|
|
|
|
|
action='store_true',
|
|
|
|
|
dest='no_libgit2',
|
|
|
|
|
default=False,
|
|
|
|
|
help="don't include libgit2 for Git package support" )
|
|
|
|
|
|
2021-07-17 15:26:55 +02:00
|
|
|
p.add_option( '-m', '--make',
|
|
|
|
|
dest='make_option',
|
|
|
|
|
help="options passed to `make`" )
|
|
|
|
|
|
|
|
|
|
p.add_option( '-d', '--debug',
|
|
|
|
|
action='store_true',
|
|
|
|
|
dest='debug_build',
|
|
|
|
|
default=False,
|
|
|
|
|
help="enable debug mode build" )
|
|
|
|
|
|
|
|
|
|
p.add_option( '-c', '--checkcom',
|
|
|
|
|
action='store_true',
|
|
|
|
|
dest='check_command',
|
|
|
|
|
default=False,
|
|
|
|
|
help="check command line and exit without building" )
|
|
|
|
|
|
|
|
|
|
p.add_option( '-y', '--deploy',
|
|
|
|
|
action='store_true',
|
|
|
|
|
dest='deploy_full',
|
|
|
|
|
default=False,
|
|
|
|
|
help="fully deploy built binaries" )
|
|
|
|
|
|
|
|
|
|
p.add_option( '-Y', '--DEPLOY',
|
|
|
|
|
action='store_true',
|
|
|
|
|
dest='deploy_partial',
|
|
|
|
|
default=False,
|
|
|
|
|
help="deploy built binaries when non-OS-standard script language is chosen" )
|
|
|
|
|
|
|
|
|
|
p.add_option( '-v', '--verbose',
|
|
|
|
|
dest='deploy_verbose',
|
|
|
|
|
help="verbose level of `macdeployqt` tool" )
|
|
|
|
|
|
2023-10-04 15:08:11 +02:00
|
|
|
p.add_option( '-t', '--tooldebug',
|
|
|
|
|
action='append',
|
|
|
|
|
dest='tool_debug',
|
|
|
|
|
help="developer's debug level list for this tool" ) # not shown in the usage
|
|
|
|
|
|
2021-07-17 15:26:55 +02:00
|
|
|
p.add_option( '-?', '--??',
|
|
|
|
|
action='store_true',
|
|
|
|
|
dest='checkusage',
|
|
|
|
|
default=False,
|
|
|
|
|
help='check usage' )
|
|
|
|
|
|
2024-09-23 23:36:16 +02:00
|
|
|
if Platform.upper() in [ "SEQUOIA", "SONOMA", "VENTURA", "MONTEREY" ]: # with Xcode [13.1 .. ]
|
2024-04-01 10:59:06 +02:00
|
|
|
p.set_defaults( type_qt = "qt5macports",
|
|
|
|
|
type_ruby = "sys",
|
|
|
|
|
type_python = "sys",
|
|
|
|
|
build_pymod_whl = False,
|
|
|
|
|
no_qt_binding = False,
|
|
|
|
|
no_qt_uitools = False,
|
|
|
|
|
no_libgit2 = False,
|
|
|
|
|
make_option = "--jobs=4",
|
|
|
|
|
debug_build = False,
|
|
|
|
|
check_command = False,
|
|
|
|
|
deploy_full = False,
|
|
|
|
|
deploy_partial = False,
|
|
|
|
|
deploy_verbose = "1",
|
|
|
|
|
tool_debug = [],
|
|
|
|
|
checkusage = False )
|
2023-11-23 07:13:41 +01:00
|
|
|
else:
|
|
|
|
|
raise Exception( "! Too obsolete platform <%s>" % Platform )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
opt, args = p.parse_args()
|
|
|
|
|
if (opt.checkusage):
|
|
|
|
|
print(Usage)
|
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
# (A) Determine the Qt type
|
|
|
|
|
candidates = dict()
|
|
|
|
|
candidates['QT5MACPORTS'] = 'Qt5MacPorts'
|
|
|
|
|
candidates['QT5BREW'] = 'Qt5Brew'
|
|
|
|
|
candidates['QT5ANA3'] = 'Qt5Ana3'
|
2022-10-10 04:36:50 +02:00
|
|
|
candidates['QT6MACPORTS'] = 'Qt6MacPorts'
|
|
|
|
|
candidates['QT6BREW'] = 'Qt6Brew'
|
2021-07-17 15:26:55 +02:00
|
|
|
try:
|
|
|
|
|
ModuleQt = candidates[ opt.type_qt.upper() ]
|
|
|
|
|
except KeyError:
|
|
|
|
|
ModuleQt = ''
|
|
|
|
|
pass
|
|
|
|
|
if ModuleQt == '':
|
|
|
|
|
print("")
|
|
|
|
|
print( "!!! Unknown Qt type <%s>. Case-insensitive candidates: %s" % \
|
|
|
|
|
(opt.type_qt, list(candidates.keys())), file=sys.stderr )
|
|
|
|
|
print(Usage)
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
elif ModuleQt == "Qt5MacPorts":
|
2022-10-10 04:36:50 +02:00
|
|
|
choiceQt56 = 'qt5MP'
|
2021-07-17 15:26:55 +02:00
|
|
|
elif ModuleQt == "Qt5Brew":
|
2022-10-10 04:36:50 +02:00
|
|
|
choiceQt56 = 'qt5Brew'
|
2021-07-17 15:26:55 +02:00
|
|
|
elif ModuleQt == "Qt5Ana3":
|
2022-10-10 04:36:50 +02:00
|
|
|
choiceQt56 = 'qt5Ana3'
|
|
|
|
|
elif ModuleQt == "Qt6MacPorts":
|
|
|
|
|
choiceQt56 = 'qt6MP'
|
|
|
|
|
elif ModuleQt == "Qt6Brew":
|
|
|
|
|
choiceQt56 = 'qt6Brew'
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2023-11-23 07:13:41 +01:00
|
|
|
# Check if non-OS-standard (-bundled) script languages (Ruby and Python) are used
|
2021-07-17 15:26:55 +02:00
|
|
|
NonOSStdLang = False
|
|
|
|
|
|
|
|
|
|
# (B) Determine the Ruby type
|
|
|
|
|
candidates = dict()
|
|
|
|
|
candidates['NIL'] = 'nil'
|
|
|
|
|
candidates['SYS'] = 'Sys'
|
2024-02-16 22:51:08 +01:00
|
|
|
candidates['MP33'] = 'MP33'
|
2025-01-18 23:51:02 +01:00
|
|
|
candidates['HB34'] = 'HB34'
|
2023-11-23 07:13:41 +01:00
|
|
|
candidates['ANA3'] = 'Ana3'
|
2021-07-17 15:26:55 +02:00
|
|
|
try:
|
|
|
|
|
choiceRuby = candidates[ opt.type_ruby.upper() ]
|
|
|
|
|
except KeyError:
|
|
|
|
|
ModuleRuby = ''
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
ModuleRuby = ''
|
|
|
|
|
if choiceRuby == "nil":
|
|
|
|
|
ModuleRuby = 'nil'
|
|
|
|
|
elif choiceRuby == "Sys":
|
2024-09-23 23:36:16 +02:00
|
|
|
if Platform == "Sequoia":
|
|
|
|
|
ModuleRuby = 'RubySequoia'
|
|
|
|
|
elif Platform == "Sonoma":
|
2023-11-23 07:13:41 +01:00
|
|
|
ModuleRuby = 'RubySonoma'
|
|
|
|
|
elif Platform == "Ventura":
|
2023-01-16 23:13:28 +01:00
|
|
|
ModuleRuby = 'RubyVentura'
|
|
|
|
|
elif Platform == "Monterey":
|
2021-11-15 22:38:47 +01:00
|
|
|
ModuleRuby = 'RubyMonterey'
|
2024-02-16 22:51:08 +01:00
|
|
|
elif choiceRuby == "MP33":
|
|
|
|
|
ModuleRuby = 'Ruby33MacPorts'
|
2023-02-12 22:24:01 +01:00
|
|
|
NonOSStdLang = True
|
2025-01-18 23:51:02 +01:00
|
|
|
elif choiceRuby == "HB34":
|
|
|
|
|
ModuleRuby = 'Ruby34Brew'
|
2023-02-12 22:24:01 +01:00
|
|
|
NonOSStdLang = True
|
2023-11-23 07:13:41 +01:00
|
|
|
elif choiceRuby == "Ana3":
|
|
|
|
|
ModuleRuby = 'RubyAnaconda3'
|
|
|
|
|
NonOSStdLang = True
|
2021-07-17 15:26:55 +02:00
|
|
|
if ModuleRuby == '':
|
|
|
|
|
print("")
|
|
|
|
|
print( "!!! Unknown Ruby type <%s>. Case-insensitive candidates: %s" % \
|
|
|
|
|
(opt.type_ruby, list(candidates.keys())), file=sys.stderr )
|
|
|
|
|
print(Usage)
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
# (C) Determine the Python type
|
|
|
|
|
candidates = dict()
|
|
|
|
|
candidates['NIL'] = 'nil'
|
2024-02-16 22:51:08 +01:00
|
|
|
candidates['SYS'] = 'Sys'
|
2024-09-23 23:36:16 +02:00
|
|
|
candidates['MP312'] = 'MP312'
|
|
|
|
|
candidates['HB312'] = 'HB312'
|
|
|
|
|
candidates['ANA3'] = 'Ana3'
|
2023-11-23 07:13:41 +01:00
|
|
|
candidates['MP311'] = 'MP311'
|
|
|
|
|
candidates['HB311'] = 'HB311'
|
2021-07-17 15:26:55 +02:00
|
|
|
candidates['HBAUTO'] = 'HBAuto'
|
|
|
|
|
try:
|
|
|
|
|
choicePython = candidates[ opt.type_python.upper() ]
|
|
|
|
|
except KeyError:
|
|
|
|
|
ModulePython = ''
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
ModulePython = ''
|
|
|
|
|
if choicePython == "nil":
|
|
|
|
|
ModulePython = 'nil'
|
2024-02-16 22:51:08 +01:00
|
|
|
OSPython3FW = None
|
|
|
|
|
elif choicePython == "Sys":
|
2024-09-23 23:36:16 +02:00
|
|
|
if Platform == "Sequoia":
|
|
|
|
|
ModulePython = 'PythonSequoia'
|
|
|
|
|
OSPython3FW = SequoiaPy3FW
|
|
|
|
|
elif Platform == "Sonoma":
|
2024-02-16 22:51:08 +01:00
|
|
|
ModulePython = 'PythonSonoma'
|
|
|
|
|
OSPython3FW = SonomaPy3FW
|
|
|
|
|
elif Platform == "Ventura":
|
|
|
|
|
ModulePython = 'PythonVentura'
|
|
|
|
|
OSPython3FW = VenturaPy3FW
|
|
|
|
|
elif Platform == "Monterey":
|
|
|
|
|
ModulePython = 'PythonMonterey'
|
|
|
|
|
OSPython3FW = MontereyPy3FW
|
2024-09-23 23:36:16 +02:00
|
|
|
elif choicePython == "MP312":
|
|
|
|
|
ModulePython = 'Python312MacPorts'
|
2024-02-16 22:51:08 +01:00
|
|
|
OSPython3FW = None
|
2021-07-17 15:26:55 +02:00
|
|
|
NonOSStdLang = True
|
2024-09-23 23:36:16 +02:00
|
|
|
elif choicePython == "HB312":
|
|
|
|
|
ModulePython = 'Python312Brew'
|
2024-02-16 22:51:08 +01:00
|
|
|
OSPython3FW = None
|
2021-07-17 15:26:55 +02:00
|
|
|
NonOSStdLang = True
|
|
|
|
|
elif choicePython == "Ana3":
|
|
|
|
|
ModulePython = 'PythonAnaconda3'
|
2024-02-16 22:51:08 +01:00
|
|
|
OSPython3FW = None
|
2023-11-23 07:13:41 +01:00
|
|
|
NonOSStdLang = True
|
2024-09-23 23:36:16 +02:00
|
|
|
elif choicePython == "HB311":
|
|
|
|
|
ModulePython = 'Python311Brew'
|
2024-02-16 22:51:08 +01:00
|
|
|
OSPython3FW = None
|
2021-11-27 04:05:27 +01:00
|
|
|
NonOSStdLang = True
|
2021-07-17 15:26:55 +02:00
|
|
|
elif choicePython == "HBAuto":
|
|
|
|
|
ModulePython = 'PythonAutoBrew'
|
2024-02-16 22:51:08 +01:00
|
|
|
OSPython3FW = None
|
2021-07-17 15:26:55 +02:00
|
|
|
NonOSStdLang = True
|
|
|
|
|
if ModulePython == '':
|
|
|
|
|
print("")
|
|
|
|
|
print( "!!! Unknown Python type <%s>. Case-insensitive candidates: %s" % \
|
|
|
|
|
(opt.type_python, list(candidates.keys())), file=sys.stderr )
|
|
|
|
|
print(Usage)
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
# (D) Set of modules chosen
|
2022-10-10 04:36:50 +02:00
|
|
|
ModuleSet = ( choiceQt56, choiceRuby, choicePython )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2022-05-05 22:01:40 +02:00
|
|
|
# (E) Set other parameters
|
2024-04-01 10:59:06 +02:00
|
|
|
BuildPymodWhl = opt.build_pymod_whl
|
|
|
|
|
NoQtBindings = opt.no_qt_binding
|
|
|
|
|
NoQtUiTools = opt.no_qt_uitools
|
|
|
|
|
NoLibGit2 = opt.no_libgit2
|
|
|
|
|
MakeOptions = opt.make_option
|
|
|
|
|
DebugMode = opt.debug_build
|
|
|
|
|
CheckComOnly = opt.check_command
|
|
|
|
|
DeploymentF = opt.deploy_full
|
|
|
|
|
DeploymentP = opt.deploy_partial
|
|
|
|
|
ToolDebug = sorted( set([ int(val) for val in opt.tool_debug ]) )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
if DeploymentF and DeploymentP:
|
|
|
|
|
print("")
|
|
|
|
|
print( "!!! Choose either [-y|--deploy] or [-Y|--DEPLOY]", file=sys.stderr )
|
|
|
|
|
print(Usage)
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
DeployVerbose = int(opt.deploy_verbose)
|
|
|
|
|
if not DeployVerbose in [0, 1, 2, 3]:
|
|
|
|
|
print("")
|
|
|
|
|
print( "!!! Unsupported verbose level passed to `macdeployqt` tool", file=sys.stderr )
|
|
|
|
|
print(Usage)
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
# (F) Build mode
|
2021-07-17 15:26:55 +02:00
|
|
|
if not DeploymentF and not DeploymentP:
|
|
|
|
|
target = "%s %s %s" % (Platform, Release, Machine)
|
|
|
|
|
modules = "Qt=%s, Ruby=%s, Python=%s" % (ModuleQt, ModuleRuby, ModulePython)
|
2024-04-01 10:59:06 +02:00
|
|
|
if BuildPymodWhl:
|
|
|
|
|
pymodWhlbuild = "enabled"
|
2022-05-10 20:25:30 +02:00
|
|
|
else:
|
2024-04-01 10:59:06 +02:00
|
|
|
pymodWhlbuild = "disabled"
|
2022-05-10 20:25:30 +02:00
|
|
|
message = "### You are going to build KLayout\n for <%s>\n with <%s>\n with Pymod <%s>...\n"
|
2021-07-17 15:26:55 +02:00
|
|
|
print("")
|
2024-04-01 10:59:06 +02:00
|
|
|
print( message % (target, modules, pymodWhlbuild) )
|
|
|
|
|
# (G) Deploy mode
|
2021-07-17 15:26:55 +02:00
|
|
|
else:
|
2024-04-01 10:59:06 +02:00
|
|
|
EmbedQt = False
|
|
|
|
|
EmbedPython3 = False
|
|
|
|
|
okHWdmg = True
|
|
|
|
|
message = "### You are going to make "
|
2021-07-17 15:26:55 +02:00
|
|
|
if DeploymentP:
|
|
|
|
|
PackagePrefix = "LW-"
|
2024-04-01 10:59:06 +02:00
|
|
|
if not BuildPymodWhl:
|
|
|
|
|
message += "a lightweight (LW-) package excluding Qt[5|6], Ruby, and Python..."
|
2022-05-10 20:25:30 +02:00
|
|
|
else:
|
2024-04-01 10:59:06 +02:00
|
|
|
message += "a lightweight (LW-) package with Pymod (*.whl) excluding Qt[5|6], Ruby, and Python..."
|
2021-07-17 15:26:55 +02:00
|
|
|
elif DeploymentF:
|
2024-04-01 10:59:06 +02:00
|
|
|
if ModuleQt == "Qt5Ana3":
|
|
|
|
|
EmbedQt = False
|
|
|
|
|
message += "Qt5 from Anaconda3 embedded, which is not allowed!"
|
|
|
|
|
okHWdmg = False
|
|
|
|
|
elif (ModuleRuby in RubySys) and (ModulePython in PythonSys):
|
2021-07-17 15:26:55 +02:00
|
|
|
PackagePrefix = "ST-"
|
2024-04-01 10:59:06 +02:00
|
|
|
EmbedQt = True
|
2022-10-10 04:36:50 +02:00
|
|
|
message += "a standard (ST-) package including Qt[5|6] and using OS-bundled Ruby and Python..."
|
2024-09-23 23:36:16 +02:00
|
|
|
elif ModulePython in ['Python311Brew', 'PythonAutoBrew']:
|
2021-07-17 15:26:55 +02:00
|
|
|
PackagePrefix = "HW-"
|
2024-04-01 10:59:06 +02:00
|
|
|
EmbedQt = True
|
|
|
|
|
EmbedPython3 = True
|
2024-09-23 23:36:16 +02:00
|
|
|
message += "a heavyweight (HW-) package including Qt[5|6] and Python3.[11] from Homebrew..."
|
2023-11-23 07:13:41 +01:00
|
|
|
okHWdmg = (ModulePython == 'Python311Brew') or \
|
2024-09-23 23:36:16 +02:00
|
|
|
(ModulePython == 'PythonAutoBrew' and HBPythonAutoVersion in ["3.11"] )
|
2021-07-17 15:26:55 +02:00
|
|
|
else:
|
|
|
|
|
PackagePrefix = "EX-"
|
|
|
|
|
message += "a package with exceptional (EX-) combinations of different modules..."
|
|
|
|
|
print( "" )
|
|
|
|
|
print( message )
|
|
|
|
|
print( "" )
|
2023-11-23 07:13:41 +01:00
|
|
|
if not okHWdmg:
|
2024-04-01 10:59:06 +02:00
|
|
|
print( "!!! HW-dmg package assumes the two conditions:" )
|
|
|
|
|
print( " (1) either Qt5 or Qt6 from MacPorts or Homebrew (Anaconda3 is not a candidate)" )
|
2024-09-23 23:36:16 +02:00
|
|
|
print( " (2) python@3.11 from Homebrew" )
|
2023-11-23 07:13:41 +01:00
|
|
|
sys.exit(1)
|
2022-05-10 20:25:30 +02:00
|
|
|
if CheckComOnly:
|
2021-07-17 15:26:55 +02:00
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
# [3] Update the configuration to return
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
config['Usage'] = Usage
|
|
|
|
|
config['Platform'] = Platform
|
|
|
|
|
config['ModuleQt'] = ModuleQt
|
|
|
|
|
config['ModuleRuby'] = ModuleRuby
|
|
|
|
|
config['ModulePython'] = ModulePython
|
2024-04-01 10:59:06 +02:00
|
|
|
config['BuildPymodWhl'] = BuildPymodWhl
|
2021-07-17 15:26:55 +02:00
|
|
|
config['NonOSStdLang'] = NonOSStdLang
|
|
|
|
|
config['NoQtBindings'] = NoQtBindings
|
|
|
|
|
config['NoQtUiTools'] = NoQtUiTools
|
2023-11-23 07:13:41 +01:00
|
|
|
config['NoLibGit2'] = NoLibGit2
|
2021-07-17 15:26:55 +02:00
|
|
|
config['MakeOptions'] = MakeOptions
|
|
|
|
|
config['DebugMode'] = DebugMode
|
|
|
|
|
config['CheckComOnly'] = CheckComOnly
|
|
|
|
|
config['DeploymentF'] = DeploymentF
|
|
|
|
|
config['DeploymentP'] = DeploymentP
|
|
|
|
|
config['PackagePrefix'] = PackagePrefix
|
|
|
|
|
config['DeployVerbose'] = DeployVerbose
|
2022-05-05 22:01:40 +02:00
|
|
|
config['ModuleSet'] = ModuleSet
|
2023-10-04 15:08:11 +02:00
|
|
|
config['ToolDebug'] = ToolDebug
|
2024-02-16 22:51:08 +01:00
|
|
|
config['OSPython3FW'] = OSPython3FW
|
2024-04-01 10:59:06 +02:00
|
|
|
config['EmbedQt'] = EmbedQt
|
|
|
|
|
config['EmbedPython3'] = EmbedPython3
|
2022-05-10 20:25:30 +02:00
|
|
|
|
|
|
|
|
if CheckComOnly:
|
|
|
|
|
pp = pprint.PrettyPrinter( indent=4, width=140 )
|
|
|
|
|
parameters = Get_Build_Parameters(config)
|
2024-04-01 10:59:06 +02:00
|
|
|
Build_pymod_wheel(parameters)
|
2022-05-10 20:25:30 +02:00
|
|
|
pp.pprint(parameters)
|
|
|
|
|
sys.exit(0)
|
|
|
|
|
else:
|
|
|
|
|
return config
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
|
## To run the main Bash script "build.sh" with appropriate options
|
|
|
|
|
#
|
|
|
|
|
# @param[in] config dictionary containing the build configuration
|
|
|
|
|
|
|
|
|
|
# @return a dictionary containing the build parameters
|
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
|
def Get_Build_Parameters(config):
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
# [1] Retrieve the configuration
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
ProjectDir = config['ProjectDir']
|
|
|
|
|
Platform = config['Platform']
|
|
|
|
|
BuildBash = config['BuildBash']
|
|
|
|
|
ModuleQt = config['ModuleQt']
|
|
|
|
|
ModuleRuby = config['ModuleRuby']
|
|
|
|
|
ModulePython = config['ModulePython']
|
2024-04-01 10:59:06 +02:00
|
|
|
BuildPymodWhl = config['BuildPymodWhl']
|
2021-07-17 15:26:55 +02:00
|
|
|
ModuleSet = config['ModuleSet']
|
|
|
|
|
NoQtBindings = config['NoQtBindings']
|
|
|
|
|
NoQtUiTools = config['NoQtUiTools']
|
2023-11-23 07:13:41 +01:00
|
|
|
NoLibGit2 = config['NoLibGit2']
|
2021-07-17 15:26:55 +02:00
|
|
|
MakeOptions = config['MakeOptions']
|
|
|
|
|
DebugMode = config['DebugMode']
|
|
|
|
|
CheckComOnly = config['CheckComOnly']
|
|
|
|
|
DeploymentF = config['DeploymentF']
|
|
|
|
|
DeploymentP = config['DeploymentP']
|
|
|
|
|
PackagePrefix = config['PackagePrefix']
|
2024-02-16 22:51:08 +01:00
|
|
|
OSPython3FW = config['OSPython3FW']
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
# [2] Set parameters passed to the main Bash script
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
parameters = dict()
|
|
|
|
|
parameters['build_cmd'] = BuildBash
|
|
|
|
|
parameters['check_cmd_only'] = CheckComOnly
|
|
|
|
|
|
|
|
|
|
# (A) debug or release
|
|
|
|
|
parameters['debug_mode'] = DebugMode # True if debug, False if release
|
|
|
|
|
if parameters["debug_mode"]:
|
|
|
|
|
mode = "debug"
|
|
|
|
|
else:
|
|
|
|
|
mode = "release"
|
|
|
|
|
|
|
|
|
|
# (B) Modules
|
2022-01-10 07:13:22 +01:00
|
|
|
(qt, ruby, python) = ModuleSet # ( 'qt6Brew', 'Sys', 'Sys' )
|
2021-07-17 15:26:55 +02:00
|
|
|
ruby_python = "R%sP%s" % ( ruby.lower(), python.lower() )
|
|
|
|
|
|
|
|
|
|
# (C) Target directories and files
|
|
|
|
|
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)
|
|
|
|
|
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)
|
|
|
|
|
MacBuildDirQAT = MacBuildDir + ".macQAT"
|
2024-04-01 10:59:06 +02:00
|
|
|
parameters['bin'] = MacBinDir
|
|
|
|
|
parameters['build'] = MacBuildDir
|
2021-07-17 15:26:55 +02:00
|
|
|
parameters['logfile'] = MacBuildLog
|
|
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
# (D) about Qt[5|6]
|
|
|
|
|
parameters['qmake'] = Qt56Dictionary[ModuleQt]['qmake']
|
|
|
|
|
parameters['deploy_tool'] = Qt56Dictionary[ModuleQt]['deploy']
|
|
|
|
|
parameters['qt_lib_root'] = Qt56Dictionary[ModuleQt]['libdir']
|
|
|
|
|
|
|
|
|
|
# (E) rpath
|
2024-09-23 23:36:16 +02:00
|
|
|
if OSPython3FW in [ MontereyPy3FW, VenturaPy3FW, SonomaPy3FW, SequoiaPy3FW ]:
|
2024-02-16 22:51:08 +01:00
|
|
|
parameters['rpath'] = OSPython3FW
|
|
|
|
|
else:
|
|
|
|
|
parameters['rpath'] = "@executable_path/../Frameworks"
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
# (F) want Qt bindings with Ruby scripts?
|
2021-07-17 15:26:55 +02:00
|
|
|
parameters['no_qt_bindings'] = NoQtBindings
|
|
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
# (G) want QtUiTools?
|
2021-07-17 15:26:55 +02:00
|
|
|
parameters['no_qt_uitools'] = NoQtUiTools
|
|
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
# (H) options to `make` tool
|
2021-07-17 15:26:55 +02:00
|
|
|
if not MakeOptions == "":
|
|
|
|
|
parameters['make_options'] = MakeOptions
|
2022-05-10 20:25:30 +02:00
|
|
|
try:
|
|
|
|
|
jobopt, number = MakeOptions.split('=') # like '--jobs=4' ?
|
|
|
|
|
pnum = int(number)
|
|
|
|
|
except Exception:
|
|
|
|
|
parameters['num_parallel'] = 4 # default
|
|
|
|
|
else:
|
|
|
|
|
parameters['num_parallel'] = pnum
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
# (I) about Ruby
|
2021-07-17 15:26:55 +02:00
|
|
|
if ModuleRuby != "nil":
|
|
|
|
|
parameters['ruby'] = RubyDictionary[ModuleRuby]['exe']
|
|
|
|
|
parameters['rbinc'] = RubyDictionary[ModuleRuby]['inc']
|
|
|
|
|
parameters['rblib'] = RubyDictionary[ModuleRuby]['lib']
|
|
|
|
|
if 'inc2' in RubyDictionary[ModuleRuby]:
|
|
|
|
|
parameters['rbinc2'] = RubyDictionary[ModuleRuby]['inc2']
|
|
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
# (J) about Python
|
2021-07-17 15:26:55 +02:00
|
|
|
if ModulePython != "nil":
|
|
|
|
|
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
|
|
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
# (K) Extra parameters needed for deployment
|
2021-07-17 15:26:55 +02:00
|
|
|
parameters['project_dir'] = ProjectDir
|
2022-05-05 22:01:40 +02:00
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
# (L) Extra parameters needed for <pymod>
|
2022-05-10 20:25:30 +02:00
|
|
|
# <pymod> will be built if:
|
2024-04-01 10:59:06 +02:00
|
|
|
# BuildPymodWhl = True
|
2024-09-23 23:36:16 +02:00
|
|
|
# Platform = [ 'Sequoia', 'Sonoma', 'Ventura', 'Monterey']
|
2025-01-18 23:51:02 +01:00
|
|
|
# ModuleRuby = [ 'Ruby33MacPorts', 'Ruby34Brew', 'RubyAnaconda3' ]
|
2024-09-23 23:36:16 +02:00
|
|
|
# ModulePython = [ 'Python312MacPorts', 'Python311MacPorts',
|
|
|
|
|
# 'Python311Brew',
|
2024-04-01 10:59:06 +02:00
|
|
|
# 'PythonAnaconda3' ]
|
|
|
|
|
parameters['BuildPymodWhl'] = BuildPymodWhl
|
|
|
|
|
parameters['Platform'] = Platform
|
|
|
|
|
parameters['ModuleRuby'] = ModuleRuby
|
|
|
|
|
parameters['ModulePython'] = ModulePython
|
2022-05-05 22:01:40 +02:00
|
|
|
|
|
|
|
|
PymodDistDir = dict()
|
2024-09-23 23:36:16 +02:00
|
|
|
if Platform in [ 'Sequoia', 'Sonoma', 'Ventura', 'Monterey' ]:
|
2025-01-18 23:51:02 +01:00
|
|
|
if ModuleRuby in [ 'Ruby33MacPorts', 'Ruby34Brew', 'RubyAnaconda3' ]:
|
2024-09-23 23:36:16 +02:00
|
|
|
if ModulePython in [ 'Python312MacPorts', 'Python311MacPorts' ]:
|
2024-02-16 22:51:08 +01:00
|
|
|
PymodDistDir[ModulePython] = 'dist-MP3-%s' % ModuleQt
|
2024-09-23 23:36:16 +02:00
|
|
|
elif ModulePython in [ 'Python311Brew' ]:
|
2024-02-16 22:51:08 +01:00
|
|
|
PymodDistDir[ModulePython] = 'dist-HB3-%s' % ModuleQt
|
2022-05-05 22:01:40 +02:00
|
|
|
elif ModulePython in [ 'PythonAnaconda3' ]:
|
2024-02-16 22:51:08 +01:00
|
|
|
PymodDistDir[ModulePython] = 'dist-ana3-%s' % ModuleQt
|
2022-05-05 22:01:40 +02:00
|
|
|
parameters['pymod_dist'] = PymodDistDir
|
2021-07-17 15:26:55 +02:00
|
|
|
return parameters
|
|
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------------
|
2022-05-05 22:01:40 +02:00
|
|
|
## To run the "setup.py" script with appropriate options for building
|
2024-04-01 10:59:06 +02:00
|
|
|
# the klayout Python Module "pymod (*.whl)".
|
2021-07-17 15:26:55 +02:00
|
|
|
#
|
|
|
|
|
# @param[in] parameters dictionary containing the build parameters
|
|
|
|
|
#
|
|
|
|
|
# @return 0 on success; non-zero (1), otherwise
|
|
|
|
|
#------------------------------------------------------------------------------
|
2024-04-01 10:59:06 +02:00
|
|
|
def Build_pymod_wheel(parameters):
|
2023-11-23 07:13:41 +01:00
|
|
|
#-----------------------------------------------------------------------------------------------------------
|
2022-05-10 20:25:30 +02:00
|
|
|
# [1] <pymod> will be built if:
|
2024-04-01 10:59:06 +02:00
|
|
|
# BuildPymodWhl = True
|
2024-09-23 23:36:16 +02:00
|
|
|
# Platform = [ 'Sequoia', 'Sonoma', 'Ventura', 'Monterey']
|
2025-01-18 23:51:02 +01:00
|
|
|
# ModuleRuby = [ 'Ruby33MacPorts', 'Ruby34Brew', 'RubyAnaconda3' ]
|
2024-09-23 23:36:16 +02:00
|
|
|
# ModulePython = [ 'Python312MacPorts', 'Python311MacPorts',
|
|
|
|
|
# 'Python311Brew',
|
2024-04-01 10:59:06 +02:00
|
|
|
# 'PythonAnaconda3' ]
|
2023-11-23 07:13:41 +01:00
|
|
|
#-----------------------------------------------------------------------------------------------------------
|
2024-04-01 10:59:06 +02:00
|
|
|
BuildPymodWhl = parameters['BuildPymodWhl']
|
|
|
|
|
Platform = parameters['Platform']
|
|
|
|
|
ModuleRuby = parameters['ModuleRuby']
|
|
|
|
|
ModulePython = parameters['ModulePython']
|
|
|
|
|
if not BuildPymodWhl:
|
2022-05-10 20:25:30 +02:00
|
|
|
return 0
|
2024-09-23 23:36:16 +02:00
|
|
|
if not Platform in [ 'Sequoia', 'Sonoma', 'Ventura', 'Monterey' ]:
|
2022-05-05 22:01:40 +02:00
|
|
|
return 0
|
2025-01-18 23:51:02 +01:00
|
|
|
elif not ModuleRuby in [ 'Ruby33MacPorts', 'Ruby34Brew', 'RubyAnaconda3' ]:
|
2022-05-05 22:01:40 +02:00
|
|
|
return 0
|
2024-09-23 23:36:16 +02:00
|
|
|
elif not ModulePython in [ 'Python312MacPorts', 'Python311MacPorts', \
|
|
|
|
|
'Python311Brew', \
|
|
|
|
|
'PythonAnaconda3' ]:
|
2022-05-05 22:01:40 +02:00
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
#--------------------------------------------------------------------
|
2022-12-17 05:42:08 +01:00
|
|
|
# [2] Get the new directory names (dictionary) for "dist" and
|
|
|
|
|
# set the CPATH environment variable for including <png.h>
|
|
|
|
|
# required to build the pymod of 0.28 or later
|
2022-05-05 22:01:40 +02:00
|
|
|
#--------------------------------------------------------------------
|
|
|
|
|
PymodDistDir = parameters['pymod_dist']
|
2022-12-17 05:42:08 +01:00
|
|
|
# Using MacPorts
|
2024-02-16 22:51:08 +01:00
|
|
|
if PymodDistDir[ModulePython].find('dist-MP3') >= 0:
|
2023-03-18 23:38:14 +01:00
|
|
|
addBinPath = "/opt/local/bin"
|
2022-12-17 05:42:08 +01:00
|
|
|
addIncPath = "/opt/local/include"
|
2023-01-16 23:13:28 +01:00
|
|
|
addLibPath = "/opt/local/lib"
|
2024-04-03 13:54:47 +02:00
|
|
|
whlTarget = "MP3"
|
2022-12-17 05:42:08 +01:00
|
|
|
# Using Homebrew
|
2024-02-16 22:51:08 +01:00
|
|
|
elif PymodDistDir[ModulePython].find('dist-HB3') >= 0:
|
2023-03-18 23:38:14 +01:00
|
|
|
addBinPath = "%s/bin" % DefaultHomebrewRoot # defined in "build4mac_env.py"
|
|
|
|
|
addIncPath = "%s/include" % DefaultHomebrewRoot # -- ditto --
|
|
|
|
|
addLibPath = "%s/lib" % DefaultHomebrewRoot # -- ditto --
|
2024-04-03 13:54:47 +02:00
|
|
|
whlTarget = "HB3"
|
2023-11-23 07:13:41 +01:00
|
|
|
# Using Anaconda3
|
2024-02-16 22:51:08 +01:00
|
|
|
elif PymodDistDir[ModulePython].find('dist-ana3') >= 0:
|
2023-03-18 23:38:14 +01:00
|
|
|
addBinPath = "/Applications/anaconda3/bin"
|
2022-12-17 05:42:08 +01:00
|
|
|
addIncPath = "/Applications/anaconda3/include"
|
2023-01-16 23:13:28 +01:00
|
|
|
addLibPath = "/Applications/anaconda3/lib"
|
2024-04-03 13:54:47 +02:00
|
|
|
whlTarget = "ana3"
|
2022-12-17 05:42:08 +01:00
|
|
|
else:
|
2023-03-18 23:38:14 +01:00
|
|
|
addBinPath = ""
|
2022-12-17 05:42:08 +01:00
|
|
|
addIncPath = ""
|
2023-01-16 23:13:28 +01:00
|
|
|
addLibPath = ""
|
2024-04-03 13:54:47 +02:00
|
|
|
whlTarget = ""
|
2023-01-16 23:13:28 +01:00
|
|
|
|
2023-03-18 23:38:14 +01:00
|
|
|
if not addBinPath == "":
|
|
|
|
|
try:
|
|
|
|
|
bpath = os.environ['PATH']
|
|
|
|
|
except KeyError:
|
|
|
|
|
os.environ['PATH'] = addBinPath
|
|
|
|
|
else:
|
|
|
|
|
os.environ['PATH'] = "%s:%s" % (addBinPath, bpath)
|
|
|
|
|
|
2022-12-17 05:42:08 +01:00
|
|
|
if not addIncPath == "":
|
|
|
|
|
try:
|
|
|
|
|
cpath = os.environ['CPATH']
|
|
|
|
|
except KeyError:
|
|
|
|
|
os.environ['CPATH'] = addIncPath
|
|
|
|
|
else:
|
|
|
|
|
os.environ['CPATH'] = "%s:%s" % (addIncPath, cpath)
|
2022-05-05 22:01:40 +02:00
|
|
|
|
2023-01-16 23:13:28 +01:00
|
|
|
if not addLibPath == "":
|
|
|
|
|
try:
|
|
|
|
|
ldpath = os.environ['LDFLAGS']
|
|
|
|
|
except KeyError:
|
2023-09-26 13:53:19 +02:00
|
|
|
os.environ['LDFLAGS'] = '-L%s -headerpad_max_install_names' % addLibPath
|
2023-01-16 23:13:28 +01:00
|
|
|
else:
|
2023-09-26 13:53:19 +02:00
|
|
|
os.environ['LDFLAGS'] = '-L%s %s -headerpad_max_install_names' % (addLibPath, ldpath)
|
2023-01-16 23:13:28 +01:00
|
|
|
|
2022-05-05 22:01:40 +02:00
|
|
|
#--------------------------------------------------------------------
|
|
|
|
|
# [3] Set different command line parameters for building <pymod>
|
|
|
|
|
#--------------------------------------------------------------------
|
2023-03-18 23:38:14 +01:00
|
|
|
cmd1_args = " -m setup build \\\n"
|
|
|
|
|
cmd2_args = " -m setup bdist_wheel \\\n"
|
|
|
|
|
deloc_cmd = " delocate-wheel --ignore-missing-dependencies"
|
|
|
|
|
cmd3_args = " <wheel file> \\\n"
|
|
|
|
|
cmd4_args = " -m setup clean --all \\\n"
|
2022-05-05 22:01:40 +02:00
|
|
|
|
|
|
|
|
#--------------------------------------------------------------------
|
|
|
|
|
# [4] Make the consolidated command lines
|
|
|
|
|
#--------------------------------------------------------------------
|
|
|
|
|
command1 = "time"
|
|
|
|
|
command1 += " \\\n %s \\\n" % parameters['python']
|
|
|
|
|
command1 += cmd1_args
|
|
|
|
|
command1 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
|
|
|
|
|
command1 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
|
|
|
|
|
|
|
|
|
command2 = "time"
|
|
|
|
|
command2 += " \\\n %s \\\n" % parameters['python']
|
|
|
|
|
command2 += cmd2_args
|
|
|
|
|
command2 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
|
|
|
|
|
command2 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
|
|
|
|
|
|
|
|
|
command3 = "time"
|
2023-03-18 23:38:14 +01:00
|
|
|
command3 += " \\\n %s \\\n" % deloc_cmd
|
2022-05-05 22:01:40 +02:00
|
|
|
command3 += cmd3_args
|
|
|
|
|
command3 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
|
|
|
|
|
command3 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
|
|
|
|
|
|
|
|
|
command4 = "time"
|
|
|
|
|
command4 += " \\\n %s \\\n" % parameters['python']
|
|
|
|
|
command4 += cmd4_args
|
|
|
|
|
command4 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
|
|
|
|
|
command4 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
|
|
|
|
|
|
|
|
|
print( "" )
|
|
|
|
|
print( "### You are going to build <pymod> with the following four stages." )
|
|
|
|
|
print( "<Stage-1>")
|
|
|
|
|
print( " ", command1 )
|
|
|
|
|
print( "" )
|
|
|
|
|
|
|
|
|
|
print( "<Stage-2>")
|
|
|
|
|
print( " ", command2 )
|
|
|
|
|
print( "" )
|
|
|
|
|
|
|
|
|
|
print( "<Stage-3>")
|
|
|
|
|
print( " ", command3 )
|
|
|
|
|
print( "" )
|
|
|
|
|
|
|
|
|
|
print( "<Stage-4>")
|
|
|
|
|
print( " ", command4 )
|
|
|
|
|
print( "" )
|
2023-03-18 23:38:14 +01:00
|
|
|
|
2021-07-17 15:26:55 +02:00
|
|
|
if parameters['check_cmd_only']:
|
2022-05-10 20:25:30 +02:00
|
|
|
return 0
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
#-----------------------------------------------------
|
2024-04-03 13:54:47 +02:00
|
|
|
# [5-A] Invoke the main Python scripts; takes time:-)
|
2021-07-17 15:26:55 +02:00
|
|
|
#-----------------------------------------------------
|
|
|
|
|
myscript = os.path.basename(__file__)
|
2022-05-05 22:01:40 +02:00
|
|
|
ret = subprocess.call( command1, shell=True )
|
2021-07-17 15:26:55 +02:00
|
|
|
if ret != 0:
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
2022-05-05 22:01:40 +02:00
|
|
|
print( "!!! <%s>: failed to build <pymod>" % myscript, file=sys.stderr )
|
2021-07-17 15:26:55 +02:00
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
|
2022-05-05 22:01:40 +02:00
|
|
|
ret = subprocess.call( command2, shell=True )
|
|
|
|
|
if ret != 0:
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "!!! <%s>: failed to build <pymod-wheel>" % myscript, file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
return 1
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2023-03-18 23:38:14 +01:00
|
|
|
#---------------------------------------------------------------------------------------------------------
|
2024-04-03 13:54:47 +02:00
|
|
|
# [5-B] Copy and relink library dependencies for wheel.
|
|
|
|
|
# In this step, the "delocate-wheel" command using the desired Python must be found in the PATH.
|
|
|
|
|
# Refer to: https://github.com/Kazzz-S/klayout/issues/49#issuecomment-1432154118
|
|
|
|
|
# https://pypi.org/project/delocate/
|
2023-03-18 23:38:14 +01:00
|
|
|
#---------------------------------------------------------------------------------------------------------
|
2024-09-23 23:36:16 +02:00
|
|
|
cmd3_args = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.29.7-cp312-cp312-macosx_12_0_x86_64.whl']
|
2023-03-18 23:38:14 +01:00
|
|
|
if len(cmd3_args) == 1:
|
|
|
|
|
command3 = "time"
|
|
|
|
|
command3 += " \\\n %s \\\n" % deloc_cmd
|
|
|
|
|
command3 += " %s \\\n" % cmd3_args[0]
|
|
|
|
|
command3 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
|
|
|
|
|
command3 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
|
|
|
|
ret = subprocess.call( command3, shell=True )
|
|
|
|
|
else:
|
|
|
|
|
ret = 1
|
2022-05-05 22:01:40 +02:00
|
|
|
if ret != 0:
|
2021-07-17 15:26:55 +02:00
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
2023-03-18 23:38:14 +01:00
|
|
|
print( "!!! <%s>: failed to <delocate-wheel>" % myscript, file=sys.stderr )
|
2021-07-17 15:26:55 +02:00
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
|
2022-05-05 22:01:40 +02:00
|
|
|
ret = subprocess.call( command4, shell=True )
|
|
|
|
|
if ret != 0:
|
2021-07-17 15:26:55 +02:00
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
2022-05-05 22:01:40 +02:00
|
|
|
print( "!!! <%s>: failed to clean <pymod>" % myscript, file=sys.stderr )
|
2021-07-17 15:26:55 +02:00
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
|
2024-04-03 13:54:47 +02:00
|
|
|
#------------------------------------------------------------------------
|
|
|
|
|
# [5-C] Forcibly change the wheel file name for anaconda3
|
|
|
|
|
# Ref. https://github.com/Kazzz-S/klayout/issues/53
|
2024-09-23 23:36:16 +02:00
|
|
|
# original: klayout-0.29.7-cp312-cp312-macosx_12_0_x86_64.whl
|
2024-04-03 13:54:47 +02:00
|
|
|
# |
|
|
|
|
|
# V
|
2024-09-23 23:36:16 +02:00
|
|
|
# new: klayout-0.29.7-cp312-cp312-macosx_10_9_x86_64.whl
|
2024-04-03 13:54:47 +02:00
|
|
|
#------------------------------------------------------------------------
|
|
|
|
|
if whlTarget == "ana3":
|
2024-09-23 23:36:16 +02:00
|
|
|
wheels = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.29.7-cp312-cp312-macosx_12_0_x86_64.whl']
|
2024-04-03 13:54:47 +02:00
|
|
|
if not len(wheels) == 1:
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "!!! <%s>: failed to <find wheel for anaconda3>" % myscript, file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
else:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
original = wheels[0]
|
|
|
|
|
# 0 1 2 3 4 5 6 *7 8 9
|
|
|
|
|
patwhl = r"(^dist/klayout-)([0-9.]+)(-)(cp[0-9]+)(-)(cp[0-9]+)(-macosx_)([0-9]+_[0-9]+)([a-z0-9_]+)(\.whl)"
|
|
|
|
|
regwhl = re.compile(patwhl)
|
|
|
|
|
if not regwhl.match(original):
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "!!! <%s>: failed to <rename wheel for anaconda3>" % myscript, file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
else:
|
|
|
|
|
ver = regwhl.match(original).groups()[7]
|
|
|
|
|
new = original.replace( ver, "10_9" )
|
|
|
|
|
os.rename( original, new )
|
|
|
|
|
|
2022-05-05 22:01:40 +02:00
|
|
|
#-----------------------------------------------------
|
|
|
|
|
# [6] Rename the "dist/" directory
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
os.rename( "dist", PymodDistDir[ModulePython] )
|
2021-07-17 15:26:55 +02:00
|
|
|
return 0
|
|
|
|
|
|
2022-05-05 22:01:40 +02:00
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
|
## To run the main Bash script "build.sh" with appropriate options
|
|
|
|
|
#
|
2023-11-23 07:13:41 +01:00
|
|
|
# @param[in] config the build configuration
|
|
|
|
|
# @param[in] parameters the build parameters
|
2022-05-05 22:01:40 +02:00
|
|
|
#
|
|
|
|
|
# @return 0 on success; non-zero (1), otherwise
|
|
|
|
|
#------------------------------------------------------------------------------
|
2023-11-23 07:13:41 +01:00
|
|
|
def Run_Build_Command(config, parameters):
|
2024-07-07 11:47:11 +02:00
|
|
|
DebugMode = config['DebugMode']
|
2023-11-23 07:13:41 +01:00
|
|
|
ModuleQt = config['ModuleQt']
|
|
|
|
|
NoLibGit2 = config['NoLibGit2']
|
|
|
|
|
ToolDebug = config['ToolDebug']
|
|
|
|
|
if 100 not in ToolDebug: # default
|
2024-04-01 10:59:06 +02:00
|
|
|
jump2pymod_wheel = False
|
2023-11-23 07:13:41 +01:00
|
|
|
else:
|
2024-04-01 10:59:06 +02:00
|
|
|
jump2pymod_wheel = True
|
2023-11-23 07:13:41 +01:00
|
|
|
|
2024-07-07 11:47:11 +02:00
|
|
|
#-----------------------------------------------------------------
|
|
|
|
|
# [1] Use the AddressSanitizer (ASan) in the debug build.
|
|
|
|
|
# This environment variable is tested in ../src/klayout.pri.
|
|
|
|
|
#-----------------------------------------------------------------
|
|
|
|
|
try:
|
|
|
|
|
useAsan = os.environ['MAC_USE_ASAN']
|
|
|
|
|
except KeyError:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
del os.environ['MAC_USE_ASAN']
|
|
|
|
|
|
|
|
|
|
if DebugMode:
|
|
|
|
|
os.environ['MAC_USE_ASAN'] = "1"
|
|
|
|
|
|
2023-11-23 07:13:41 +01:00
|
|
|
#-----------------------------------------------------
|
2024-07-07 11:47:11 +02:00
|
|
|
# [2] Set two environment variables to use libgit2
|
2023-11-23 07:13:41 +01:00
|
|
|
#-----------------------------------------------------
|
|
|
|
|
if not NoLibGit2:
|
|
|
|
|
# Using MacPorts
|
|
|
|
|
if ModuleQt.upper() in [ 'QT5MACPORTS', 'QT6MACPORTS' ]:
|
|
|
|
|
addIncPath = "/opt/local/include"
|
|
|
|
|
addLibPath = "/opt/local/lib"
|
|
|
|
|
# Using Homebrew
|
|
|
|
|
elif ModuleQt.upper() in [ 'QT5BREW', 'QT6BREW' ]:
|
|
|
|
|
addIncPath = "%s/include" % DefaultHomebrewRoot # defined in "build4mac_env.py"
|
|
|
|
|
addLibPath = "%s/lib" % DefaultHomebrewRoot # -- ditto --
|
|
|
|
|
# Using Anaconda3
|
|
|
|
|
elif ModuleQt.upper() in [ 'QT5ANA3' ]:
|
|
|
|
|
addIncPath = "/Applications/anaconda3/include"
|
|
|
|
|
addLibPath = "/Applications/anaconda3/lib"
|
|
|
|
|
else:
|
|
|
|
|
addIncPath = ""
|
|
|
|
|
addLibPath = ""
|
|
|
|
|
|
|
|
|
|
# These environment variables are expanded on the fly in ../src/klayout.pri.
|
|
|
|
|
if not addIncPath == "":
|
|
|
|
|
os.environ['MAC_LIBGIT2_INC'] = "%s" % addIncPath
|
|
|
|
|
else:
|
|
|
|
|
os.environ['MAC_LIBGIT2_INC'] = "_invalid_MAC_LIBGIT2_INC_" # compile should fail
|
|
|
|
|
|
|
|
|
|
if not addLibPath == "":
|
|
|
|
|
os.environ['MAC_LIBGIT2_LIB'] = "%s" % addLibPath
|
|
|
|
|
else:
|
|
|
|
|
os.environ['MAC_LIBGIT2_LIB'] = "_invalid_MAC_LIBGIT2_LIB_" # link should fail
|
2022-05-05 22:01:40 +02:00
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
if not jump2pymod_wheel:
|
2022-05-05 22:01:40 +02:00
|
|
|
#-----------------------------------------------------
|
2024-07-07 11:47:11 +02:00
|
|
|
# [3] Set parameters passed to the main Bash script
|
2022-05-05 22:01:40 +02:00
|
|
|
#-----------------------------------------------------
|
|
|
|
|
cmd_args = ""
|
|
|
|
|
|
|
|
|
|
# (A) debug or release
|
|
|
|
|
if parameters["debug_mode"]:
|
|
|
|
|
mode = "debug"
|
|
|
|
|
cmd_args += " -debug"
|
|
|
|
|
else:
|
|
|
|
|
mode = "release"
|
|
|
|
|
cmd_args += " -release"
|
|
|
|
|
|
|
|
|
|
# (C) Target directories and files
|
|
|
|
|
MacBuildDirQAT = parameters['build'] + ".macQAT"
|
|
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
# (D) Qt5 (MacPorts, Homebrew, Anaconda3) | Qt6 (MacPorts, Homebrew)
|
2022-05-05 22:01:40 +02:00
|
|
|
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) want QtUiTools?
|
|
|
|
|
if parameters['no_qt_uitools']:
|
|
|
|
|
cmd_args += " \\\n -without-qt-uitools"
|
|
|
|
|
|
2023-11-23 07:13:41 +01:00
|
|
|
# (G) don't want to use libgit2?
|
|
|
|
|
if NoLibGit2:
|
|
|
|
|
cmd_args += " \\\n -libgit2"
|
|
|
|
|
|
|
|
|
|
# (H) options to `make` tool
|
2022-05-05 22:01:40 +02:00
|
|
|
if 'make_options' in parameters:
|
|
|
|
|
cmd_args += " \\\n -option %s" % parameters['make_options']
|
|
|
|
|
|
2023-11-23 07:13:41 +01:00
|
|
|
# (I) about Ruby
|
2022-05-05 22:01:40 +02:00
|
|
|
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"
|
|
|
|
|
|
2023-11-23 07:13:41 +01:00
|
|
|
# (J) about Python
|
2022-05-05 22:01:40 +02:00
|
|
|
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"
|
|
|
|
|
|
|
|
|
|
#-----------------------------------------------------
|
2024-07-07 11:47:11 +02:00
|
|
|
# [4] Make the consolidated command line
|
2022-05-05 22:01:40 +02:00
|
|
|
#-----------------------------------------------------
|
|
|
|
|
command = "time"
|
|
|
|
|
command += " \\\n %s" % parameters['build_cmd']
|
|
|
|
|
command += cmd_args
|
|
|
|
|
command += " 2>&1 | tee %s; \\\n" % parameters['logfile']
|
|
|
|
|
command += "test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
|
|
|
|
|
|
|
|
|
|
if parameters['check_cmd_only']:
|
|
|
|
|
print(command)
|
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
#-----------------------------------------------------
|
2024-07-07 11:47:11 +02:00
|
|
|
# [5] Invoke the main Bash script; takes time:-)
|
2022-05-05 22:01:40 +02:00
|
|
|
#-----------------------------------------------------
|
|
|
|
|
myscript = os.path.basename(__file__)
|
|
|
|
|
ret = subprocess.call( command, shell=True )
|
|
|
|
|
if ret != 0:
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "!!! <%s>: failed to build KLayout" % myscript, file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
|
|
|
|
print( "### <%s>: successfully built KLayout" % myscript, file=sys.stderr )
|
|
|
|
|
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------
|
2024-07-07 11:47:11 +02:00
|
|
|
# [6] Prepare "*.macQAT/" directory for the QATest.
|
2022-05-05 22:01:40 +02:00
|
|
|
# Binaries under "*.macQAT/" such as *.dylib will be touched later.
|
|
|
|
|
#------------------------------------------------------------------------
|
|
|
|
|
print( "### Preparing <%s>" % MacBuildDirQAT )
|
|
|
|
|
if os.path.isdir( MacBuildDirQAT ):
|
|
|
|
|
shutil.rmtree( MacBuildDirQAT )
|
|
|
|
|
|
|
|
|
|
os.chdir( parameters['build'] )
|
|
|
|
|
tarFile = "../macQATest.tar"
|
|
|
|
|
tarCmdC = "tar cf %s ." % tarFile
|
|
|
|
|
if subprocess.call( tarCmdC, shell=True ) != 0:
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "!!! <%s>: failed to create <%s>" % (myscript, tarFile), file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
os.chdir( "../" )
|
|
|
|
|
os.mkdir( MacBuildDirQAT )
|
|
|
|
|
os.chdir( MacBuildDirQAT )
|
|
|
|
|
tarCmdX = "tar xf %s" % tarFile
|
|
|
|
|
if subprocess.call( tarCmdX, shell=True ) != 0:
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "!!! <%s>: failed to unpack <%s>" % (myscript, tarFile), file=sys.stderr )
|
|
|
|
|
print( "-------------------------------------------------------------", file=sys.stderr )
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
os.remove( tarFile )
|
|
|
|
|
os.chdir( "../" )
|
|
|
|
|
shutil.copy2( "macbuild/macQAT.py", MacBuildDirQAT )
|
|
|
|
|
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
|
|
|
|
print( "### <%s>: prepared the initial *.macQAT/" % myscript, file=sys.stderr )
|
|
|
|
|
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
|
|
|
|
print( "", file=sys.stderr )
|
|
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------
|
2024-07-07 11:47:11 +02:00
|
|
|
# [7] Build <pymod> for some predetermined environments on demand
|
2022-05-05 22:01:40 +02:00
|
|
|
#------------------------------------------------------------------------
|
2024-04-01 10:59:06 +02:00
|
|
|
BuildPymodWhl = parameters['BuildPymodWhl']
|
|
|
|
|
if BuildPymodWhl:
|
|
|
|
|
ret = Build_pymod_wheel(parameters)
|
2022-05-10 20:25:30 +02:00
|
|
|
return ret
|
|
|
|
|
else:
|
|
|
|
|
return 0
|
2022-05-05 22:01:40 +02:00
|
|
|
|
2021-07-17 15:26:55 +02:00
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
|
## For making a bundle (klayout.app), deploy built binaries and libraries
|
|
|
|
|
# on which those binaries depend.
|
|
|
|
|
#
|
|
|
|
|
# Reference: "Deploying an Application on Mac OS X" of Qt Assistant.
|
|
|
|
|
#
|
|
|
|
|
# @param[in] config the build configuration
|
|
|
|
|
# @param[in] parameters the build parameters
|
|
|
|
|
#
|
|
|
|
|
# @return 0 on success; non-zero on failure
|
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
|
def Deploy_Binaries_For_Bundle(config, parameters):
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
# [0] Retrieve the configuration and build parameters
|
|
|
|
|
#-----------------------------------------------------
|
|
|
|
|
NonOSStdLang = config['NonOSStdLang']
|
|
|
|
|
DeploymentF = config['DeploymentF']
|
|
|
|
|
DeploymentP = config['DeploymentP']
|
|
|
|
|
MacPkgDir = config['MacPkgDir']
|
|
|
|
|
Version = config['Version']
|
|
|
|
|
DeployVerbose = config['DeployVerbose']
|
|
|
|
|
ModuleRuby = config['ModuleRuby']
|
|
|
|
|
ModulePython = config['ModulePython']
|
2023-10-04 15:08:11 +02:00
|
|
|
ToolDebug = config['ToolDebug']
|
2024-04-01 10:59:06 +02:00
|
|
|
EmbedQt = config['EmbedQt']
|
|
|
|
|
EmbedPython3 = config['EmbedPython3']
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
BuildPymodWhl = parameters['BuildPymodWhl']
|
2021-07-17 15:26:55 +02:00
|
|
|
ProjectDir = parameters['project_dir']
|
|
|
|
|
MacBinDir = parameters['bin']
|
|
|
|
|
MacBuildDir = parameters['build']
|
|
|
|
|
MacBuildLog = parameters['logfile']
|
2023-07-09 23:47:07 +02:00
|
|
|
Platform = parameters['Platform']
|
2024-04-01 10:59:06 +02:00
|
|
|
QtLibRoot = parameters['qt_lib_root']
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
AbsMacPkgDir = "%s/%s" % (ProjectDir, MacPkgDir)
|
|
|
|
|
AbsMacBinDir = "%s/%s" % (ProjectDir, MacBinDir)
|
|
|
|
|
AbsMacBuildDir = "%s/%s" % (ProjectDir, MacBuildDir)
|
|
|
|
|
AbsMacBuildLog = "%s/%s" % (ProjectDir, MacBuildLog)
|
|
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
if BuildPymodWhl:
|
2022-05-10 20:25:30 +02:00
|
|
|
try:
|
|
|
|
|
PymodDistDir = parameters['pymod_dist']
|
2024-02-16 22:51:08 +01:00
|
|
|
pymodDistDir = PymodDistDir[ModulePython] # [ 'dist-MP3-${ModuleQt}', 'dist-HB3-${ModuleQt}', 'dist-ana3-${ModuleQt}' ]
|
2022-05-10 20:25:30 +02:00
|
|
|
except KeyError:
|
|
|
|
|
pymodDistDir = ""
|
|
|
|
|
else:
|
|
|
|
|
pass
|
2022-05-05 22:01:40 +02:00
|
|
|
else:
|
2022-05-10 20:25:30 +02:00
|
|
|
pymodDistDir = ""
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
print("")
|
|
|
|
|
print( "##### Started deploying libraries and executables for <klayout.app> #####" )
|
|
|
|
|
print( " [1] Checking the status of working directory ..." )
|
|
|
|
|
#-------------------------------------------------------------
|
|
|
|
|
# [1] Check the status of working directory
|
|
|
|
|
#-------------------------------------------------------------
|
|
|
|
|
os.chdir(ProjectDir)
|
|
|
|
|
if not DeploymentF and not DeploymentP:
|
|
|
|
|
return 1
|
|
|
|
|
if DeploymentF and NonOSStdLang:
|
|
|
|
|
print( " WARNING!!! You chose <-y|--deploy> while using non-OS-standard script language.", file=sys.stderr )
|
|
|
|
|
print( " Consider using <-Y|--DEPLOY> instead", file=sys.stderr )
|
|
|
|
|
#return 1
|
|
|
|
|
if not os.path.isfile(MacBuildLog):
|
|
|
|
|
print( "!!! Build log file <%s> is not present !!!" % MacBuildLog, file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
if not os.path.isdir(MacBuildDir):
|
|
|
|
|
print( "!!! Build directory <%s> is not present !!!" % MacBuildDir, file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
if not os.path.isdir(MacBinDir):
|
|
|
|
|
print( "!!! Binary directory <%s> is not present !!!" % MacBinDir, file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print( " [2] Creating a new empty directory <%s> for deployment ..." % MacPkgDir )
|
|
|
|
|
#-------------------------------------------------------------
|
|
|
|
|
# [2] Create a new empty directory for deploying binaries
|
|
|
|
|
#-------------------------------------------------------------
|
|
|
|
|
os.chdir(ProjectDir)
|
|
|
|
|
if os.path.isfile(MacPkgDir):
|
|
|
|
|
os.remove(MacPkgDir)
|
|
|
|
|
if os.path.isdir(MacPkgDir):
|
|
|
|
|
shutil.rmtree(MacPkgDir)
|
|
|
|
|
os.mkdir(MacPkgDir)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print( " [3] Creating the standard directory structure for 'klayout.app' bundle ..." )
|
2022-05-05 22:01:40 +02:00
|
|
|
#--------------------------------------------------------------------------------------------------------------
|
2024-04-01 10:59:06 +02:00
|
|
|
# [3] Create the directory skeleton for "klayout.app" bundle and command line buddy tools such as "strm2cif".
|
2021-07-17 15:26:55 +02:00
|
|
|
# They are stored in the directory structure below.
|
|
|
|
|
#
|
|
|
|
|
# klayout.app/+
|
|
|
|
|
# +-- Contents/+
|
|
|
|
|
# +-- Info.plist
|
|
|
|
|
# +-- PkgInfo
|
|
|
|
|
# +-- Resources/+
|
|
|
|
|
# | +-- 'klayout.icns'
|
|
|
|
|
# +-- Frameworks/+
|
|
|
|
|
# | +-- '*.framework'
|
|
|
|
|
# | +-- '*.dylib'
|
2024-04-01 10:59:06 +02:00
|
|
|
# | +-- 'db_plugins' --sym.link--> ../MacOS/db_plugins/
|
|
|
|
|
# | +-- 'lay_plugins' --sym.link--> ../MacOS/lay_plugins/
|
|
|
|
|
# | +-- 'pymod' --sym.link--> ../MacOS/pymod/
|
2021-07-17 15:26:55 +02:00
|
|
|
# +-- MacOS/+
|
|
|
|
|
# | +-- 'klayout'
|
|
|
|
|
# | +-- db_plugins/
|
|
|
|
|
# | +-- lay_plugins/
|
2023-03-07 23:44:39 +01:00
|
|
|
# | +-- pymod/
|
2024-04-01 10:59:06 +02:00
|
|
|
# |
|
2021-07-17 15:26:55 +02:00
|
|
|
# +-- Buddy/+
|
2022-05-05 22:01:40 +02:00
|
|
|
# | +-- 'strm2cif'
|
|
|
|
|
# | +-- 'strm2dxf'
|
|
|
|
|
# | :
|
|
|
|
|
# | +-- 'strmxor'
|
|
|
|
|
# |
|
2023-11-23 07:13:41 +01:00
|
|
|
# +-- pymod-dist/+ (created only if *.whl is available)
|
2022-05-05 22:01:40 +02:00
|
|
|
# +-- klayout-0.27.8-cp38-cp38-macosx_10_9_x86_64.whl (example)(1)
|
|
|
|
|
#
|
2023-11-23 07:13:41 +01:00
|
|
|
# (1) *.whl is install with 'pip3'
|
2022-05-05 22:01:40 +02:00
|
|
|
#--------------------------------------------------------------------------------------------------------------
|
2021-07-17 15:26:55 +02:00
|
|
|
targetDir0 = "%s/klayout.app/Contents" % AbsMacPkgDir
|
|
|
|
|
targetDirR = targetDir0 + "/Resources"
|
|
|
|
|
targetDirF = targetDir0 + "/Frameworks"
|
|
|
|
|
targetDirM = targetDir0 + "/MacOS"
|
|
|
|
|
targetDirB = targetDir0 + "/Buddy"
|
2022-05-05 22:01:40 +02:00
|
|
|
targetDirP = targetDir0 + "/pymod-dist"
|
2021-07-17 15:26:55 +02:00
|
|
|
os.makedirs(targetDirR)
|
|
|
|
|
os.makedirs(targetDirF)
|
|
|
|
|
os.makedirs(targetDirM)
|
|
|
|
|
os.makedirs(targetDirB)
|
2024-04-01 10:59:06 +02:00
|
|
|
if BuildPymodWhl and not pymodDistDir == "":
|
2022-05-05 22:01:40 +02:00
|
|
|
os.makedirs(targetDirP)
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
print( " [4-1] Copying KLayout's dynamic link libraries to 'Frameworks' ..." )
|
|
|
|
|
#--------------------------------------------------------------------------------------------------------------
|
|
|
|
|
# [4-1] Copy KLayout's dynamic link libraries to "Frameworks/" and create the library dependency dictionary.
|
|
|
|
|
# <<< Do this job in "Frameworks/" >>>
|
2021-07-17 15:26:55 +02:00
|
|
|
#
|
|
|
|
|
# Note:
|
|
|
|
|
# KLayout's dynamic link library is built as below:
|
|
|
|
|
# (1) libklayout_lay.0.26.1.dylib
|
|
|
|
|
# (2) libklayout_lay.0.26.dylib -> libklayout_lay.0.26.1.dylib
|
|
|
|
|
# (3) libklayout_lay.0.dylib -> libklayout_lay.0.26.1.dylib
|
|
|
|
|
# (4) libklayout_lay.dylib -> libklayout_lay.0.26.1.dylib
|
|
|
|
|
# where,
|
|
|
|
|
# (1) is an ordinary file with full version number 'major.minor.teeny'
|
|
|
|
|
# between "library_name."='libklayout_lay.' and '.dylib'
|
|
|
|
|
# (2) is a symbolic link with 'major.minor' version number
|
|
|
|
|
# (3) is a symbolic link with 'major' version number
|
|
|
|
|
# (4) is a symbolic link without version number number
|
|
|
|
|
#
|
|
|
|
|
# The dynamic linker tries to find a library name in style (3) as shown
|
|
|
|
|
# in the example below.
|
|
|
|
|
#
|
|
|
|
|
# Example:
|
|
|
|
|
# MacBookPro2(1)$ otool -L klayout
|
|
|
|
|
# klayout:
|
|
|
|
|
# :
|
|
|
|
|
# :
|
|
|
|
|
# libklayout_tl.0.dylib (compatibility version 0.26.0, current version 0.26.1)
|
|
|
|
|
# libklayout_gsi.0.dylib (compatibility version 0.26.0, current version 0.26.1)
|
|
|
|
|
# libklayout_db.0.dylib (compatibility version 0.26.0, current version 0.26.1)
|
|
|
|
|
# :
|
2024-04-01 10:59:06 +02:00
|
|
|
#--------------------------------------------------------------------------------------------------------------
|
|
|
|
|
os.chdir(targetDirF)
|
|
|
|
|
dynamicLinkLibs = glob.glob( os.path.join( AbsMacBinDir, "*.dylib" ) )
|
|
|
|
|
dependencyDic_1 = dict() # inter-library dependency dictionary
|
|
|
|
|
pathDic_1 = dict() # paths to insert for each library
|
2021-07-17 15:26:55 +02:00
|
|
|
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', '26', '1', 'dylib' ]
|
|
|
|
|
nameStyle3 = fullName[0] + "." + fullName[1] + ".dylib"
|
|
|
|
|
shutil.copy2( item, nameStyle3 )
|
|
|
|
|
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 dylib" % nameStyle3
|
|
|
|
|
otoolOut = os.popen( otoolCm ).read()
|
|
|
|
|
dependDic = DecomposeLibraryDependency(otoolOut)
|
2024-04-01 10:59:06 +02:00
|
|
|
dependencyDic_1.update(dependDic)
|
2021-07-17 15:26:55 +02:00
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
# (C) This library goes into Frameworks, hence record it's path there
|
|
|
|
|
#-------------------------------------------------------------------
|
2024-04-01 10:59:06 +02:00
|
|
|
pathDic_1[nameStyle3] = "@executable_path/../Frameworks/" + nameStyle3
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
if 410 in ToolDebug:
|
|
|
|
|
DumpDependencyDicPair( "In [4-1 410]:", dependencyDic_1, pathDic_1 )
|
|
|
|
|
|
|
|
|
|
print( " [4-2] Copying the contents of the plugins to the place next to the application..." )
|
2021-07-17 15:26:55 +02:00
|
|
|
os.chdir(ProjectDir)
|
2024-04-01 10:59:06 +02:00
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
# (A) 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 ) )
|
2021-07-17 15:26:55 +02:00
|
|
|
dynamicLinkLibs = glob.glob( os.path.join( MacBinDir, piDir, "*.dylib" ) )
|
|
|
|
|
for item in dynamicLinkLibs:
|
|
|
|
|
if os.path.isfile(item) and not os.path.islink(item):
|
|
|
|
|
#-------------------------------------------------------------------
|
2024-04-01 10:59:06 +02:00
|
|
|
# (B) Copy an ordinary *.dylib file here by changing the name
|
2021-07-17 15:26:55 +02:00
|
|
|
# to style (3) and set its mode to 0755 (sanity check).
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
fullName = os.path.basename(item).split('.')
|
|
|
|
|
# e.g. [ 'libklayout_lay', '0', '26', '1', 'dylib' ]
|
|
|
|
|
nameStyle3 = fullName[0] + "." + fullName[1] + ".dylib"
|
2024-04-01 10:59:06 +02:00
|
|
|
destPath = os.path.join( targetDirM, piDir, nameStyle3 )
|
2021-07-17 15:26:55 +02:00
|
|
|
shutil.copy2( item, destPath )
|
|
|
|
|
os.chmod( destPath, 0o0755 )
|
|
|
|
|
#-------------------------------------------------------------------
|
2024-04-01 10:59:06 +02:00
|
|
|
# (C) Then get inter-library dependencies
|
2021-07-17 15:26:55 +02:00
|
|
|
# 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)
|
2024-04-01 10:59:06 +02:00
|
|
|
dependencyDic_1.update(dependDic)
|
2021-07-17 15:26:55 +02:00
|
|
|
#-------------------------------------------------------------------
|
2024-04-01 10:59:06 +02:00
|
|
|
# (D) This library goes into the plugin directory
|
2021-07-17 15:26:55 +02:00
|
|
|
#-------------------------------------------------------------------
|
2024-04-01 10:59:06 +02:00
|
|
|
pathDic_1[nameStyle3] = "@executable_path/" + piDir + "/" + nameStyle3
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
if 420 in ToolDebug:
|
|
|
|
|
DumpDependencyDicPair( "In [4-2 420]:", dependencyDic_1, pathDic_1 )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
print( " [4-3] Making symbolic links from 'Frameworks' to '../MacOS/[db_plugins | lay_plugins | pymod]'..." )
|
|
|
|
|
#--------------------------------------------------------------------------------------------------------------
|
|
|
|
|
# [4-3] Make symbolic links
|
|
|
|
|
# 'db_plugins' --slink--> ../MacOS/db_plugins/
|
|
|
|
|
# 'lay_plugins' --slink--> ../MacOS/lay_plugins/
|
|
|
|
|
# 'pymod' --slink--> ../MacOS/pymod/
|
|
|
|
|
# under Frameworks/.
|
2021-07-17 15:26:55 +02:00
|
|
|
#
|
2024-04-01 10:59:06 +02:00
|
|
|
# 'db_plugins' is required for the command line Buddy tools.
|
|
|
|
|
# Ref. https://github.com/KLayout/klayout/issues/460#issuecomment-571803458
|
2021-07-17 15:26:55 +02:00
|
|
|
#
|
|
|
|
|
# :
|
|
|
|
|
# +-- Frameworks/+
|
|
|
|
|
# | +-- '*.framework'
|
|
|
|
|
# | +-- '*.dylib'
|
2024-04-01 10:59:06 +02:00
|
|
|
# | +-- 'db_plugins' --sym.link--> ../MacOS/db_plugins/
|
|
|
|
|
# | +-- 'lay_plugins' --sym.link--> ../MacOS/lay_plugins/
|
|
|
|
|
# | +-- 'pymod' --sym.link--> ../MacOS/pymod/
|
2021-07-17 15:26:55 +02:00
|
|
|
# +-- MacOS/+
|
|
|
|
|
# | +-- 'klayout'
|
|
|
|
|
# | +-- db_plugins/
|
|
|
|
|
# | +-- lay_plugins/
|
2023-03-07 23:44:39 +01:00
|
|
|
# | +-- pymod/
|
2021-07-17 15:26:55 +02:00
|
|
|
# :
|
2024-04-01 10:59:06 +02:00
|
|
|
#--------------------------------------------------------------------------------------------------------------
|
|
|
|
|
os.chdir(targetDirF)
|
|
|
|
|
os.symlink( "../MacOS/db_plugins/", "./db_plugins" )
|
|
|
|
|
os.symlink( "../MacOS/lay_plugins/", "./lay_plugins" )
|
|
|
|
|
os.symlink( "../MacOS/pymod/", "./pymod" )
|
|
|
|
|
|
|
|
|
|
print( " [4-4] Deeply copying 'pymod/*' to 'MacOS/pymod/*'..." )
|
|
|
|
|
#--------------------------------------------------------------------------------------------------------------
|
|
|
|
|
# [4-4] Deeply copy the 'pymod' directory's contents, if any
|
|
|
|
|
# :
|
|
|
|
|
# +-- Frameworks/+
|
|
|
|
|
# | +-- '*.framework'
|
|
|
|
|
# | +-- '*.dylib'
|
|
|
|
|
# | +-- 'db_plugins' --sym.link--> ../MacOS/db_plugins/
|
|
|
|
|
# | +-- 'lay_plugins' --sym.link--> ../MacOS/lay_plugins/
|
|
|
|
|
# | +-- 'pymod' --sym.link--> ../MacOS/pymod/
|
|
|
|
|
# +-- MacOS/+
|
|
|
|
|
# | +-- 'klayout'
|
|
|
|
|
# | +-- db_plugins/
|
|
|
|
|
# | +-- lay_plugins/
|
|
|
|
|
# | +-- pymod/+
|
|
|
|
|
# | +-- klayout/+
|
|
|
|
|
# | +-- (*)
|
|
|
|
|
# | +-- pya/+
|
|
|
|
|
# | +-- __init__.py
|
|
|
|
|
# :
|
|
|
|
|
# (*) Example
|
|
|
|
|
# -rwxr-xr-x ... QtCore.cpython-311-darwin.so --- (+)
|
|
|
|
|
# -rwxr-xr-x ... QtDesigner.cpython-311-darwin.so
|
|
|
|
|
# -rwxr-xr-x ... QtGui.cpython-311-darwin.so
|
|
|
|
|
# -rwxr-xr-x ... QtMultimedia.cpython-311-darwin.so
|
|
|
|
|
# -rwxr-xr-x ... QtNetwork.cpython-311-darwin.so
|
|
|
|
|
# -rwxr-xr-x ... QtPrintSupport.cpython-311-darwin.so
|
|
|
|
|
# -rwxr-xr-x ... QtSql.cpython-311-darwin.so
|
|
|
|
|
# -rwxr-xr-x ... QtSvg.cpython-311-darwin.so
|
|
|
|
|
# -rwxr-xr-x ... QtUiTools.cpython-311-darwin.so
|
|
|
|
|
# -rwxr-xr-x ... QtWidgets.cpython-311-darwin.so
|
|
|
|
|
# -rwxr-xr-x ... QtXml.cpython-311-darwin.so
|
|
|
|
|
# -rwxr-xr-x ... QtXmlPatterns.cpython-311-darwin.so
|
|
|
|
|
# -rwxr-xr-x ... __init__.py
|
|
|
|
|
# drwxr-xr-x ... __pycache__
|
|
|
|
|
# drwxr-xr-x ... db
|
|
|
|
|
# -rwxr-xr-x ... dbcore.cpython-311-darwin.so
|
|
|
|
|
# drwxr-xr-x ... lay
|
|
|
|
|
# -rwxr-xr-x ... laycore.cpython-311-darwin.so
|
|
|
|
|
# drwxr-xr-x ... lib
|
|
|
|
|
# -rwxr-xr-x ... libcore.cpython-311-darwin.so
|
|
|
|
|
# drwxr-xr-x ... pya
|
|
|
|
|
# -rwxr-xr-x ... pyacore.cpython-311-darwin.so
|
|
|
|
|
# drwxr-xr-x ... rdb
|
|
|
|
|
# -rwxr-xr-x ... rdbcore.cpython-311-darwin.so
|
|
|
|
|
# drwxr-xr-x ... tl
|
|
|
|
|
# -rwxr-xr-x ... tlcore.cpython-311-darwin.so
|
|
|
|
|
#
|
|
|
|
|
#--------------------------------------------------------------------------------------------------------------
|
|
|
|
|
# (+) Example of the inter-library dependency of pymod's library
|
|
|
|
|
#
|
|
|
|
|
# % otool -L QtCore.cpython-311-darwin.so
|
|
|
|
|
#
|
|
|
|
|
# QtCore.cpython-311-darwin.so:
|
|
|
|
|
# libQtCore.0.dylib (compatibility version 0.28.0, current version 0.28.17)
|
|
|
|
|
# /opt/local/lib/libgit2.1.7.dylib (compatibility version 1.7.0, current version 1.7.2)
|
|
|
|
|
# /opt/local/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.3.1)
|
|
|
|
|
# /usr/local/opt/python@3.11/Frameworks/Python.framework/Versions/3.11/Python (compatibility...)
|
|
|
|
|
# libklayout_tl.0.dylib (compatibility version 0.28.0, current version 0.28.17)
|
|
|
|
|
# libklayout_gsi.0.dylib (compatibility version 0.28.0, current version 0.28.17)
|
|
|
|
|
# libklayout_pya.0.dylib (compatibility version 0.28.0, current version 0.28.17)
|
|
|
|
|
# libklayout_QtCore.0.dylib (compatibility version 0.28.0, current version 0.28.17)
|
|
|
|
|
# libklayout_QtGui.0.dylib (compatibility version 0.28.0, current version 0.28.17)
|
|
|
|
|
# libklayout_QtWidgets.0.dylib (compatibility version 0.28.0, current version 0.28.17)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtPrintSupport.framework/Versions/5/QtPrintSupport (compatibility...)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtDesigner.framework/Versions/5/QtDesigner (compatibility...)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtMultimediaWidgets.framework/Versions/5/QtMultimediaWidgets (compatibility...)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtSvg.framework/Versions/5/QtSvg (compatibility...)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtWidgets.framework/Versions/5/QtWidgets (compatibility...)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtMultimedia.framework/Versions/5/QtMultimedia (compatibility...)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtGui.framework/Versions/5/QtGui (compatibility...)
|
|
|
|
|
# /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility...)
|
|
|
|
|
# /System/Library/Frameworks/Metal.framework/Versions/A/Metal (compatibility...)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtXml.framework/Versions/5/QtXml (compatibility...)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtXmlPatterns.framework/Versions/5/QtXmlPatterns (compatibility...)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtNetwork.framework/Versions/5/QtNetwork (compatibility...)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtSql.framework/Versions/5/QtSql (compatibility...)
|
|
|
|
|
# /opt/local/libexec/qt5/lib/QtCore.framework/Versions/5/QtCore (compatibility...)
|
|
|
|
|
# /System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration (compatibility...)
|
|
|
|
|
# /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility...)
|
|
|
|
|
# /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility...)
|
|
|
|
|
# /System/Library/Frameworks/AGL.framework/Versions/A/AGL (compatibility...)
|
|
|
|
|
# /usr/lib/libc++.1.dylib (compatibility...)
|
|
|
|
|
# /usr/lib/libSystem.B.dylib (compatibility...)
|
|
|
|
|
#--------------------------------------------------------------------------------------------------------------
|
|
|
|
|
os.chdir(AbsMacBinDir)
|
|
|
|
|
sourceDirKly = "pymod/klayout"
|
|
|
|
|
sourdeDirPya = "pymod/pya"
|
|
|
|
|
pymodDirInBin = os.path.isdir(sourceDirKly) and os.path.isdir(sourdeDirPya)
|
|
|
|
|
dependencyDic_2 = dict() # inter-library dependency dictionary
|
|
|
|
|
pathDic_2 = dict() # paths to insert for each library
|
|
|
|
|
dependencyDic_3 = dict() # inter-library dependency dictionary
|
|
|
|
|
pathDic_3 = dict() # paths to insert for each library
|
|
|
|
|
dependencyDic_4 = dict() # inter-library dependency dictionary
|
|
|
|
|
pathDic_4 = dict() # paths to insert for each library
|
|
|
|
|
|
|
|
|
|
if pymodDirInBin:
|
|
|
|
|
targetDirKly = os.path.join(targetDirM, sourceDirKly)
|
|
|
|
|
targetDirPya = os.path.join(targetDirM, sourdeDirPya)
|
|
|
|
|
|
|
|
|
|
retK = Deeply_Copy_Dir( sourceDirKly, targetDirKly, excl_pat_list=["__pycache__"] )
|
|
|
|
|
retP = Deeply_Copy_Dir( sourdeDirPya, targetDirPya, excl_pat_list=["__pycache__"] )
|
|
|
|
|
if not (retK and retP):
|
|
|
|
|
msg = "!!! Failed to deeply copy the 'pymod' directory's contents !!!"
|
|
|
|
|
print(msg)
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
# <<< Do the remaining job in "MacOS/pymod/klayout/" >>>
|
|
|
|
|
os.chdir(targetDirKly)
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
# (A) Prepare regular expressions for the library name-matching
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
# (1) KLayout's self libraries
|
|
|
|
|
patSelf = r'^(lib.+[.]dylib)'
|
|
|
|
|
regSelf = re.compile(patSelf)
|
|
|
|
|
|
|
|
|
|
# (2) Auxiliary libraries such as 'libgit2.1.7.dylib'
|
|
|
|
|
libAux_1 = "/opt/local/lib/"
|
|
|
|
|
libAux_2 = "/usr/local/lib/"
|
|
|
|
|
libAux_3 = "/opt/homebrew/lib/"
|
|
|
|
|
libAux_4 = "/Applications/anaconda3/lib/"
|
|
|
|
|
patAux = r'^(%s|%s|%s|%s)(lib.+[.]dylib)' % (libAux_1, libAux_2, libAux_3, libAux_4)
|
|
|
|
|
regAux = re.compile(patAux)
|
|
|
|
|
|
|
|
|
|
# (3) Qt frameworks
|
|
|
|
|
# QtLibRoot:
|
|
|
|
|
# MacPorts ===> '/opt/local/libexec/qt5/lib'
|
|
|
|
|
# Homebrew ===> '/usr/local/opt/qt@5/lib'
|
|
|
|
|
# Anaconda3 ===> '/Applications/anaconda3/lib' (not frameworks and won't be embedded)
|
|
|
|
|
patQt = r'(%s/)(Qt.+[.]framework.+)' % QtLibRoot
|
|
|
|
|
regQt = re.compile(patQt)
|
|
|
|
|
|
|
|
|
|
# (4) Python frameworks (only for Homebrew) # in the case of Intel Mac...
|
2024-09-23 23:36:16 +02:00
|
|
|
libPy3_1 = "%s/" % HBPython312FrameworkPath # /usr/local/opt/python@3.12/Frameworks/Python.framework/
|
|
|
|
|
libPy3_2 = "%s/" % HBPython311FrameworkPath # /usr/local/opt/python@3.11/Frameworks/Python.framework/
|
2024-04-01 10:59:06 +02:00
|
|
|
patPy3 = r'^(%s|%s)(.+)' % (libPy3_1, libPy3_2)
|
|
|
|
|
regPy3 = re.compile(patPy3)
|
|
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
# (B) Copy the contents of the pymod/klayout/ directory to the place next to
|
|
|
|
|
# the main application executable
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
dynamicLinkLibs = glob.glob( os.path.join( targetDirM, sourceDirKly, "*.so" ) )
|
|
|
|
|
for item in dynamicLinkLibs:
|
|
|
|
|
if os.path.isfile(item) and not os.path.islink(item):
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
# (C) Copy an ordinary *.dylib file here by changing the name
|
|
|
|
|
# to style (3) and set its mode to 0755 (sanity check).
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
baseName = os.path.basename(item) # 'QtCore.cpython-311-darwin.so'
|
|
|
|
|
fullName = os.path.basename(item).split('.') # [ 'QtCore', 'cpython-311-darwin', 'so' ]
|
|
|
|
|
nameStyle3 = fullName[0] + "." + fullName[1] + ".so" # == fullName; no need to change!
|
|
|
|
|
destPath = os.path.join( targetDirM, sourceDirKly, nameStyle3 )
|
|
|
|
|
# shutil.copy2( item, destPath ) # already deeply copied!
|
|
|
|
|
os.chmod( destPath, 0o0755 ) # just for confirmation
|
|
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
# (D) Then get inter-library dependencies
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
otoolCm = "otool -L %s" % destPath
|
|
|
|
|
otoolOut = os.popen( otoolCm ).read()
|
|
|
|
|
dependDic = DecomposeLibraryDependency(otoolOut)
|
|
|
|
|
dicKey = list(dependDic.keys())[0]
|
|
|
|
|
dicVal = dependDic[dicKey]
|
|
|
|
|
dicValIdx = list( range(0, len(dicVal)) )
|
|
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
# (E) Dependencies on KLayout's self libraries (always)
|
|
|
|
|
# Populate 'dependencyDic_2' and 'pathDic_2'
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
if True:
|
|
|
|
|
dependLib_2 = dict()
|
|
|
|
|
for idx in dicValIdx:
|
|
|
|
|
fname = dicVal[idx]
|
|
|
|
|
if regSelf.match(fname):
|
|
|
|
|
if idx == 0:
|
|
|
|
|
dependLib_2[baseName] = baseName
|
|
|
|
|
else:
|
|
|
|
|
dependLib_2[fname] = fname
|
|
|
|
|
|
|
|
|
|
dependencyDic_2.update( {dicKey: dependLib_2} )
|
|
|
|
|
pathDic_2[nameStyle3] = "@executable_path/" + sourceDirKly + "/" + nameStyle3
|
|
|
|
|
|
|
|
|
|
for libname in dependLib_2.keys():
|
|
|
|
|
if libname == baseName:
|
|
|
|
|
continue
|
|
|
|
|
else:
|
|
|
|
|
pathDic_2[libname] = "@executable_path/../Frameworks/" + dependLib_2[libname]
|
|
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
# (F) Dependencies on Qt and auxiliary libraries (optional)
|
|
|
|
|
# Populate 'dependencyDic_3' and 'pathDic_3'
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
if EmbedQt:
|
|
|
|
|
dependLib_3 = dict()
|
|
|
|
|
for idx in dicValIdx:
|
|
|
|
|
fname = dicVal[idx]
|
|
|
|
|
if regAux.match(fname):
|
|
|
|
|
dependLib_3[fname] = regAux.match(fname).groups()[1]
|
|
|
|
|
elif regQt.match(fname):
|
|
|
|
|
dependLib_3[fname] = regQt.match(fname).groups()[1]
|
|
|
|
|
|
|
|
|
|
dependencyDic_3.update( {dicKey: dependLib_3} )
|
|
|
|
|
pathDic_3[nameStyle3] = "@executable_path/" + sourceDirKly + "/" + nameStyle3
|
|
|
|
|
|
|
|
|
|
for libname in dependLib_3.keys():
|
|
|
|
|
if libname == baseName:
|
|
|
|
|
continue
|
|
|
|
|
else:
|
|
|
|
|
pathDic_3[libname] = "@executable_path/../Frameworks/" + dependLib_3[libname]
|
|
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
# (G) Dependencies on Python framework (optional)
|
|
|
|
|
# Populate 'dependencyDic_4' and 'pathDic_4'
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
|
if EmbedPython3:
|
|
|
|
|
dependLib_4 = dict()
|
|
|
|
|
for idx in dicValIdx:
|
|
|
|
|
fname = dicVal[idx]
|
|
|
|
|
if regPy3.match(fname):
|
|
|
|
|
dependLib_4[fname] = "Python.framework/%s" % regPy3.match(fname).groups()[1]
|
|
|
|
|
|
|
|
|
|
dependencyDic_4.update( {dicKey: dependLib_4} )
|
|
|
|
|
pathDic_4[nameStyle3] = "@executable_path/" + sourceDirKly + "/" + nameStyle3
|
|
|
|
|
|
|
|
|
|
for libname in dependLib_4.keys():
|
|
|
|
|
if libname == baseName:
|
|
|
|
|
continue
|
|
|
|
|
else:
|
|
|
|
|
pathDic_4[libname] = "@executable_path/../Frameworks/" + dependLib_4[libname]
|
|
|
|
|
|
|
|
|
|
if 441 in ToolDebug:
|
|
|
|
|
DumpDependencyDicPair( "In [4-4 441]:", dependencyDic_2, pathDic_2 )
|
|
|
|
|
|
|
|
|
|
if 442 in ToolDebug:
|
|
|
|
|
DumpDependencyDicPair( "In [4-4 442]:", dependencyDic_3, pathDic_3 )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
if 443 in ToolDebug:
|
|
|
|
|
DumpDependencyDicPair( "In [4-4 443]:", dependencyDic_4, pathDic_4 )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
print( " [5-1] Setting and changing the identification names among KLayout's libraries ..." )
|
2021-07-17 15:26:55 +02:00
|
|
|
#-------------------------------------------------------------
|
2024-04-01 10:59:06 +02:00
|
|
|
# [5-1] Set the identification names for KLayout's libraries
|
2021-07-17 15:26:55 +02:00
|
|
|
# and make the library aware of the locations of libraries
|
|
|
|
|
# on which it depends; that is, inter-library dependency
|
|
|
|
|
#-------------------------------------------------------------
|
2024-04-01 10:59:06 +02:00
|
|
|
os.chdir(targetDirF)
|
|
|
|
|
ret = SetChangeIdentificationNameOfDyLib( dependencyDic_1, pathDic_1 )
|
2021-07-17 15:26:55 +02:00
|
|
|
if not ret == 0:
|
2024-04-01 10:59:06 +02:00
|
|
|
msg = "!!! Failed to set and change to new identification names with (dependencyDic_1, pathDic_1) !!!"
|
2021-07-17 15:26:55 +02:00
|
|
|
print(msg)
|
|
|
|
|
return 1
|
|
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
print( " [5-2] Setting and changing the identification names among pymod's libraries ..." )
|
|
|
|
|
#-------------------------------------------------------------
|
|
|
|
|
# [5-2] Similarly for the pymod's libraries...
|
|
|
|
|
#-------------------------------------------------------------
|
|
|
|
|
if not targetDirKly == None:
|
|
|
|
|
os.chdir(targetDirKly)
|
|
|
|
|
if len(dependencyDic_2) > 0 and len(pathDic_2) > 0:
|
|
|
|
|
ret = SetChangeIdentificationNameOfDyLib( dependencyDic_2, pathDic_2 )
|
|
|
|
|
if not ret == 0:
|
|
|
|
|
msg = "!!! Failed to set and change to new identification names with (dependencyDic_2, pathDic_2) !!!"
|
|
|
|
|
print(msg)
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
if len(dependencyDic_3) > 0 and len(pathDic_3) > 0:
|
|
|
|
|
ret = SetChangeIdentificationNameOfDyLib( dependencyDic_3, pathDic_3 )
|
|
|
|
|
if not ret == 0:
|
|
|
|
|
msg = "!!! Failed to set and change to new identification names with (dependencyDic_3, pathDic_3) !!!"
|
|
|
|
|
print(msg)
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
if len(dependencyDic_4) > 0 and len(pathDic_4) > 0:
|
|
|
|
|
ret = SetChangeIdentificationNameOfDyLib( dependencyDic_4, pathDic_4 )
|
|
|
|
|
if not ret == 0:
|
|
|
|
|
msg = "!!! Failed to set and change to new identification names with (dependencyDic_4, pathDic_4) !!!"
|
|
|
|
|
print(msg)
|
|
|
|
|
return 1
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2024-04-01 10:59:06 +02:00
|
|
|
print( " [6] Copying the built executables and resource files ..." )
|
2021-07-17 15:26:55 +02:00
|
|
|
#-------------------------------------------------------------
|
|
|
|
|
# [6] Copy some known files in source directories to
|
|
|
|
|
# relevant target directories
|
|
|
|
|
#-------------------------------------------------------------
|
|
|
|
|
os.chdir(ProjectDir)
|
|
|
|
|
sourceDir0 = "%s/klayout.app/Contents" % MacBinDir
|
|
|
|
|
sourceDir1 = sourceDir0 + "/MacOS"
|
|
|
|
|
sourceDir2 = "%s/macbuild/Resources" % ProjectDir
|
|
|
|
|
sourceDir3 = "%s" % MacBinDir
|
|
|
|
|
|
2022-05-05 22:01:40 +02:00
|
|
|
# (A) the main components
|
2021-07-17 15:26:55 +02:00
|
|
|
tmpfileM = ProjectDir + "/macbuild/Resources/Info.plist.template"
|
|
|
|
|
keydicM = { 'exe': 'klayout', 'icon': 'klayout.icns', 'bname': 'klayout', 'ver': Version }
|
|
|
|
|
plistM = GenerateInfoPlist( keydicM, tmpfileM )
|
2024-04-01 10:59:06 +02:00
|
|
|
with open( targetDir0 + "/Info.plist", "w" ) as file:
|
|
|
|
|
file.write(plistM)
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
shutil.copy2( sourceDir0 + "/PkgInfo", targetDir0 ) # this file is not mandatory
|
|
|
|
|
shutil.copy2( sourceDir1 + "/klayout", targetDirM )
|
|
|
|
|
shutil.copy2( sourceDir2 + "/klayout.icns", targetDirR )
|
|
|
|
|
|
|
|
|
|
os.chmod( targetDir0 + "/PkgInfo", 0o0644 )
|
|
|
|
|
os.chmod( targetDir0 + "/Info.plist", 0o0644 )
|
|
|
|
|
os.chmod( targetDirM + "/klayout", 0o0755 )
|
|
|
|
|
os.chmod( targetDirR + "/klayout.icns", 0o0644 )
|
|
|
|
|
|
2022-05-05 22:01:40 +02:00
|
|
|
# (B) the buddy command line tools
|
2021-07-17 15:26:55 +02:00
|
|
|
buddies = glob.glob( sourceDir3 + "/strm*" )
|
|
|
|
|
for item in buddies:
|
|
|
|
|
shutil.copy2( item, targetDirB )
|
|
|
|
|
buddy = os.path.basename(item)
|
|
|
|
|
os.chmod( targetDirB + "/" + buddy, 0o0755 )
|
|
|
|
|
|
2022-05-10 20:25:30 +02:00
|
|
|
# (C) the Pymod
|
2024-04-01 10:59:06 +02:00
|
|
|
if BuildPymodWhl and not pymodDistDir == "":
|
2022-05-05 22:01:40 +02:00
|
|
|
for item in glob.glob( pymodDistDir + "/*.whl" ):
|
|
|
|
|
shutil.copy2( item, targetDirP )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
print( " [7] Setting and changing the identification names of KLayout's libraries in each executable ..." )
|
2023-10-04 15:08:11 +02:00
|
|
|
#------------------------------------------------------------------------------------
|
|
|
|
|
# [7] Set and change the library identification name(s) of different executable(s)
|
|
|
|
|
#------------------------------------------------------------------------------------
|
2021-07-17 15:26:55 +02:00
|
|
|
os.chdir(ProjectDir)
|
|
|
|
|
os.chdir(MacPkgDir)
|
|
|
|
|
klayoutexec = "klayout.app/Contents/MacOS/klayout"
|
|
|
|
|
ret = SetChangeLibIdentificationName( klayoutexec, "../Frameworks" )
|
|
|
|
|
if not ret == 0:
|
|
|
|
|
os.chdir(ProjectDir)
|
|
|
|
|
msg = "!!! Failed to set/change library identification name for <%s> !!!"
|
|
|
|
|
print( msg % klayoutexec, file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
buddies = glob.glob( "klayout.app/Contents/Buddy/strm*" )
|
|
|
|
|
macdepQtOpt = ""
|
|
|
|
|
for buddy in buddies:
|
|
|
|
|
macdepQtOpt += " -executable=%s" % buddy
|
|
|
|
|
ret = SetChangeLibIdentificationName( buddy, "../Frameworks" )
|
|
|
|
|
if not ret == 0:
|
|
|
|
|
os.chdir(ProjectDir)
|
|
|
|
|
msg = "!!! Failed to set/change library identification name for <%s> !!!"
|
|
|
|
|
print( msg % buddy, file=sys.stderr )
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
if DeploymentF:
|
2024-04-01 10:59:06 +02:00
|
|
|
print( " [8] Finally, deploying Qt's Frameworks and auxiliary libraries ..." )
|
2021-07-17 15:26:55 +02:00
|
|
|
#-------------------------------------------------------------
|
|
|
|
|
# [8] Deploy Qt Frameworks
|
|
|
|
|
#-------------------------------------------------------------
|
2023-10-04 15:08:11 +02:00
|
|
|
verbose = " -verbose=%d" % DeployVerbose
|
2021-07-17 15:26:55 +02:00
|
|
|
app_bundle = "klayout.app"
|
2023-10-04 15:08:11 +02:00
|
|
|
options = macdepQtOpt + verbose
|
2021-07-17 15:26:55 +02:00
|
|
|
deploytool = parameters['deploy_tool']
|
|
|
|
|
|
|
|
|
|
# Without the following, the plugin cocoa would not be found properly.
|
|
|
|
|
shutil.copy2( sourceDir2 + "/qt.conf", targetDirM )
|
2023-10-04 15:08:11 +02:00
|
|
|
os.chmod( targetDirM + "/qt.conf", 0o0644 )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
os.chdir(ProjectDir)
|
|
|
|
|
os.chdir(MacPkgDir)
|
|
|
|
|
command = "%s %s %s" % ( deploytool, app_bundle, options )
|
|
|
|
|
if subprocess.call( command, shell=True ) != 0:
|
|
|
|
|
msg = "!!! Failed to deploy applications on OSX/macOS !!!"
|
|
|
|
|
print( msg, file=sys.stderr )
|
|
|
|
|
print("")
|
|
|
|
|
os.chdir(ProjectDir)
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
#-----------------------------------------------------------------------------------------------
|
2024-09-23 23:36:16 +02:00
|
|
|
# [9] Special deployment of Python3.11 from Homebrew
|
|
|
|
|
# To use Python3.1 from Homebrew on Sonoma...
|
|
|
|
|
# in "/usr/local/opt/python@3.11/lib/"
|
2021-07-17 15:26:55 +02:00
|
|
|
# Python.framework -> ../Frameworks/Python.framework/ <=== this symbolic was needed
|
|
|
|
|
# pkgconfig/
|
2022-12-17 05:42:08 +01:00
|
|
|
#
|
|
|
|
|
# Use the "python3HB.py" tool to make different symbolic links [*] including the above one.
|
2024-09-23 23:36:16 +02:00
|
|
|
# Sonoma{kazzz-s} lib (1)% pwd
|
|
|
|
|
# /usr/local/opt/python@3.11/lib
|
|
|
|
|
# Sonoma{kazzz-s} lib (2)% ll
|
2022-12-17 05:42:08 +01:00
|
|
|
# total 0
|
2024-09-23 23:36:16 +02:00
|
|
|
# drwxr-xr-x 4 kazzz-s admin 128 9 21 23:03 .
|
|
|
|
|
# drwxr-xr-x 14 kazzz-s admin 448 9 21 18:33 ..
|
|
|
|
|
# [*] lrwxr-xr-x 1 kazzz-s admin 31 9 21 23:03 Python.framework -> ../Frameworks/Python.framework/
|
|
|
|
|
# drwxr-xr-x 4 kazzz-s admin 128 9 7 10:03 pkgconfig
|
2022-12-17 05:42:08 +01:00
|
|
|
#
|
2024-09-23 23:36:16 +02:00
|
|
|
# Sonoma{kazzz-s} Python.framework (3)% pwd
|
|
|
|
|
# /usr/local/opt/python@3.11/Frameworks/Python.framework/Versions
|
|
|
|
|
# Sonoma{kazzz-s} Versions (4)% ll
|
2022-12-17 05:42:08 +01:00
|
|
|
# total 0
|
2024-09-23 23:36:16 +02:00
|
|
|
# drwxr-xr-x 4 kazzz-s admin 128 9 21 23:03 .
|
|
|
|
|
# drwxr-xr-x 6 kazzz-s admin 192 9 21 23:03 ..
|
|
|
|
|
# drwxr-xr-x 9 kazzz-s admin 288 9 7 10:03 3.11
|
|
|
|
|
# [*] lrwxr-xr-x 1 kazzz-s admin 5 9 21 23:03 Current -> 3.11/
|
2022-12-17 05:42:08 +01:00
|
|
|
#
|
2024-09-23 23:36:16 +02:00
|
|
|
# Sonoma{kazzz-s} Python.framework (5)% pwd
|
|
|
|
|
# /usr/local/opt/python@3.11/Frameworks/Python.framework
|
|
|
|
|
# Sonoma{kazzz-s} Python.framework (6)% ll
|
2022-12-17 05:42:08 +01:00
|
|
|
# total 0
|
2024-09-23 23:36:16 +02:00
|
|
|
# drwxr-xr-x 6 kazzz-s admin 192 9 21 23:03 .
|
|
|
|
|
# drwxr-xr-x 3 kazzz-s admin 96 9 7 10:03 ..
|
|
|
|
|
# [*] lrwxr-xr-x 1 kazzz-s admin 25 9 21 23:03 Headers -> Versions/Current/Headers/
|
|
|
|
|
# [*] lrwxr-xr-x 1 kazzz-s admin 23 9 21 23:03 Python -> Versions/Current/Python
|
|
|
|
|
# [*] lrwxr-xr-x 1 kazzz-s admin 27 9 21 23:03 Resources -> Versions/Current/Resources/
|
|
|
|
|
# drwxr-xr-x 4 kazzz-s admin 128 9 21 23:03 Versions
|
2021-07-17 15:26:55 +02:00
|
|
|
#-----------------------------------------------------------------------------------------------
|
2023-11-23 07:13:41 +01:00
|
|
|
deploymentPython311HB = (ModulePython == 'Python311Brew')
|
2021-07-17 15:26:55 +02:00
|
|
|
deploymentPythonAutoHB = (ModulePython == 'PythonAutoBrew')
|
2024-09-23 23:36:16 +02:00
|
|
|
if (deploymentPython311HB or deploymentPythonAutoHB) and NonOSStdLang:
|
2023-10-04 15:08:11 +02:00
|
|
|
# from build4mac_util import WalkFrameworkPaths, PerformChanges
|
|
|
|
|
# from build4mac_util import Change_Python_LibPath_RelativeToAbsolute, DumpDependencyDic
|
2023-11-23 07:13:41 +01:00
|
|
|
if deploymentPython311HB:
|
|
|
|
|
HBPythonFrameworkPath = HBPython311FrameworkPath
|
2024-09-23 23:36:16 +02:00
|
|
|
pythonHBVer = "3.11" # required to provide the legacy pip in HW-*.dmg
|
2021-07-17 15:26:55 +02:00
|
|
|
elif deploymentPythonAutoHB:
|
|
|
|
|
HBPythonFrameworkPath = HBPythonAutoFrameworkPath
|
|
|
|
|
pythonHBVer = HBPythonAutoVersion
|
|
|
|
|
|
|
|
|
|
bundlePath = AbsMacPkgDir + '/klayout.app'
|
|
|
|
|
bundleExecPathAbs = '%s/Contents/MacOS/' % bundlePath
|
|
|
|
|
pythonFrameworkPath = '%s/Contents/Frameworks/Python.framework' % bundlePath
|
|
|
|
|
testTarget = '%s/Versions/%s/lib/python%s/test' % (pythonFrameworkPath, pythonHBVer, pythonHBVer)
|
|
|
|
|
resourceTarget1 = '%s/Versions/%s/Resources' % (pythonFrameworkPath, pythonHBVer)
|
|
|
|
|
resourceTarget2 = '%s/Resources' % pythonFrameworkPath
|
|
|
|
|
binTarget = '%s/Versions/%s/bin' % (pythonFrameworkPath, pythonHBVer)
|
|
|
|
|
sitepackagesTarget = '%s/Versions/%s/lib/python%s/site-packages' % (pythonFrameworkPath, pythonHBVer, pythonHBVer)
|
|
|
|
|
sitepackagesSource = '%s/Versions/%s/lib/python%s/site-packages' % (HBPythonFrameworkPath, pythonHBVer, pythonHBVer)
|
|
|
|
|
|
|
|
|
|
print( "" )
|
|
|
|
|
print( " [9] Optional deployment of Python from %s ..." % HBPythonFrameworkPath )
|
|
|
|
|
print( " [9.1] Copying Python Framework" )
|
2023-10-04 15:08:11 +02:00
|
|
|
if 910 in ToolDebug:
|
|
|
|
|
dbglevel = 910
|
|
|
|
|
else:
|
|
|
|
|
dbglevel = 0
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
cmd01 = "rm -rf %s" % pythonFrameworkPath
|
|
|
|
|
cmd02 = "rsync -a --safe-links %s/ %s" % (HBPythonFrameworkPath, pythonFrameworkPath)
|
|
|
|
|
|
|
|
|
|
cmd03 = "rm -rf %s" % testTarget
|
|
|
|
|
cmd04 = "rm -rf %s" % resourceTarget1
|
|
|
|
|
cmd05 = "unlink %s" % resourceTarget2
|
|
|
|
|
cmd06 = "rm -rf %s" % binTarget
|
|
|
|
|
|
|
|
|
|
cmd07 = "mkdir %s" % sitepackagesTarget
|
2021-11-15 22:38:47 +01:00
|
|
|
cmd08 = "cp -RL %s/{*distutils*,pip*,pkg_resources,setuptools*,wheel*} %s" % (sitepackagesSource, sitepackagesTarget)
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
shell_commands = list()
|
|
|
|
|
shell_commands.append(cmd01)
|
|
|
|
|
shell_commands.append(cmd02)
|
|
|
|
|
shell_commands.append(cmd03)
|
|
|
|
|
shell_commands.append(cmd04)
|
|
|
|
|
shell_commands.append(cmd05)
|
|
|
|
|
shell_commands.append(cmd06)
|
|
|
|
|
shell_commands.append(cmd07)
|
|
|
|
|
shell_commands.append(cmd08)
|
|
|
|
|
|
|
|
|
|
for command in shell_commands:
|
|
|
|
|
if subprocess.call( command, shell=True ) != 0:
|
2023-10-04 15:08:11 +02:00
|
|
|
msg = "In [9.1], failed to execute command: %s"
|
2021-07-17 15:26:55 +02:00
|
|
|
print( msg % command, file=sys.stderr )
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
2024-09-23 23:36:16 +02:00
|
|
|
ret = Generate_Start_Console_Py( sourceDir2 + "/template-start-console.py",
|
|
|
|
|
pythonHBVer,
|
|
|
|
|
targetDirM + "/start-console.py" )
|
|
|
|
|
if ret == False:
|
|
|
|
|
print( "! Generate_Start_Console_Py() failed", file=sys.stderr )
|
|
|
|
|
return 1
|
2023-11-23 07:13:41 +01:00
|
|
|
|
2021-07-17 15:26:55 +02:00
|
|
|
shutil.copy2( sourceDir2 + "/klayout_console", targetDirM )
|
|
|
|
|
os.chmod( targetDirM + "/start-console.py", 0o0755 )
|
|
|
|
|
os.chmod( targetDirM + "/klayout_console", 0o0755 )
|
|
|
|
|
|
2023-10-04 15:08:11 +02:00
|
|
|
print( " [9.2] Re-linking dylib dependencies inside Python.framework" )
|
2022-12-17 05:42:08 +01:00
|
|
|
print( " [9.2.1] Patching Python Framework" )
|
2023-10-04 15:08:11 +02:00
|
|
|
if 921 in ToolDebug:
|
|
|
|
|
dbglevel = 921
|
|
|
|
|
else:
|
|
|
|
|
dbglevel = 0
|
|
|
|
|
Change_Python_LibPath_RelativeToAbsolute( pythonFrameworkPath, debug_level=dbglevel )
|
|
|
|
|
depdict = WalkFrameworkPaths( pythonFrameworkPath, debug_level=dbglevel )
|
|
|
|
|
DumpDependencyDic( "[9.2.1]", depdict, debug_level=dbglevel )
|
2021-07-17 15:26:55 +02:00
|
|
|
appPythonFrameworkPath = '@executable_path/../Frameworks/Python.framework/'
|
2023-10-04 15:08:11 +02:00
|
|
|
replacePairs = [ (HBPythonFrameworkPath, appPythonFrameworkPath, False) ]
|
|
|
|
|
PerformChanges( depdict, replacePairs, bundleExecPathAbs, debug_level=dbglevel )
|
2022-12-17 05:42:08 +01:00
|
|
|
|
|
|
|
|
print( " [9.2.2] Patching 'Python' itself in Python Framework" )
|
2023-10-04 15:08:11 +02:00
|
|
|
if 922 in ToolDebug:
|
|
|
|
|
dbglevel = 922
|
|
|
|
|
else:
|
|
|
|
|
dbglevel = 0
|
2022-12-17 05:42:08 +01:00
|
|
|
filterreg = r'\t+%s/(opt|Cellar)' % DefaultHomebrewRoot
|
2023-10-04 15:08:11 +02:00
|
|
|
Patch_Python_In_PythonFramework( pythonFrameworkPath, filter_regex=filterreg, debug_level=dbglevel )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2022-12-17 05:42:08 +01:00
|
|
|
print( " [9.2.3] Patching %s/opt/ libs" % DefaultHomebrewRoot ) # eg. DefaultHomebrewRoot == "/usr/local"
|
2023-10-04 15:08:11 +02:00
|
|
|
if 923 in ToolDebug:
|
|
|
|
|
dbglevel = 923
|
|
|
|
|
else:
|
|
|
|
|
dbglevel = 0
|
|
|
|
|
filterreg = r'\t+%s/(opt|Cellar)' % DefaultHomebrewRoot
|
|
|
|
|
depdict = WalkFrameworkPaths( pythonFrameworkPath, search_path_filter=filterreg, debug_level=dbglevel )
|
|
|
|
|
DumpDependencyDic( "[9.2.3]", depdict, debug_level=dbglevel )
|
2022-12-17 05:42:08 +01:00
|
|
|
usrLocalPath = '%s/opt/' % DefaultHomebrewRoot
|
2021-07-17 15:26:55 +02:00
|
|
|
appUsrLocalPath = '@executable_path/../Frameworks/'
|
2022-12-17 05:42:08 +01:00
|
|
|
replacePairs = [ (usrLocalPath, appUsrLocalPath, True) ]
|
2023-10-04 15:08:11 +02:00
|
|
|
PerformChanges( depdict, replacePairs, bundleExecPathAbs, debug_level=dbglevel )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2023-07-09 23:47:07 +02:00
|
|
|
#---------------------------------------------------------------------------------------------------
|
2023-11-23 07:13:41 +01:00
|
|
|
# https://formulae.brew.sh/formula/python@3.9
|
2023-10-04 15:08:11 +02:00
|
|
|
# as of 2023-09-22, python@3.9 depends on:
|
|
|
|
|
# gdbm 1.23 GNU database manager
|
|
|
|
|
# mpdecimal 2.5.1 Library for decimal floating point arithmetic
|
|
|
|
|
# openssl@3 3.1.2 Cryptography and SSL/TLS Toolkit
|
|
|
|
|
# readline 8.2.1 Library for command-line editing
|
|
|
|
|
# sqlite 3.43.1 Command-line interface for SQLite
|
|
|
|
|
# xz 5.4.4 General-purpose data compression with high compression ratio
|
|
|
|
|
#---------------------------------------------------------------------------------------------------
|
2023-11-23 07:13:41 +01:00
|
|
|
# https://formulae.brew.sh/formula/python@3.11
|
2024-09-23 23:36:16 +02:00
|
|
|
# as of 2024-09-21, python@3.11 depends on:
|
|
|
|
|
# mpdecimal 4.0.0 Library for decimal floating point arithmetic
|
|
|
|
|
# openssl@3 3.3.2 Cryptography and SSL/TLS Toolkit
|
|
|
|
|
# sqlite 3.46.1 Command-line interface for SQLite
|
|
|
|
|
# xz 5.6.2 General-purpose data compression with high compression ratio
|
2023-11-23 07:13:41 +01:00
|
|
|
#---------------------------------------------------------------------------------------------------
|
|
|
|
|
print( " [9.2.4] Patching [mpdecimal, openssl@3, sqlite, xz(, gdbm, readline)]" )
|
|
|
|
|
if 924 in ToolDebug:
|
|
|
|
|
dbglevel = 924
|
|
|
|
|
else:
|
|
|
|
|
dbglevel = 0
|
|
|
|
|
usrLocalPath = '%s/opt/' % DefaultHomebrewRoot
|
|
|
|
|
appUsrLocalPath = '@executable_path/../Frameworks/'
|
|
|
|
|
replacePairs = [ (usrLocalPath, appUsrLocalPath, True) ]
|
|
|
|
|
replacePairs.extend( [ (openssl_version, '@executable_path/../Frameworks/openssl@3', True)
|
|
|
|
|
for openssl_version in glob.glob( '%s/Cellar/openssl@3/*' % DefaultHomebrewRoot ) ] )
|
|
|
|
|
filterreg = r'\t+%s/(opt|Cellar)' % DefaultHomebrewRoot
|
|
|
|
|
depdict = WalkFrameworkPaths( [pythonFrameworkPath + '/../mpdecimal',
|
|
|
|
|
pythonFrameworkPath + '/../openssl@3',
|
|
|
|
|
pythonFrameworkPath + '/../sqlite',
|
|
|
|
|
pythonFrameworkPath + '/../xz',
|
|
|
|
|
pythonFrameworkPath + '/../gdbm',
|
|
|
|
|
pythonFrameworkPath + '/../readline'],
|
|
|
|
|
search_path_filter=filterreg,
|
|
|
|
|
debug_level=dbglevel )
|
2022-12-17 05:42:08 +01:00
|
|
|
|
2023-10-04 15:08:11 +02:00
|
|
|
DumpDependencyDic( "[9.2.4]", depdict, debug_level=dbglevel )
|
|
|
|
|
PerformChanges( depdict, replacePairs, bundleExecPathAbs, debug_level=dbglevel )
|
|
|
|
|
|
|
|
|
|
print( " [9.3] Re-linking dylib dependencies for klayout" )
|
|
|
|
|
if 931 in ToolDebug:
|
|
|
|
|
dbglevel = 931
|
|
|
|
|
else:
|
|
|
|
|
dbglevel = 0
|
2021-07-17 15:26:55 +02:00
|
|
|
klayoutPath = bundleExecPathAbs
|
2023-10-04 15:08:11 +02:00
|
|
|
depdict = WalkFrameworkPaths( klayoutPath, filter_regex=r'klayout$', debug_level=dbglevel )
|
|
|
|
|
DumpDependencyDic( "[9.3.1]", depdict, debug_level=dbglevel )
|
|
|
|
|
replacePairs = [ (HBPythonFrameworkPath, appPythonFrameworkPath, False) ]
|
|
|
|
|
PerformChanges( depdict, replacePairs, bundleExecPathAbs, debug_level=dbglevel )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2023-10-04 15:08:11 +02:00
|
|
|
if 932 in ToolDebug:
|
|
|
|
|
dbglevel = 932
|
|
|
|
|
else:
|
|
|
|
|
dbglevel = 0
|
2021-07-17 15:26:55 +02:00
|
|
|
libKlayoutPath = bundleExecPathAbs + '../Frameworks'
|
2023-10-04 15:08:11 +02:00
|
|
|
depdict = WalkFrameworkPaths( libKlayoutPath, filter_regex=r'libklayout', debug_level=dbglevel )
|
|
|
|
|
DumpDependencyDic( "[9.3.2]", depdict, debug_level=dbglevel )
|
|
|
|
|
replacePairs = [ (HBPythonFrameworkPath, appPythonFrameworkPath, False) ]
|
|
|
|
|
PerformChanges( depdict, replacePairs, bundleExecPathAbs, debug_level=dbglevel )
|
2021-07-17 15:26:55 +02:00
|
|
|
|
2023-11-23 07:13:41 +01:00
|
|
|
print( " [9.4] Patching site.py and pip/" )
|
2023-10-04 15:08:11 +02:00
|
|
|
if 940 in ToolDebug:
|
|
|
|
|
dbglevel = 940
|
|
|
|
|
else:
|
|
|
|
|
dbglevel = 0
|
2021-07-17 15:26:55 +02:00
|
|
|
site_module = "%s/Versions/%s/lib/python%s/site.py" % (pythonFrameworkPath, pythonHBVer, pythonHBVer)
|
2023-11-23 07:13:41 +01:00
|
|
|
#-----------------------------------------------------------------------------------------
|
|
|
|
|
# Rewrite the above <site.py> file.
|
|
|
|
|
# :
|
|
|
|
|
# # Prefixes for site-packages; add additional prefixes like /usr/local here
|
|
|
|
|
# PREFIXES = [sys.prefix, sys.exec_prefix]
|
|
|
|
|
# (1) sys.real_prefix = sys.prefix <=== (1) add
|
|
|
|
|
# # Enable per user site-packages directory
|
|
|
|
|
# # set it to False to disable the feature or True to force the feature
|
|
|
|
|
# (2) ENABLE_USER_SITE = False <=== (2) modify
|
|
|
|
|
# :
|
|
|
|
|
#
|
|
|
|
|
# This will fool pip into thinking it's inside a virtual environment
|
|
|
|
|
# and install new packages to the correct site-packages.
|
|
|
|
|
#-----------------------------------------------------------------------------------------
|
|
|
|
|
# It looks like the technique of modifying <site.py> works when Python<=3.9 as follows.
|
|
|
|
|
# However, it doesn't when 3.11<=Python.
|
|
|
|
|
#
|
|
|
|
|
# In </home/kazzz-s/GitWork/cpython-39/Lib/site.py> (Linux source code build)
|
|
|
|
|
# :
|
|
|
|
|
# # Prefixes for site-packages; add additional prefixes like /usr/local here
|
|
|
|
|
# PREFIXES = [sys.prefix, sys.exec_prefix]
|
|
|
|
|
# # Enable per user site-packages directory
|
|
|
|
|
# # set it to False to disable the feature or True to force the feature
|
|
|
|
|
# ENABLE_USER_SITE = None
|
|
|
|
|
# print( "### I have imported the modified <%s>" % __file__ ) <=== (3) added
|
|
|
|
|
# :
|
|
|
|
|
#
|
|
|
|
|
# MyLinux{kazzz-s}(1)$ ./python
|
|
|
|
|
# ### I have imported the modified </home/kazzz-s/GitWork/cpython-39/Lib/site.py> ---(3)
|
|
|
|
|
# Python 3.9.18+ (heads/3.9:43a6e4fa49, Oct 27 2023, 12:51:17)
|
|
|
|
|
# [GCC 9.4.0] on linux
|
|
|
|
|
# Type "help", "copyright", "credits" or "license" for more information.
|
|
|
|
|
# >>>
|
|
|
|
|
#-----------------------------------------------------------------------------------------
|
2021-07-17 15:26:55 +02:00
|
|
|
with open(site_module, 'r') as site:
|
|
|
|
|
buf = site.readlines()
|
|
|
|
|
with open(site_module, 'w') as site:
|
|
|
|
|
for line in buf:
|
|
|
|
|
if re.match("^PREFIXES", line) is not None:
|
2023-11-23 07:13:41 +01:00
|
|
|
line = line + "sys.real_prefix = sys.prefix\n" # --- (1)
|
2021-07-17 15:26:55 +02:00
|
|
|
# do not allow installation in the user folder.
|
|
|
|
|
if re.match("^ENABLE_USER_SITE", line) is not None:
|
2023-11-23 07:13:41 +01:00
|
|
|
line = "ENABLE_USER_SITE = False\n" # --- (2)
|
2021-07-17 15:26:55 +02:00
|
|
|
site.write(line)
|
|
|
|
|
|
2023-11-23 07:13:41 +01:00
|
|
|
#-----------------------------------------------------------------------------------------
|
2021-07-17 15:26:55 +02:00
|
|
|
# Typical usage of 'pip' after installation of the DMG package
|
|
|
|
|
#
|
2021-11-27 23:51:05 +01:00
|
|
|
# $ cd /Applications/klayout.app/Contents/MacOS/
|
|
|
|
|
# $ ./start-console.py
|
|
|
|
|
#
|
2022-10-10 04:36:50 +02:00
|
|
|
# $ /Applications/klayout.app/Contents/MacOS/start-console.py
|
|
|
|
|
# Warning: Populating font family aliases took 195 ms. Replace uses of missing font\
|
|
|
|
|
# family "Monospace" with one that exists to avoid this cost.
|
|
|
|
|
# Python 3.7.8 (default, Jul 4 2020, 10:17:17)
|
|
|
|
|
# [Clang 11.0.3 (clang-1103.0.32.62)] on darwin
|
2021-07-17 15:26:55 +02:00
|
|
|
# Type "help", "copyright", "credits" or "license" for more information.
|
|
|
|
|
# (KLayout Python Console)
|
|
|
|
|
# >>> import pip
|
2023-10-04 15:08:11 +02:00
|
|
|
# >>> pip.main( ['install', 'pandas', 'scipy', 'matplotlib'] )
|
|
|
|
|
# >>> quit()
|
|
|
|
|
#
|
|
|
|
|
# 'pandas' depends on many modules including 'numpy'. They are also installed.
|
2023-11-23 07:13:41 +01:00
|
|
|
#-----------------------------------------------------------------------------------------
|
2021-07-17 15:26:55 +02:00
|
|
|
pip_module = "%s/Versions/%s/lib/python%s/site-packages/pip/__init__.py" % \
|
|
|
|
|
(pythonFrameworkPath, pythonHBVer, pythonHBVer)
|
|
|
|
|
with open(pip_module, 'r') as pip:
|
|
|
|
|
buf = pip.readlines()
|
|
|
|
|
with open(pip_module, 'w') as pip:
|
|
|
|
|
for line in buf:
|
|
|
|
|
# this will reject user's configuration of pip, forcing the isolated mode
|
|
|
|
|
line = re.sub("return isolated$", "return isolated or True", line)
|
|
|
|
|
pip.write(line)
|
|
|
|
|
|
2023-11-23 07:13:41 +01:00
|
|
|
#----------------------------------------------------------------------------------------------------
|
|
|
|
|
# Patch distutils/ in older versions of Python.
|
|
|
|
|
# However, newer versions of Python deprecate the distutils.cfg file and the distutils module itself.
|
|
|
|
|
# Ref. https://github.com/Homebrew/homebrew-core/issues/76621
|
|
|
|
|
#----------------------------------------------------------------------------------------------------
|
2024-09-23 23:36:16 +02:00
|
|
|
"""
|
2023-11-23 07:13:41 +01:00
|
|
|
if deploymentPython39HB or (HBPythonAutoVersion == "3.9"): # Python == 3.9
|
|
|
|
|
print( deploymentPython39HB, HBPythonAutoVersion )
|
|
|
|
|
print( " [9.5.1] Patching distutils/" )
|
|
|
|
|
if 951 in ToolDebug:
|
|
|
|
|
dbglevel = 951
|
|
|
|
|
else:
|
|
|
|
|
dbglevel = 0
|
|
|
|
|
distutilsconfig = "%s/Versions/%s/lib/python%s/distutils/distutils.cfg" % \
|
2021-07-17 15:26:55 +02:00
|
|
|
(pythonFrameworkPath, pythonHBVer, pythonHBVer)
|
2023-11-23 07:13:41 +01:00
|
|
|
#-----------------------------------------------------------------------------------------
|
|
|
|
|
# Rewrite the above <distutils.cfg> file in Homebrew python@3.9.18.
|
|
|
|
|
# [install]
|
|
|
|
|
# prefix=/usr/local <=== remove this line
|
|
|
|
|
# [build_ext]
|
|
|
|
|
# include_dirs=/usr/local/include:/usr/local/opt/openssl@3/include:\
|
|
|
|
|
# /usr/local/opt/sqlite/include
|
|
|
|
|
# library_dirs=/usr/local/lib:/usr/local/opt/openssl@3/lib:/usr/local/opt/sqlite/lib
|
|
|
|
|
#
|
|
|
|
|
# This will cause all packages to be installed to sys.prefix
|
|
|
|
|
#-----------------------------------------------------------------------------------------
|
|
|
|
|
with open(distutilsconfig, 'r') as file:
|
|
|
|
|
buf = file.readlines()
|
|
|
|
|
with open(distutilsconfig, 'w') as file:
|
|
|
|
|
for line in buf:
|
|
|
|
|
if re.match('prefix=', line) is not None:
|
|
|
|
|
continue
|
|
|
|
|
file.write(line)
|
2024-09-23 23:36:16 +02:00
|
|
|
"""
|
|
|
|
|
if deploymentPython311HB or (HBPythonAutoVersion == "3.11"): # Python == 3.11
|
2023-11-23 07:13:41 +01:00
|
|
|
# The above 'distutils.cfg' file does not exist in the distutils/ directory of Python 3.11.
|
|
|
|
|
# Use a different technique.
|
|
|
|
|
print( " [9.5.2] In the Python3.11 environment, use an alternative method of patching distutils/" )
|
|
|
|
|
print( " See Contents/MacOS/start-console.py in /Applications/klayout.app/" )
|
2024-09-23 23:36:16 +02:00
|
|
|
else: # other than ["3.11"]
|
|
|
|
|
print( "!!! HW-dmg package assumes python@3.11" )
|
2023-11-23 07:13:41 +01:00
|
|
|
print( "!!! 'distutils' has been deprecated in 3.12 <= Python" )
|
|
|
|
|
print("")
|
|
|
|
|
os.chdir(ProjectDir)
|
|
|
|
|
return 1
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
#-------------------------------------------------------------
|
2024-02-16 22:51:08 +01:00
|
|
|
# [10] Special deployment of Ruby3.3 from Homebrew?
|
2021-07-17 15:26:55 +02:00
|
|
|
#-------------------------------------------------------------
|
2025-01-18 23:51:02 +01:00
|
|
|
deploymentRuby33HB = (ModuleRuby == 'Ruby34Brew')
|
2024-04-01 10:59:06 +02:00
|
|
|
if deploymentRuby33HB and NonOSStdLang:
|
2021-07-17 15:26:55 +02:00
|
|
|
|
|
|
|
|
print( "" )
|
2025-01-18 23:51:02 +01:00
|
|
|
print( " [10] You have reached optional deployment of Ruby from %s ..." % HBRuby34Path )
|
2021-07-17 15:26:55 +02:00
|
|
|
print( " [!!!] Sorry, the deployed package will not work properly since deployment of" )
|
2024-02-16 22:51:08 +01:00
|
|
|
print( " Ruby3.3 from Homebrew is not yet supported." )
|
2021-07-17 15:26:55 +02:00
|
|
|
print( " Since you have Homebrew development environment, there two options:" )
|
|
|
|
|
print( " (1) Retry to make a package with '-Y|--DEPLOY' option." )
|
2022-10-10 04:36:50 +02:00
|
|
|
print( " This will not deploy any of Qt[5|6], Python, and Ruby from Homebrew." )
|
2021-07-17 15:26:55 +02:00
|
|
|
print( " Instead, the package will directly use those Frameworks and libraries" )
|
|
|
|
|
print( " in your Homebrew environment." )
|
|
|
|
|
print( " (2) Rebuild KLayout with '-r|--ruby <nil|Sys>' option depending on your preference." )
|
|
|
|
|
print( "" )
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
print( " [8] Skipped deploying Qt's Frameworks and optional Python/Ruby Frameworks..." )
|
2024-04-01 10:59:06 +02:00
|
|
|
print( "##### Finished deploying the libraries and executables for <klayout.app> #####" )
|
2021-07-17 15:26:55 +02:00
|
|
|
print("")
|
|
|
|
|
os.chdir(ProjectDir)
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
|
## The main function
|
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
|
def Main():
|
|
|
|
|
pp = pprint.PrettyPrinter( indent=4, width=140 )
|
|
|
|
|
config = Get_Default_Config()
|
|
|
|
|
Parse_CLI_Args(config)
|
|
|
|
|
|
|
|
|
|
#----------------------------------------------------------
|
|
|
|
|
# [The main build stage]
|
|
|
|
|
#----------------------------------------------------------
|
|
|
|
|
parameters = Get_Build_Parameters(config)
|
|
|
|
|
pp.pprint(parameters)
|
|
|
|
|
|
|
|
|
|
if not config['DeploymentF'] and not config['DeploymentP']:
|
2023-11-23 07:13:41 +01:00
|
|
|
ret = Run_Build_Command(config, parameters)
|
2021-07-17 15:26:55 +02:00
|
|
|
pp.pprint(config)
|
|
|
|
|
if not ret == 0:
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
else:
|
|
|
|
|
#----------------------------------------------------------
|
|
|
|
|
# [The deployment stage]
|
|
|
|
|
# Deployment of dynamic link libraries, executables and
|
|
|
|
|
# resources to make the main "klayout.app" bundle
|
|
|
|
|
#----------------------------------------------------------
|
|
|
|
|
ret = Deploy_Binaries_For_Bundle(config, parameters)
|
|
|
|
|
if not ret == 0:
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
#===================================================================================
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
Main()
|
|
|
|
|
|
|
|
|
|
#---------------
|
|
|
|
|
# End of file
|
|
|
|
|
#---------------
|