diff --git a/macbuild/ReadMe.md b/macbuild/ReadMe.md index cfd8fe3c4f..4a8da914d7 100644 --- a/macbuild/ReadMe.md +++ b/macbuild/ReadMe.md @@ -1,9 +1,9 @@ -Relevant KLayout version: 0.28.17
+Relevant KLayout version: 0.29.0
Author: Kazzz-S
-Last modified: 2024-02-16
+Last modified: 2024-03-27
# 1. Introduction -This directory **`macbuild`** contains various files required for building KLayout (http://www.klayout.de/) version 0.28.17 or later for different 64-bit macOS, including: +This directory **`macbuild`** contains various files required for building KLayout (http://www.klayout.de/) version 0.29.0 or later for different 64-bit macOS, including: * Monterey (12.x) : the primary development environment * Ventura (13.x) : experimental * Sonoma (14.x) : -- ditto -- @@ -22,14 +22,14 @@ All Apple (M1|M2|M3) chips are still untested, as the author does not own an (M1 # 2. Qt Frameworks -The default Qt framework is "Qt5" from Homebrew (https://brew.sh/), which is usually located under: +The default Qt framework is "Qt5" from **MacPorts** (https://www.macports.org/), which is usually located under: ``` -/usr/local/opt/qt@5/ +/opt/local/libexec/qt5/ ``` -If you prefer **MacPorts** (https://www.macports.org/), "Qt5" is usually located under: +If you prefer "Qt6" from **Homebrew** (https://brew.sh/), which is usually located under: ``` -/opt/local/libexec/qt5/ +/usr/local/opt/qt@6/ ``` You can also choose "Qt5" from Anaconda3 (https://www.anaconda.com/), which is usually located under: @@ -41,11 +41,12 @@ If you have installed Anaconda3 under $HOME/opt/anaconda3/, make a symbolic link /Applications/anaconda3/ ---> $HOME/opt/anaconda3/ ``` -The migration work to "Qt6" is ongoing. You can try to use it; however, you will encounter some build and runtime errors. +The migration work to "Qt6" is ongoing. You can try to use it; however, you will encounter some build and runtime errors.
+If you use **Homebrew** to build KLayout >= 0.29.0, you need "Qt6" to address [the compilation issue](https://github.com/KLayout/klayout/issues/1599). # 3. Script language support: Ruby and Python -The build script **`build4mac.py`** provides several possible combinations of Qt5, Ruby, and Python modules to suit the user's needs and preferences.
+The build script **`build4mac.py`** provides several possible combinations of Qt, Ruby, and Python modules to suit the user's needs and preferences.
Some typical use cases are described in Section 6. # 4. Prerequisites @@ -53,8 +54,8 @@ You need to have the followings: * The latest Xcode and command-line tool kit compliant with each OS * https://developer.apple.com/xcode/resources/ * https://mac.install.guide/commandlinetools/4 -* Qt5 package from Homebrew, MacPorts, or Anaconda3 -* Optionally, Ruby and Python packages from Homebrew, MacPorts, or Anaconda3 +* Qt5 package from MacPorts or Anaconda3. Qt6, from Homebrew. +* Optionally, Ruby and Python packages from MacPorts, Homebrew, or Anaconda3 #### For matching versions of Ruby and Python, please also refer to `build4mac_env.py`. # 5. Command-line options of **`build4mac.py`** @@ -65,7 +66,7 @@ The operating system type is detected automatically. ``` --------------------------------------------------------------------------------------------------------- << Usage of 'build4mac.py' >> - for building KLayout 0.28.17 or later on different Apple macOS platforms. + for building KLayout 0.29.0 or later on different Apple macOS platforms. $ [python] ./build4mac.py option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details)| default value @@ -121,7 +122,7 @@ $ [python] ./build4mac.py In this section, the actual file and directory names are those obtained on macOS Monterey.
On different OS, those names differ accordingly. -### 6A. Standard build using the OS-bundled Ruby and Python with MacPorts Qt +### 6A. Standard build using the OS-bundled Ruby and Python with MacPorts Qt5 0. Install MacPorts, then install Qt5 and libgit2 by ``` $ sudo port install coreutils @@ -155,41 +156,45 @@ $ ./build4mac.py -q qt5macports -r sys -p sys -y * "RsysPsys" means that Ruby is 2.6 provided by OS; Python is 3.9 provided by OS. 4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation. -### 6B. Fully Homebrew-flavored build with Homebrew Ruby 3.3 and Homebrew Python 3.11 -0. Install Homebrew, then install Qt5, Ruby 3.3, Python 3.11, and libgit2 by +### 6B. Fully MacPorts-flavored build with MacPorts Ruby 3.3 and MacPorts Python 3.11 +0. Install MacPorts, then install Qt5, Ruby 3.3, Python 3.11, and libgit2 by ``` -$ brew install qt@5 -$ brew install ruby@3.3 -$ brew install python@3.11 -$ brew install libgit2 -$ cd /where/'build.sh'/exists -$ cd macbuild -$ ./python3HB.py -v 3.11 +$ sudo port install coreutils +$ sudo port install findutils +$ sudo port install qt5 +$ sudo port install ruby33 +$ sudo port install python311 +$ sudo port install py311-pip +$ sudo port install libgit2 ``` 1. Invoke **`build4mac.py`** with the following options: ``` $ cd /where/'build.sh'/exists -$ ./build4mac.py -q qt5brew -r hb33 -p hb311 +$ ./build4mac.py -q qt5macports -r mp33 -p mp311 ``` 2. Confirm successful build (it will take about one hour, depending on your machine spec). 3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.
The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step.
- If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Python Module (\*.whl) will be built and deployed under **klayout.app/Contents/pymod-dist/**. + If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Standalone Python Package (\*.whl) will be built and deployed under **klayout.app/Contents/pymod-dist/**. ``` -$ ./build4mac.py -q qt5brew -r hb33 -p hb311 -Y +$ ./build4mac.py -q qt5macports -r mp33 -p mp311 -Y ``` The application bundle **`klayout.app`** is located under:
- **`LW-qt5Brew.pkg.macos-Monterey-release-Rhb33Phb311`** directory, where + **`LW-qt5MP.pkg.macos-Monterey-release-Rmp33Pmp311`** directory, where * "LW-" means this is a lightweight package. -* "qt5Brew" means that Qt5 from Homebrew is used. -* "Rhb33Phb311" means that Ruby is 3.3 from Homebrew; Python is 3.11 from Homebrew. +* "qt5MP" means that Qt5 from MacPorts is used. +* "Rmp33Pmp311" means that Ruby is 3.3 from MacPorts; Python is 3.11 from MacPorts. 4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation. -### 6C. Partially Homebrew-flavored build with System Ruby and Homebrew Python 3.11 -0. Install Homebrew, then install Qt5, Python 3.11, and libgit2 by +### 6C. Fully Homebrew-flavored build with Homebrew Ruby 3.3 and Homebrew Python 3.11 +> [!IMPORTANT] +> To build KLayout >= 0.29.0, you need "Qt6" to address [the compilation issue](https://github.com/KLayout/klayout/issues/1599). + +0. Install Homebrew, then install Qt6, Ruby 3.3, Python 3.11, and libgit2 by ``` -$ brew install qt@5 +$ brew install qt@6 +$ brew install ruby@3.3 $ brew install python@3.11 $ brew install libgit2 $ cd /where/'build.sh'/exists @@ -199,55 +204,62 @@ $ ./python3HB.py -v 3.11 1. Invoke **`build4mac.py`** with the following options: ``` $ cd /where/'build.sh'/exists -$ ./build4mac.py -q qt5brew -r sys -p hb311 +$ ./build4mac.py -q qt6brew -r hb33 -p hb311 ``` 2. Confirm successful build (it will take about one hour, depending on your machine spec). -3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-y" to deploy executables and libraries (including Qt and Python frameworks) under the **`klayout.app`** bundle.
- The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step. +3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.
+ The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step.
+ If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Standalone Python Package (\*.whl) will be built and deployed under **klayout.app/Contents/pymod-dist/**. ``` -$ ./build4mac.py -q qt5brew -r sys -p hb311 -y +$ ./build4mac.py -q qt6brew -r hb33 -p hb311 -Y ``` The application bundle **`klayout.app`** is located under:
- **`HW-qt5Brew.pkg.macos-Monterey-release-RsysPhb311`** directory, where -* "HW-" means this is a heavyweight package because both Qt5 and Python Frameworks are deployed. -* "qt5Brew" means that Qt5 from Homebrew is used. -* "RsysPhb311" means that Ruby is OS-bundled; Python is 3.11 from Homebrew. + **`LW-qt6Brew.pkg.macos-Monterey-release-Rhb33Phb311`** directory, where +* "LW-" means this is a lightweight package. +* "qt6Brew" means that Qt6 from Homebrew is used. +* "Rhb33Phb311" means that Ruby is 3.3 from Homebrew; Python is 3.11 from Homebrew. 4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation. -### Important -So far, the deployment of Homebrew Ruby is not supported.
-Therefore, if you intend to use the "-y" option for deployment, you need to use the "-r sys" option for building. -### 6D. Fully MacPorts-flavored build with MacPorts Ruby 3.3 and MacPorts Python 3.11 -0. Install MacPorts, then install Qt5, Ruby 3.3, Python 3.11, and libgit2 by +### 6D. Partially Homebrew-flavored build with System Ruby and Homebrew Python 3.11 +> [!IMPORTANT] +> To build KLayout >= 0.29.0, you need "Qt6" to address [the compilation issue](https://github.com/KLayout/klayout/issues/1599). + +> [!CAUTION] +> Homebrew Qt6.6.2 seems buggy. More precisely, it does not perfectly deploy the required Qt frameworks. +> If you plan to distribute an HW*.dmg package, consider using Qt6.4.x from MacPorts. +> That is, substitute `qt6brew` with `qt6macports` in the following command lines. + +0. Install Homebrew, then install Qt6, Python 3.11, and libgit2 by ``` -$ sudo port install coreutils -$ sudo port install findutils -$ sudo port install qt5 -$ sudo port install ruby33 -$ sudo port install python311 -$ sudo port install py311-pip -$ sudo port install libgit2 +$ brew install qt@6 +$ brew install python@3.11 +$ brew install libgit2 +$ cd /where/'build.sh'/exists +$ cd macbuild +$ ./python3HB.py -v 3.11 ``` 1. Invoke **`build4mac.py`** with the following options: ``` $ cd /where/'build.sh'/exists -$ ./build4mac.py -q qt5macports -r mp33 -p mp311 +$ ./build4mac.py -q qt6brew -r sys -p hb311 ``` 2. Confirm successful build (it will take about one hour, depending on your machine spec). -3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.
- The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step.
- If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Python Module (\*.whl) will be built and deployed under **klayout.app/Contents/pymod-dist/**. +3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-y" to deploy executables and libraries (including Qt and Python frameworks) under the **`klayout.app`** bundle.
+ The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step. ``` -$ ./build4mac.py -q qt5macports -r mp33 -p mp311 -Y +$ ./build4mac.py -q qt6brew -r sys -p hb311 -y ``` The application bundle **`klayout.app`** is located under:
- **`LW-qt5MP.pkg.macos-Monterey-release-Rmp33Pmp311`** directory, where -* "LW-" means this is a lightweight package. -* "qt5MP" means that Qt5 from MacPorts is used. -* "Rmp33Pmp311" means that Ruby is 3.3 from MacPorts; Python is 3.11 from MacPorts. + **`HW-qt6Brew.pkg.macos-Monterey-release-RsysPhb311`** directory, where +* "HW-" means this is a heavyweight package because both Qt6 and Python Frameworks are deployed. +* "qt6Brew" means that Qt6 from Homebrew is used. +* "RsysPhb311" means that Ruby is OS-bundled; Python is 3.11 from Homebrew. 4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation. +> [!IMPORTANT] +> So far, the deployment of Homebrew Ruby is not supported.
+> Therefore, if you intend to use the "-y" option for deployment, you need to use the "-r sys" option for building. ### 6E. Fully Anaconda3-flavored build with Anaconda3 Ruby 3.2 and Anaconda3 Python 3.11 0. Install Anaconda3 (Anaconda3-2023.09-0-MacOSX-x86_64.pkg), then install Ruby 3.2 and libgit2 by @@ -264,7 +276,7 @@ $ ./build4mac.py -q qt5ana3 -r ana3 -p ana3 2. Confirm successful build (it will take about one hour, depending on your machine spec). 3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.
The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step.
- If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Python Module (\*.whl) will be built and deployed under **klayout.app/Contents/pymod-dist/**. + If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Standalone Python Package (\*.whl) will be built and deployed under **klayout.app/Contents/pymod-dist/**. ``` $ ./build4mac.py -q qt5ana3 -r ana3 -p ana3 -Y @@ -292,7 +304,7 @@ $ export KLAYOUT_GIT_HTTP_PROXY="http://111.222.333.444:5678" Ask your system administrator for the actual IP address and port number of your proxy server. It is highly recommended that this setting is included in a launching service script bundle.
-A sample content (`*.app.Bash`) of the script bundle can be found in `Resources/script-bundle-[A|B|H|P].zip`. +A sample content (`*.app.Bash`) of the script bundle can be found in `Resources/script-bundle-[A|B|H|P|S].zip`. ---- @@ -310,8 +322,8 @@ $ cd /where/'build.sh'/exists $ ./makeDMG4mac.py -p LW-qt5MP.pkg.macos-Monterey-release-Rmp33Pmp311 -m ``` This command will generate the two files below:
-* **`LW-klayout-0.28.17-macOS-Monterey-1-qt5MP-Rmp33Pmp311.dmg`** ---(1) the main DMG file -* **`LW-klayout-0.28.17-macOS-Monterey-1-qt5MP-Rmp33Pmp311.dmg.md5`** ---(2) MD5-value text file +* **`LW-klayout-0.29.0-macOS-Monterey-1-qt5MP-Rmp33Pmp311.dmg`** ---(1) the main DMG file +* **`LW-klayout-0.29.0-macOS-Monterey-1-qt5MP-Rmp33Pmp311.dmg.md5`** ---(2) MD5-value text file # Known issues Because we assume some specific versions of non-OS-standard Ruby and Python, updating Homebrew, MacPorts, or Anaconda3 may cause build- and link errors.
diff --git a/macbuild/Resources/script-bundle-A.zip b/macbuild/Resources/script-bundle-A.zip index 3f7e538fca..89409aa7f2 100644 Binary files a/macbuild/Resources/script-bundle-A.zip and b/macbuild/Resources/script-bundle-A.zip differ diff --git a/macbuild/Resources/script-bundle-B.zip b/macbuild/Resources/script-bundle-B.zip index 9855a5f57c..95870471e1 100644 Binary files a/macbuild/Resources/script-bundle-B.zip and b/macbuild/Resources/script-bundle-B.zip differ diff --git a/macbuild/Resources/script-bundle-H.zip b/macbuild/Resources/script-bundle-H.zip index f3d73ffb41..4db6f545d2 100644 Binary files a/macbuild/Resources/script-bundle-H.zip and b/macbuild/Resources/script-bundle-H.zip differ diff --git a/macbuild/Resources/script-bundle-P.zip b/macbuild/Resources/script-bundle-P.zip index d8df82a293..626efae4ee 100644 Binary files a/macbuild/Resources/script-bundle-P.zip and b/macbuild/Resources/script-bundle-P.zip differ diff --git a/macbuild/Resources/script-bundle-S.zip b/macbuild/Resources/script-bundle-S.zip index 164a970ba2..ad3ac4b177 100644 Binary files a/macbuild/Resources/script-bundle-S.zip and b/macbuild/Resources/script-bundle-S.zip differ diff --git a/macbuild/build4mac.py b/macbuild/build4mac.py index de2204b040..b5a5129476 100755 --- a/macbuild/build4mac.py +++ b/macbuild/build4mac.py @@ -5,7 +5,7 @@ # File: "macbuild/build4mac.py" # # The top Python script for building KLayout (http://www.klayout.de/index.php) -# version 0.28.17 or later on different Apple Mac OSX platforms. +# version 0.29.0 or later on different Apple Mac OSX platforms. #=============================================================================== import sys import os @@ -45,7 +45,7 @@ def GenerateUsage(platform): usage = "\n" usage += "---------------------------------------------------------------------------------------------------------\n" usage += "<< Usage of 'build4mac.py' >>\n" - usage += " for building KLayout 0.28.17 or later on different Apple macOS platforms.\n" + usage += " for building KLayout 0.29.0 or later on different Apple macOS platforms.\n" usage += "\n" usage += "$ [python] ./build4mac.py\n" usage += " option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details)| default value\n" @@ -100,7 +100,7 @@ def GenerateUsage(platform): #------------------------------------------------------------------------------- ## To get the default configurations # -# @return a dictionary containing the default configuration for the macOS build +# @return a dictionary containing the default configurations for the macOS build #------------------------------------------------------------------------------- def Get_Default_Config(): ProjectDir = os.getcwd() @@ -166,7 +166,7 @@ def Get_Default_Config(): ModuleRuby = "nil" ModulePython = "nil" - BuildPymod = False + BuildPymodWhl = False NonOSStdLang = False NoQtBindings = False NoQtUiTools = False @@ -181,6 +181,8 @@ def Get_Default_Config(): Version = GetKLayoutVersionFrom( "./version.sh" ) HBPythonIs39 = False # because ModulePython == "Python311Brew" by default OSPython3FW = None # system Python3 frameworks in [ None, MontereyPy3FW, VenturaPy3FW, SonomaPy3FW ] + EmbedQt = False + EmbedPython3 = False config = dict() config['ProjectDir'] = ProjectDir # project directory where "build.sh" exists @@ -190,7 +192,7 @@ def Get_Default_Config(): config['ModuleQt'] = ModuleQt # Qt module to be used config['ModuleRuby'] = ModuleRuby # Ruby module to be used config['ModulePython'] = ModulePython # Python module to be used - config['BuildPymod'] = BuildPymod # True to build and deploy "Pymod" + config['BuildPymodWhl'] = BuildPymodWhl # True to build and deploy "Pymod (*.whl)" 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 @@ -207,6 +209,8 @@ def Get_Default_Config(): config['ToolDebug'] = ToolDebug # debug level list for this tool config['HBPythonIs39'] = HBPythonIs39 # True if the Homebrew Python version <= 3.9 config['OSPython3FW'] = OSPython3FW # system Python3 frameworks in [ None, MontereyPy3FW, VenturaPy3FW, SonomaPy3FW ] + config['EmbedQt'] = EmbedQt # True if Qt is embedded + config['EmbedPython3'] = EmbedPython3 # True if Python3 is embedded # auxiliary variables on platform config['System'] = System # 6-tuple from platform.uname() config['Node'] = Node # - do - @@ -234,7 +238,7 @@ def Parse_CLI_Args(config): ModuleQt = config['ModuleQt'] ModuleRuby = config['ModuleRuby'] ModulePython = config['ModulePython'] - BuildPymod = config['BuildPymod'] + BuildPymodWhl = config['BuildPymodWhl'] NonOSStdLang = config['NonOSStdLang'] NoQtBindings = config['NoQtBindings'] NoQtUiTools = config['NoQtUiTools'] @@ -250,6 +254,8 @@ def Parse_CLI_Args(config): ToolDebug = config['ToolDebug'] HBPythonIs39 = config['HBPythonIs39'] OSPython3FW = config['OSPython3FW'] + EmbedQt = config['EmbedQt'] + EmbedPython3 = config['EmbedPython3'] #----------------------------------------------------- # [2] Parse the CLI arguments @@ -269,9 +275,9 @@ def Parse_CLI_Args(config): p.add_option( '-P', '--buildPymod', action='store_true', - dest='build_pymod', + dest='build_pymod_whl', default=False, - help="build and deploy (disabled)" ) + help="build and deploy Pymod (*.whl) (disabled)" ) p.add_option( '-n', '--noqtbinding', action='store_true', @@ -335,21 +341,21 @@ def Parse_CLI_Args(config): help='check usage' ) if Platform.upper() in [ "SONOMA", "VENTURA", "MONTEREY" ]: # with Xcode [13.1 .. ] - p.set_defaults( type_qt = "qt5macports", - type_ruby = "sys", - type_python = "sys", - build_pymod = 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 ) + 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 ) else: raise Exception( "! Too obsolete platform <%s>" % Platform ) @@ -504,16 +510,16 @@ def Parse_CLI_Args(config): ModuleSet = ( choiceQt56, choiceRuby, choicePython ) # (E) Set other parameters - BuildPymod = opt.build_pymod - 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 ]) ) + 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 ]) ) if DeploymentF and DeploymentP: print("") @@ -528,31 +534,42 @@ def Parse_CLI_Args(config): print(Usage) sys.exit(1) + # (F) Build mode if not DeploymentF and not DeploymentP: target = "%s %s %s" % (Platform, Release, Machine) modules = "Qt=%s, Ruby=%s, Python=%s" % (ModuleQt, ModuleRuby, ModulePython) - if BuildPymod: - pymodbuild = "enabled" + if BuildPymodWhl: + pymodWhlbuild = "enabled" else: - pymodbuild = "disabled" + pymodWhlbuild = "disabled" message = "### You are going to build KLayout\n for <%s>\n with <%s>\n with Pymod <%s>...\n" print("") - print( message % (target, modules, pymodbuild) ) + print( message % (target, modules, pymodWhlbuild) ) + # (G) Deploy mode else: - okHWdmg = True - message = "### You are going to make " + EmbedQt = False + EmbedPython3 = False + okHWdmg = True + message = "### You are going to make " if DeploymentP: PackagePrefix = "LW-" - if not BuildPymod: - message += "a lightweight (LW-) package excluding Qt5, Ruby, and Python..." + if not BuildPymodWhl: + message += "a lightweight (LW-) package excluding Qt[5|6], Ruby, and Python..." else: - message += "a lightweight (LW-) package with Pymod excluding Qt5, Ruby, and Python..." + message += "a lightweight (LW-) package with Pymod (*.whl) excluding Qt[5|6], Ruby, and Python..." elif DeploymentF: - if (ModuleRuby in RubySys) and (ModulePython in PythonSys): + if ModuleQt == "Qt5Ana3": + EmbedQt = False + message += "Qt5 from Anaconda3 embedded, which is not allowed!" + okHWdmg = False + elif (ModuleRuby in RubySys) and (ModulePython in PythonSys): PackagePrefix = "ST-" + EmbedQt = True message += "a standard (ST-) package including Qt[5|6] and using OS-bundled Ruby and Python..." elif ModulePython in ['Python311Brew', 'Python39Brew', 'PythonAutoBrew']: PackagePrefix = "HW-" + EmbedQt = True + EmbedPython3 = True message += "a heavyweight (HW-) package including Qt[5|6] and Python3.[11|9] from Homebrew..." okHWdmg = (ModulePython == 'Python311Brew') or \ (ModulePython == 'Python39Brew') or \ @@ -564,7 +581,9 @@ def Parse_CLI_Args(config): print( message ) print( "" ) if not okHWdmg: - print( "!!! HW-dmg package assumes either python@3.11 or python@3.9" ) + print( "!!! HW-dmg package assumes the two conditions:" ) + print( " (1) either Qt5 or Qt6 from MacPorts or Homebrew (Anaconda3 is not a candidate)" ) + print( " (2) either python@3.11 or python@3.9 from Homebrew" ) sys.exit(1) if CheckComOnly: sys.exit(0) @@ -577,7 +596,7 @@ def Parse_CLI_Args(config): config['ModuleQt'] = ModuleQt config['ModuleRuby'] = ModuleRuby config['ModulePython'] = ModulePython - config['BuildPymod'] = BuildPymod + config['BuildPymodWhl'] = BuildPymodWhl config['NonOSStdLang'] = NonOSStdLang config['NoQtBindings'] = NoQtBindings config['NoQtUiTools'] = NoQtUiTools @@ -593,11 +612,13 @@ def Parse_CLI_Args(config): config['ToolDebug'] = ToolDebug config['HBPythonIs39'] = HBPythonIs39 config['OSPython3FW'] = OSPython3FW + config['EmbedQt'] = EmbedQt + config['EmbedPython3'] = EmbedPython3 if CheckComOnly: pp = pprint.PrettyPrinter( indent=4, width=140 ) parameters = Get_Build_Parameters(config) - Build_pymod(parameters) + Build_pymod_wheel(parameters) pp.pprint(parameters) sys.exit(0) else: @@ -620,7 +641,7 @@ def Get_Build_Parameters(config): ModuleQt = config['ModuleQt'] ModuleRuby = config['ModuleRuby'] ModulePython = config['ModulePython'] - BuildPymod = config['BuildPymod'] + BuildPymodWhl = config['BuildPymodWhl'] ModuleSet = config['ModuleSet'] NoQtBindings = config['NoQtBindings'] NoQtUiTools = config['NoQtUiTools'] @@ -657,39 +678,28 @@ def Get_Build_Parameters(config): 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" + parameters['bin'] = MacBinDir + parameters['build'] = MacBuildDir parameters['logfile'] = MacBuildLog - # (D) Qt5|6 - if ModuleQt == 'Qt5MacPorts': - parameters['qmake'] = Qt5MacPorts['qmake'] - parameters['deploy_tool'] = Qt5MacPorts['deploy'] - elif ModuleQt == 'Qt5Brew': - parameters['qmake'] = Qt5Brew['qmake'] - parameters['deploy_tool'] = Qt5Brew['deploy'] - elif ModuleQt == 'Qt5Ana3': - parameters['qmake'] = Qt5Ana3['qmake'] - parameters['deploy_tool'] = Qt5Ana3['deploy'] - elif ModuleQt == 'Qt6MacPorts': - parameters['qmake'] = Qt6MacPorts['qmake'] - parameters['deploy_tool'] = Qt6MacPorts['deploy'] - elif ModuleQt == 'Qt6Brew': - parameters['qmake'] = Qt6Brew['qmake'] - parameters['deploy_tool'] = Qt6Brew['deploy'] - - parameters['bin'] = MacBinDir - parameters['build'] = MacBuildDir + # (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 if OSPython3FW in [ MontereyPy3FW, VenturaPy3FW, SonomaPy3FW ]: parameters['rpath'] = OSPython3FW else: parameters['rpath'] = "@executable_path/../Frameworks" - # (E) want Qt bindings with Ruby scripts? + # (F) want Qt bindings with Ruby scripts? parameters['no_qt_bindings'] = NoQtBindings - # (F) want QtUiTools? + # (G) want QtUiTools? parameters['no_qt_uitools'] = NoQtUiTools - # (G) options to `make` tool + # (H) options to `make` tool if not MakeOptions == "": parameters['make_options'] = MakeOptions try: @@ -700,7 +710,7 @@ def Get_Build_Parameters(config): else: parameters['num_parallel'] = pnum - # (H) about Ruby + # (I) about Ruby if ModuleRuby != "nil": parameters['ruby'] = RubyDictionary[ModuleRuby]['exe'] parameters['rbinc'] = RubyDictionary[ModuleRuby]['inc'] @@ -708,7 +718,7 @@ def Get_Build_Parameters(config): if 'inc2' in RubyDictionary[ModuleRuby]: parameters['rbinc2'] = RubyDictionary[ModuleRuby]['inc2'] - # (I) about Python + # (J) about Python if ModulePython != "nil": parameters['python'] = PythonDictionary[ModulePython]['exe'] parameters['pyinc'] = PythonDictionary[ModulePython]['inc'] @@ -720,21 +730,21 @@ def Get_Build_Parameters(config): config['MacBuildDirQAT'] = MacBuildDirQAT # relative path to build directory for QATest config['MacBuildLog'] = MacBuildLog # relative path to build log file - # (J) Extra parameters needed for deployment + # (K) Extra parameters needed for deployment parameters['project_dir'] = ProjectDir - # (K) Extra parameters needed for + # (L) Extra parameters needed for # will be built if: - # BuildPymod = True - # Platform = [ 'Sonoma', 'Ventura', 'Monterey'] - # ModuleRuby = [ 'Ruby33MacPorts', 'Ruby33Brew', 'RubyAnaconda3' ] - # ModulePython = [ 'Python311MacPorts', 'Python39MacPorts', - # 'Python311Brew', Python39Brew', 'PythonAutoBrew', - # 'PythonAnaconda3' ] - parameters['BuildPymod'] = BuildPymod - parameters['Platform'] = Platform - parameters['ModuleRuby'] = ModuleRuby - parameters['ModulePython'] = ModulePython + # BuildPymodWhl = True + # Platform = [ 'Sonoma', 'Ventura', 'Monterey'] + # ModuleRuby = [ 'Ruby33MacPorts', 'Ruby33Brew', 'RubyAnaconda3' ] + # ModulePython = [ 'Python311MacPorts', 'Python39MacPorts', + # 'Python311Brew', Python39Brew', 'PythonAutoBrew', + # 'PythonAnaconda3' ] + parameters['BuildPymodWhl'] = BuildPymodWhl + parameters['Platform'] = Platform + parameters['ModuleRuby'] = ModuleRuby + parameters['ModulePython'] = ModulePython PymodDistDir = dict() if Platform in [ 'Sonoma', 'Ventura', 'Monterey' ]: @@ -750,27 +760,27 @@ def Get_Build_Parameters(config): #------------------------------------------------------------------------------ ## To run the "setup.py" script with appropriate options for building -# the klayout Python Module "pymod". +# the klayout Python Module "pymod (*.whl)". # # @param[in] parameters dictionary containing the build parameters # # @return 0 on success; non-zero (1), otherwise #------------------------------------------------------------------------------ -def Build_pymod(parameters): +def Build_pymod_wheel(parameters): #----------------------------------------------------------------------------------------------------------- # [1] will be built if: - # BuildPymod = True - # Platform = [ 'Sonoma', 'Ventura', 'Monterey'] - # ModuleRuby = [ 'Ruby33MacPorts', 'Ruby33Brew', 'RubyAnaconda3' ] - # ModulePython = [ 'Python311MacPorts', 'Python39MacPorts', - # 'Python311Brew', Python39Brew', 'PythonAutoBrew', - # 'PythonAnaconda3' ] + # BuildPymodWhl = True + # Platform = [ 'Sonoma', 'Ventura', 'Monterey'] + # ModuleRuby = [ 'Ruby33MacPorts', 'Ruby33Brew', 'RubyAnaconda3' ] + # ModulePython = [ 'Python311MacPorts', 'Python39MacPorts', + # 'Python311Brew', Python39Brew', 'PythonAutoBrew', + # 'PythonAnaconda3' ] #----------------------------------------------------------------------------------------------------------- - BuildPymod = parameters['BuildPymod'] - Platform = parameters['Platform'] - ModuleRuby = parameters['ModuleRuby'] - ModulePython = parameters['ModulePython'] - if not BuildPymod: + BuildPymodWhl = parameters['BuildPymodWhl'] + Platform = parameters['Platform'] + ModuleRuby = parameters['ModuleRuby'] + ModulePython = parameters['ModulePython'] + if not BuildPymodWhl: return 0 if not Platform in [ 'Sonoma', 'Ventura', 'Monterey' ]: return 0 @@ -791,20 +801,24 @@ def Build_pymod(parameters): addBinPath = "/opt/local/bin" addIncPath = "/opt/local/include" addLibPath = "/opt/local/lib" + whlTarget = "MP3" # Using Homebrew elif PymodDistDir[ModulePython].find('dist-HB3') >= 0: addBinPath = "%s/bin" % DefaultHomebrewRoot # defined in "build4mac_env.py" addIncPath = "%s/include" % DefaultHomebrewRoot # -- ditto -- addLibPath = "%s/lib" % DefaultHomebrewRoot # -- ditto -- + whlTarget = "HB3" # Using Anaconda3 elif PymodDistDir[ModulePython].find('dist-ana3') >= 0: addBinPath = "/Applications/anaconda3/bin" addIncPath = "/Applications/anaconda3/include" addLibPath = "/Applications/anaconda3/lib" + whlTarget = "ana3" else: addBinPath = "" addIncPath = "" addLibPath = "" + whlTarget = "" if not addBinPath == "": try: @@ -888,7 +902,7 @@ def Build_pymod(parameters): return 0 #----------------------------------------------------- - # [5] Invoke the main Python scripts; takes time:-) + # [5-A] Invoke the main Python scripts; takes time:-) #----------------------------------------------------- myscript = os.path.basename(__file__) ret = subprocess.call( command1, shell=True ) @@ -910,12 +924,12 @@ def Build_pymod(parameters): return 1 #--------------------------------------------------------------------------------------------------------- - # 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/ + # [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/ #--------------------------------------------------------------------------------------------------------- - cmd3_args = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.28.6-cp39-cp39-macosx_12_0_x86_64.whl'] + cmd3_args = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.29.0-cp311-cp311-macosx_12_0_x86_64.whl'] if len(cmd3_args) == 1: command3 = "time" command3 += " \\\n %s \\\n" % deloc_cmd @@ -942,6 +956,42 @@ def Build_pymod(parameters): print( "", file=sys.stderr ) return 1 + #------------------------------------------------------------------------ + # [5-C] Forcibly change the wheel file name for anaconda3 + # Ref. https://github.com/Kazzz-S/klayout/issues/53 + # original: klayout-0.29.0-cp311-cp311-macosx_12_0_x86_64.whl + # | + # V + # new: klayout-0.29.0-cp311-cp311-macosx_10_9_x86_64.whl + #------------------------------------------------------------------------ + if whlTarget == "ana3": + wheels = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.29.0-cp311-cp311-macosx_12_0_x86_64.whl'] + if not len(wheels) == 1: + print( "", file=sys.stderr ) + print( "-------------------------------------------------------------", file=sys.stderr ) + print( "!!! <%s>: failed to " % 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 " % 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 ) + #----------------------------------------------------- # [6] Rename the "dist/" directory #----------------------------------------------------- @@ -961,9 +1011,9 @@ def Run_Build_Command(config, parameters): NoLibGit2 = config['NoLibGit2'] ToolDebug = config['ToolDebug'] if 100 not in ToolDebug: # default - jump2pymod = False + jump2pymod_wheel = False else: - jump2pymod = True + jump2pymod_wheel = True #----------------------------------------------------- # [1] Set two environment variables to use libgit2 @@ -996,7 +1046,7 @@ def Run_Build_Command(config, parameters): else: os.environ['MAC_LIBGIT2_LIB'] = "_invalid_MAC_LIBGIT2_LIB_" # link should fail - if not jump2pymod: + if not jump2pymod_wheel: #----------------------------------------------------- # [2] Set parameters passed to the main Bash script #----------------------------------------------------- @@ -1013,8 +1063,7 @@ def Run_Build_Command(config, parameters): # (C) Target directories and files MacBuildDirQAT = parameters['build'] + ".macQAT" - # (D) Qt5 | Qt6 (Homebrew) - #cmd_args += " \\\n -qt5" # make 'build.sh' detect the Qt type automatically + # (D) Qt5 (MacPorts, Homebrew, Anaconda3) | Qt6 (MacPorts, Homebrew) cmd_args += " \\\n -qmake %s" % parameters['qmake'] cmd_args += " \\\n -bin %s" % parameters['bin'] cmd_args += " \\\n -build %s" % parameters['build'] @@ -1130,9 +1179,9 @@ def Run_Build_Command(config, parameters): #------------------------------------------------------------------------ # [6] Build for some predetermined environments on demand #------------------------------------------------------------------------ - BuildPymod = parameters['BuildPymod'] - if BuildPymod: - ret = Build_pymod(parameters) + BuildPymodWhl = parameters['BuildPymodWhl'] + if BuildPymodWhl: + ret = Build_pymod_wheel(parameters) return ret else: return 0 @@ -1162,20 +1211,23 @@ def Deploy_Binaries_For_Bundle(config, parameters): ModulePython = config['ModulePython'] ToolDebug = config['ToolDebug'] HBPythonIs39 = config['HBPythonIs39'] + EmbedQt = config['EmbedQt'] + EmbedPython3 = config['EmbedPython3'] - BuildPymod = parameters['BuildPymod'] + BuildPymodWhl = parameters['BuildPymodWhl'] ProjectDir = parameters['project_dir'] MacBinDir = parameters['bin'] MacBuildDir = parameters['build'] MacBuildLog = parameters['logfile'] Platform = parameters['Platform'] + QtLibRoot = parameters['qt_lib_root'] AbsMacPkgDir = "%s/%s" % (ProjectDir, MacPkgDir) AbsMacBinDir = "%s/%s" % (ProjectDir, MacBinDir) AbsMacBuildDir = "%s/%s" % (ProjectDir, MacBuildDir) AbsMacBuildLog = "%s/%s" % (ProjectDir, MacBuildLog) - if BuildPymod: + if BuildPymodWhl: try: PymodDistDir = parameters['pymod_dist'] pymodDistDir = PymodDistDir[ModulePython] # [ 'dist-MP3-${ModuleQt}', 'dist-HB3-${ModuleQt}', 'dist-ana3-${ModuleQt}' ] @@ -1224,8 +1276,7 @@ def Deploy_Binaries_For_Bundle(config, parameters): print( " [3] Creating the standard directory structure for 'klayout.app' bundle ..." ) #-------------------------------------------------------------------------------------------------------------- - # [3] Create the directory skeleton for "klayout.app" bundle - # and command line buddy tools such as "strm2cif". + # [3] Create the directory skeleton for "klayout.app" bundle and command line buddy tools such as "strm2cif". # They are stored in the directory structure below. # # klayout.app/+ @@ -1237,12 +1288,15 @@ def Deploy_Binaries_For_Bundle(config, parameters): # +-- Frameworks/+ # | +-- '*.framework' # | +-- '*.dylib' - # | +-- 'db_plugins' --sym.link--> ../MacOS/db_plugins/ + # | +-- '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/ + # | # +-- Buddy/+ # | +-- 'strm2cif' # | +-- 'strm2dxf' @@ -1264,15 +1318,14 @@ def Deploy_Binaries_For_Bundle(config, parameters): os.makedirs(targetDirF) os.makedirs(targetDirM) os.makedirs(targetDirB) - if BuildPymod and not pymodDistDir == "": + if BuildPymodWhl and not pymodDistDir == "": os.makedirs(targetDirP) - print( " [4] Copying KLayout's dynamic link libraries to 'Frameworks' ..." ) - #--------------------------------------------------------------------------------------- - # [4] Copy KLayout's dynamic link libraries to "Frameworks/" and create - # the library dependency dictionary. - # <<< Do this job in "Frameworks/" >>> + 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/" >>> # # Note: # KLayout's dynamic link library is built as below: @@ -1299,11 +1352,11 @@ def Deploy_Binaries_For_Bundle(config, parameters): # 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) # : - #--------------------------------------------------------------------------------------- - os.chdir( targetDirF ) - dynamicLinkLibs = glob.glob( os.path.join( AbsMacBinDir, "*.dylib" ) ) - depDicOrdinary = {} # inter-library dependency dictionary - pathDic = {} # paths to insert for each library + #-------------------------------------------------------------------------------------------------------------- + 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 for item in dynamicLinkLibs: if os.path.isfile(item) and not os.path.islink(item): #------------------------------------------------------------------- @@ -1323,88 +1376,364 @@ def Deploy_Binaries_For_Bundle(config, parameters): otoolCm = "otool -L %s | grep dylib" % nameStyle3 otoolOut = os.popen( otoolCm ).read() dependDic = DecomposeLibraryDependency(otoolOut) - depDicOrdinary.update(dependDic) + dependencyDic_1.update(dependDic) #------------------------------------------------------------------- # (C) This library goes into Frameworks, hence record it's path there #------------------------------------------------------------------- - pathDic[nameStyle3] = "@executable_path/../Frameworks/" + nameStyle3 + pathDic_1[nameStyle3] = "@executable_path/../Frameworks/" + nameStyle3 + + 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..." ) os.chdir(ProjectDir) - #------------------------------------------------------------------- - # Copy the contents of the plugin directories to a place next to - # the application binary - #------------------------------------------------------------------- - for piDir in [ "db_plugins", "lay_plugins", "pymod" ]: - os.makedirs( os.path.join( targetDirM, piDir )) + #------------------------------------------------------------------------------- + # (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 ) ) dynamicLinkLibs = glob.glob( os.path.join( MacBinDir, piDir, "*.dylib" ) ) for item in dynamicLinkLibs: if os.path.isfile(item) and not os.path.islink(item): #------------------------------------------------------------------- - # (A) Copy an ordinary *.dylib file here by changing the name + # (B) 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" - destPath = os.path.join( targetDirM, piDir, nameStyle3 ) + destPath = os.path.join( targetDirM, piDir, nameStyle3 ) shutil.copy2( item, destPath ) os.chmod( destPath, 0o0755 ) #------------------------------------------------------------------- - # (B) Then get inter-library dependencies + # (C) Then get inter-library dependencies # Note that will pull all dependencies and sort them out later # dropping those which don't have a path entry #------------------------------------------------------------------- otoolCm = "otool -L %s | grep 'dylib'" % destPath otoolOut = os.popen( otoolCm ).read() dependDic = DecomposeLibraryDependency(otoolOut) - depDicOrdinary.update(dependDic) + dependencyDic_1.update(dependDic) #------------------------------------------------------------------- - # (C) This library goes into the plugin dir + # (D) This library goes into the plugin directory #------------------------------------------------------------------- - pathDic[nameStyle3] = "@executable_path/" + piDir + "/" + nameStyle3 + pathDic_1[nameStyle3] = "@executable_path/" + piDir + "/" + nameStyle3 - ''' - PrintLibraryDependencyDictionary( depDicOrdinary, pathDic, "Style (3)" ) - exit() - ''' + if 420 in ToolDebug: + DumpDependencyDicPair( "In [4-2 420]:", dependencyDic_1, pathDic_1 ) - #---------------------------------------------------------------------------------- - # (D) Make a symbolic link - # 'db_plugins' --slink--> ../MacOS/db_plugins/ - # under Frameworks/, which is required for the command line Buddy tools. + 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/. # - # Ref. https://github.com/KLayout/klayout/issues/460#issuecomment-571803458 + # 'db_plugins' is required for the command line Buddy tools. + # Ref. https://github.com/KLayout/klayout/issues/460#issuecomment-571803458 # # : # +-- Frameworks/+ # | +-- '*.framework' # | +-- '*.dylib' - # | +-- 'db_plugins' --sym.link--> ../MacOS/db_plugins/ + # | +-- '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/ # : - #---------------------------------------------------------------------------------- - os.chdir( targetDirF ) - os.symlink( "../MacOS/db_plugins/", "./db_plugins" ) + #-------------------------------------------------------------------------------------------------------------- + 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... + libPy3_1 = "%s/" % HBPython311FrameworkPath # /usr/local/opt/python@3.11/Frameworks/Python.framework/ + libPy3_2 = "%s/" % HBPython39FrameworkPath # /usr/local/opt/python@3.9/Frameworks/Python.framework/ + 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] - print( " [5] Setting and changing the identification names among KLayout's libraries ..." ) + #------------------------------------------------------------------- + # (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 ) + + if 443 in ToolDebug: + DumpDependencyDicPair( "In [4-4 443]:", dependencyDic_4, pathDic_4 ) + + print( " [5-1] Setting and changing the identification names among KLayout's libraries ..." ) #------------------------------------------------------------- - # [5] Set the identification names for KLayout's libraries + # [5-1] Set the identification names for KLayout's libraries # and make the library aware of the locations of libraries # on which it depends; that is, inter-library dependency #------------------------------------------------------------- - ret = SetChangeIdentificationNameOfDyLib( depDicOrdinary, pathDic ) + os.chdir(targetDirF) + ret = SetChangeIdentificationNameOfDyLib( dependencyDic_1, pathDic_1 ) if not ret == 0: - msg = "!!! Failed to set and change to new identification names !!!" + msg = "!!! Failed to set and change to new identification names with (dependencyDic_1, pathDic_1) !!!" print(msg) return 1 + 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 - print( " [6] Copying built executables and resource files ..." ) + print( " [6] Copying the built executables and resource files ..." ) #------------------------------------------------------------- # [6] Copy some known files in source directories to # relevant target directories @@ -1414,15 +1743,13 @@ def Deploy_Binaries_For_Bundle(config, parameters): sourceDir1 = sourceDir0 + "/MacOS" sourceDir2 = "%s/macbuild/Resources" % ProjectDir sourceDir3 = "%s" % MacBinDir - sourceDir4 = "%s/pymod" % MacBinDir # (A) the main components tmpfileM = ProjectDir + "/macbuild/Resources/Info.plist.template" keydicM = { 'exe': 'klayout', 'icon': 'klayout.icns', 'bname': 'klayout', 'ver': Version } plistM = GenerateInfoPlist( keydicM, tmpfileM ) - file = open( targetDir0 + "/Info.plist", "w" ) - file.write(plistM) - file.close() + with open( targetDir0 + "/Info.plist", "w" ) as file: + file.write(plistM) shutil.copy2( sourceDir0 + "/PkgInfo", targetDir0 ) # this file is not mandatory shutil.copy2( sourceDir1 + "/klayout", targetDirM ) @@ -1441,7 +1768,7 @@ def Deploy_Binaries_For_Bundle(config, parameters): os.chmod( targetDirB + "/" + buddy, 0o0755 ) # (C) the Pymod - if BuildPymod and not pymodDistDir == "": + if BuildPymodWhl and not pymodDistDir == "": for item in glob.glob( pymodDistDir + "/*.whl" ): shutil.copy2( item, targetDirP ) @@ -1471,7 +1798,7 @@ def Deploy_Binaries_For_Bundle(config, parameters): return 1 if DeploymentF: - print( " [8] Finally, deploying Qt's Frameworks ..." ) + print( " [8] Finally, deploying Qt's Frameworks and auxiliary libraries ..." ) #------------------------------------------------------------- # [8] Deploy Qt Frameworks #------------------------------------------------------------- @@ -1831,8 +2158,8 @@ def Deploy_Binaries_For_Bundle(config, parameters): #------------------------------------------------------------- # [10] Special deployment of Ruby3.3 from Homebrew? #------------------------------------------------------------- - deploymentRuby32HB = (ModuleRuby == 'Ruby33Brew') - if deploymentRuby32HB and NonOSStdLang: + deploymentRuby33HB = (ModuleRuby == 'Ruby33Brew') + if deploymentRuby33HB and NonOSStdLang: print( "" ) print( " [10] You have reached optional deployment of Ruby from %s ..." % HBRuby33Path ) @@ -1848,7 +2175,7 @@ def Deploy_Binaries_For_Bundle(config, parameters): else: print( " [8] Skipped deploying Qt's Frameworks and optional Python/Ruby Frameworks..." ) - print( "##### Finished deploying libraries and executables for #####" ) + print( "##### Finished deploying the libraries and executables for #####" ) print("") os.chdir(ProjectDir) return 0 diff --git a/macbuild/build4mac_env.py b/macbuild/build4mac_env.py index feb04bad89..c7d6f2e1f2 100755 --- a/macbuild/build4mac_env.py +++ b/macbuild/build4mac_env.py @@ -6,7 +6,7 @@ # # Here are dictionaries of ... # different modules for building KLayout (http://www.klayout.de/index.php) -# version 0.28.17 or later on different Apple Mac OSX platforms. +# version 0.29.0 or later on different Apple Mac OSX platforms. # # This file is imported by 'build4mac.py' script. #=============================================================================== @@ -72,14 +72,16 @@ # install with 'sudo port install [qt5|qt5-qttools]' # [Key Type Name] = 'Qt5MacPorts' Qt5MacPorts = { 'qmake' : '/opt/local/libexec/qt5/bin/qmake', - 'deploy': '/opt/local/libexec/qt5/bin/macdeployqt' + 'deploy': '/opt/local/libexec/qt5/bin/macdeployqt', + 'libdir': '/opt/local/libexec/qt5/lib' } # Qt5 from Homebrew (https://brew.sh/) # install with 'brew install qt5' # [Key Type Name] = 'Qt5Brew' Qt5Brew = { 'qmake' : '%s/opt/qt@5/bin/qmake' % DefaultHomebrewRoot, - 'deploy': '%s/opt/qt@5/bin/macdeployqt' % DefaultHomebrewRoot + 'deploy': '%s/opt/qt@5/bin/macdeployqt' % DefaultHomebrewRoot, + 'libdir': '%s/opt/qt@5/lib' % DefaultHomebrewRoot } # Qt5 bundled with anaconda3 installed under /Applications/anaconda3/ @@ -87,7 +89,8 @@ # If so, you need to make a symbolic link: /Applications/anaconda3 ---> $HOME/opt/anaconda3/ # [Key Type Name] = 'Qt5Ana3' Qt5Ana3 = { 'qmake' : '/Applications/anaconda3/bin/qmake', - 'deploy': '/Applications/anaconda3/bin/macdeployqt' + 'deploy': '/Applications/anaconda3/bin/macdeployqt', + 'libdir': '/Applications/anaconda3/lib' } #------------------------------------------------------------------------- @@ -97,16 +100,26 @@ # install with 'sudo port install [qt6|qt6-qttools]' # [Key Type Name] = 'Qt6MacPorts' Qt6MacPorts = { 'qmake' : '/opt/local/libexec/qt6/bin/qmake', - 'deploy': '/opt/local/libexec/qt6/bin/macdeployqt' + 'deploy': '/opt/local/libexec/qt6/bin/macdeployqt', + 'libdir': '/opt/local/libexec/qt6/lib' } # Qt6 from Homebrew (https://brew.sh/) # install with 'brew install qt6' # [Key Type Name] = 'Qt6Brew' Qt6Brew = { 'qmake' : '%s/opt/qt@6/bin/qmake' % DefaultHomebrewRoot, - 'deploy': '%s/opt/qt@6/bin/macdeployqt' % DefaultHomebrewRoot + 'deploy': '%s/opt/qt@6/bin/macdeployqt' % DefaultHomebrewRoot, + 'libdir': '%s/opt/qt@6/lib' % DefaultHomebrewRoot } +# Consolidated dictionary kit for Qt[5|6] +Qt56Dictionary = { 'Qt5MacPorts': Qt5MacPorts, + 'Qt5Brew' : Qt5Brew, + 'Qt5Ana3' : Qt5Ana3, + 'Qt6MacPorts': Qt6MacPorts, + 'Qt6Brew' : Qt6Brew + } + #----------------------------------------------------- # [2] Ruby # * Dropped the followings (2023-10-24). @@ -123,31 +136,46 @@ #----------------------------------------------------- # Whereabouts of different components of Ruby #----------------------------------------------------- +# % which ruby +# /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/bin/ruby +# +# % ruby -v +# ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.x86_64-darwin21] +# +# Where is the 'ruby.h' used to build the 'ruby' executable? +# +# % ruby -e "puts File.expand_path('ruby.h', RbConfig::CONFIG['rubyhdrdir'])" +# ===> /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk \ +# /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby.h +# # Bundled with Monterey (12.x) # [Key Type Name] = 'Sys' -MontereySDK = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" +MontereyXcSDK = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" +MontereyCLTSDK = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" RubyMonterey = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/bin/ruby', - 'inc': '%s/System/Library/Frameworks/Ruby.framework/Headers' % MontereySDK, - 'inc2': '%s/System/Library/Frameworks/Ruby.framework/Headers/ruby' % MontereySDK, - 'lib': '%s/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/libruby.tbd' % MontereySDK + 'inc': '%s/System/Library/Frameworks/Ruby.framework/Headers' % MontereyXcSDK, + 'inc2': '%s/System/Library/Frameworks/Ruby.framework/Headers/ruby' % MontereyXcSDK, + 'lib': '%s/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/libruby.tbd' % MontereyXcSDK } # Bundled with Ventura (13.x) # [Key Type Name] = 'Sys' -VenturaSDK = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" +VenturaXcSDK = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" +VenturaCLTSDK = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" RubyVentura = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/bin/ruby', - 'inc': '%s/System/Library/Frameworks/Ruby.framework/Headers' % VenturaSDK, - 'inc2': '%s/System/Library/Frameworks/Ruby.framework/Headers/ruby' % VenturaSDK, - 'lib': '%s/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/libruby.tbd' % VenturaSDK + 'inc': '%s/System/Library/Frameworks/Ruby.framework/Headers' % VenturaXcSDK, + 'inc2': '%s/System/Library/Frameworks/Ruby.framework/Headers/ruby' % VenturaXcSDK, + 'lib': '%s/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/libruby.tbd' % VenturaXcSDK } # Bundled with Sonoma (14.x) # [Key Type Name] = 'Sys' -SonomaSDK = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" +SonomaXcSDK = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" +SonomaCLTSDK = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" RubySonoma = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/bin/ruby', - 'inc': '%s/System/Library/Frameworks/Ruby.framework/Headers' % SonomaSDK, - 'inc2': '%s/System/Library/Frameworks/Ruby.framework/Headers/ruby' % SonomaSDK, - 'lib': '%s/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/libruby.tbd' % SonomaSDK + 'inc': '%s/System/Library/Frameworks/Ruby.framework/Headers' % SonomaXcSDK, + 'inc2': '%s/System/Library/Frameworks/Ruby.framework/Headers/ruby' % SonomaXcSDK, + 'lib': '%s/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/libruby.tbd' % SonomaXcSDK } # Ruby 3.3 from MacPorts (https://www.macports.org/) diff --git a/macbuild/build4mac_util.py b/macbuild/build4mac_util.py index 8241aebf7c..87980982b7 100755 --- a/macbuild/build4mac_util.py +++ b/macbuild/build4mac_util.py @@ -6,7 +6,7 @@ # # Here are utility functions and classes ... # for building KLayout (http://www.klayout.de/index.php) -# version 0.28.17 or later on different Apple Mac OSX platforms. +# version 0.29.0 or later on different Apple Mac OSX platforms. # # This file is imported by 'build4mac.py' script. #======================================================================================== @@ -16,6 +16,7 @@ import string import subprocess import shutil +import fnmatch #---------------------------------------------------------------------------------------- ## To import global dictionaries of different modules @@ -80,6 +81,9 @@ def PrintLibraryDependencyDictionary( depdic, pathdic, namedic ): # @return 0 on success; non-zero on failure #---------------------------------------------------------------------------------------- def SetChangeIdentificationNameOfDyLib( libdic, pathDic ): + if len(libdic) == 0 or len(pathDic) == 0: + return 0 + cmdNameId = XcodeToolChain['nameID'] cmdNameChg = XcodeToolChain['nameCH'] dependentLibs = libdic.keys() @@ -101,10 +105,9 @@ def SetChangeIdentificationNameOfDyLib( libdic, pathDic ): # [2] Make the library aware of the new identifications of all supporters #------------------------------------------------------------------------- supporters = libdic[lib] - for sup in supporters: - supName = os.path.basename(sup) - if libName != supName and (supName in pathDic): - nameOld = "%s" % sup + for supName in supporters: + if (libName != supName) and (supName in pathDic): + nameOld = "%s" % supName nameNew = pathDic[supName] command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, lib ) if subprocess.call( command, shell=True ) != 0: @@ -133,11 +136,15 @@ def SetChangeIdentificationNameOfDyLib( libdic, pathDic ): # +-- Frameworks/+ # | +-- '*.framework' # | +-- '*.dylib' -# | +-- 'db_plugins' --slink--> ../MacOS/db_plugins/ +# | +-- '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/ +# | # +-- Buddy/+ # +-- 'strm2cif' # +-- 'strm2dxf' @@ -790,6 +797,79 @@ def Generate_Start_Console_Py( template, pythonver, target ): else: return True +#---------------------------------------------------------------------------------------- +## To deeply copy directory contents +# +# @param[in] src_dir : source directory +# @param[in] dest_dir : destination directory +# @param[in] excl_pat_list: exclude pattern list (default=[]]) +# +# @return True on success, False on failure +#---------------------------------------------------------------------------------------- +def Deeply_Copy_Dir( src_dir, dest_dir, excl_pat_list=[] ): + + def FnameMatch(item): + for excl_pat in excl_pat_list: + if fnmatch.fnmatch( item, excl_pat ): + return True + return False + + if os.path.isfile(dest_dir): + print( "! Destination <%s> is an existing file" % dest_dir, file=sys.stderr ) + return False + + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + + for item in os.listdir(src_dir): + src_item = os.path.join(src_dir, item) + dest_item = os.path.join(dest_dir, item) + + if os.path.isdir(src_item): + if FnameMatch(item): + continue # skip copying if directory name matches the exclusion pattern + Deeply_Copy_Dir( src_item, dest_item, excl_pat_list ) + else: + if FnameMatch(item): + continue # skip copying if the file matches the exclusion pattern + shutil.copy2( src_item, dest_item ) + + return True + +#---------------------------------------------------------------------------------------- +## To dump the contents of a dependency dictionary +# +# @param[in] title: title +# @param[in] depDic: dependency dictionary to dump +# @param[in] pathDic: path dictionary to dump +# +# @return void +#---------------------------------------------------------------------------------------- +def DumpDependencyDicPair( title, depDic, pathDic ): + + print( "### Dependency Dictionary Pair <%s> ###" % title ) + + # depDic + count1 = 0 + for key1 in sorted(depDic.keys()): + count1 += 1 + diclist = depDic[key1] + print( " %3d:%s" % (count1, key1) ) + + count2 = 0 + for dict_file in diclist: + count2 += 1 + print( " %3d:%s" % (count2, dict_file) ) + + # pathDic + print( " ==========" ) + count3 = 0 + for key3 in sorted(pathDic.keys()): + count3 += 1 + print( " %3d:%s: %s" % (count3, key3, pathDic[key3]) ) + + return + #---------------- # End of File #---------------- diff --git a/macbuild/macQAT.py b/macbuild/macQAT.py index f62ffce162..bd73ddcc1d 100755 --- a/macbuild/macQAT.py +++ b/macbuild/macQAT.py @@ -5,7 +5,7 @@ # File: "macbuild/macQAT.py" # # The top Python script to run "ut_runner" after building KLayout -# (http://www.klayout.de/index.php) version 0.28.17 or later on different Apple +# (http://www.klayout.de/index.php) version 0.29.0 or later on different Apple # ßMac OSX platforms. # # This script must be copied to a "*.macQAT/" directory to run. @@ -25,6 +25,7 @@ def SetGlobals(): global ProjectDir # project directory where "ut_runner" exists global RunnerUsage # True to print the usage of 'ut_runner' + global StartKLayout # True to start the KLayout main GUI window global Run # True to run this script global ContinueOnError # True to continue after an error global TestsExcluded # list of tests to exclude @@ -54,6 +55,7 @@ def SetGlobals(): Usage += " -----------------------------------------------------------------+---------------\n" Usage += " [-u|--usage] : print usage of 'ut_runner'and exit | disabled\n" Usage += " |\n" + Usage += " [-k|--klayout] : just start the KLayout main GUI window | disabled\n" Usage += " <-r|--run> : run this script | disabled\n" Usage += " [-s|--stop] : stop on error | disabled\n" Usage += " [-x|--exclude ] : exclude test(s) such as 'pymod,pya' | ''\n" @@ -66,6 +68,7 @@ def SetGlobals(): ProjectDir = os.getcwd() RunnerUsage = False + StartKLayout = False Run = False ContinueOnError = True TestsExcluded = list() @@ -104,6 +107,7 @@ def GetTimeStamp(): def ParseCommandLineArguments(): global Usage global RunnerUsage + global StartKLayout global Run global ContinueOnError global TestsExcluded @@ -117,6 +121,12 @@ def ParseCommandLineArguments(): default=False, help="print usage of 'ut_runner' and exit (false)" ) + p.add_option( '-k', '--klayout', + action='store_true', + dest='start_KLayout', + default=False, + help='just start the KLayout main GUI window (false)' ) + p.add_option( '-r', '--run', action='store_true', dest='runme', @@ -152,6 +162,7 @@ def ParseCommandLineArguments(): help='check usage (false)' ) p.set_defaults( runner_usage = False, + start_KLayout = False, runme = False, stop_on_error = False, exclude_tests = list(), @@ -165,6 +176,7 @@ def ParseCommandLineArguments(): quit() RunnerUsage = opt.runner_usage + StartKLayout = opt.start_KLayout Run = opt.runme ContinueOnError = not opt.stop_on_error if not len(opt.exclude_tests) == 0: @@ -211,6 +223,18 @@ def ExportEnvVariables(): for env in [ 'TESTSRC', 'TESTTMP', 'LD_LIBRARY_PATH' ]: os.environ[env] = MyEnviron[env] +#------------------------------------------------------------------------------- +## Start the KLayout main GUI window +# +#------------------------------------------------------------------------------- +def StartKLatyouGUIWindow(): + if System == "Darwin": + command = "./klayout.app/Contents/MacOS/klayout" + else: + command = "./klayout" + + subprocess.call( command, shell=False ) + #------------------------------------------------------------------------------- ## Run the tester # @@ -255,35 +279,43 @@ def Main(): quit() #------------------------------------------------------- - # [3] Run the unit tester + # [3] Start the KLayout main GUI window + #------------------------------------------------------- + if StartKLayout: + StartKLatyouGUIWindow() + #------------------------------------------------------- - if not Run: - print( "! pass <-r|--run> option to run" ) + # [4] Run the unit tester + #------------------------------------------------------- + if not Run and not StartKLayout: + print( "! pass <-r|--run> option to run the QA tests" ) + print( "! pass <-k|--klayout> option to start the KLayout main GUI window" ) print(Usage) quit() - command = './ut_runner' - if ContinueOnError: - command += " -c" - for item in TestsExcluded: - command += ' -x %s' % item - if not len(Arguments) == 0: - for arg in Arguments: - command += " %s" % arg - - print( "" ) - print( "### Dumping the log to <%s>" % LogFile ) - print( "------------------------------------------------------------------------" ) - print( " Git SHA1 = %s" % GitSHA1 ) - print( " Time stamp = %s" % TimeStamp ) - print( " Command line = %s" % command ) - print( "------------------------------------------------------------------------" ) - if DryRun: - quit() - sleep(1.0) - HidePrivateDir() - RunTester( command, logfile=LogFile ) - ShowPrivateDir() + if Run: + command = './ut_runner' + if ContinueOnError: + command += " -c" + for item in TestsExcluded: + command += ' -x %s' % item + if not len(Arguments) == 0: + for arg in Arguments: + command += " %s" % arg + + print( "" ) + print( "### Dumping the log to <%s>" % LogFile ) + print( "------------------------------------------------------------------------" ) + print( " Git SHA1 = %s" % GitSHA1 ) + print( " Time stamp = %s" % TimeStamp ) + print( " Command line = %s" % command ) + print( "------------------------------------------------------------------------" ) + if DryRun: + quit() + sleep(1.0) + HidePrivateDir() + RunTester( command, logfile=LogFile ) + ShowPrivateDir() #=================================================================================== if __name__ == "__main__": diff --git a/macbuild/makeDMG4mac.py b/macbuild/makeDMG4mac.py index 1b2ae16835..1cdd03cde6 100755 --- a/macbuild/makeDMG4mac.py +++ b/macbuild/makeDMG4mac.py @@ -77,7 +77,7 @@ def SetGlobals(): Usage = "\n" Usage += "---------------------------------------------------------------------------------------------------------\n" Usage += "<< Usage of 'makeDMG4mac.py' >>\n" - Usage += " for making a DMG file of KLayout 0.28.17 or later on different Apple macOS platforms.\n" + Usage += " for making a DMG file of KLayout 0.29.0 or later on different Apple macOS platforms.\n" Usage += "\n" Usage += "$ [python] ./makeDMG4mac.py\n" Usage += " option & argument : descriptions | default value\n" @@ -162,36 +162,50 @@ def SetGlobals(): Item3AppleScript = "" # Populate DicStdLightHeavyW - DicStdLightHeavyW[ "std" ] = dict() # ST-* - DicStdLightHeavyW[ "ports" ] = dict() # LW-* - DicStdLightHeavyW[ "brew" ] = dict() # LW-* - DicStdLightHeavyW[ "ana3" ] = dict() # LW-* - DicStdLightHeavyW[ "brewH" ] = dict() # HW-* - - DicStdLightHeavyW[ "std" ]["zip"] = "macbuild/Resources/script-bundle-S.zip" - DicStdLightHeavyW[ "std" ]["src"] = "script-bundle-S" - DicStdLightHeavyW[ "std" ]["des"] = "MacStdUser-ReadMeFirst" - DicStdLightHeavyW[ "std" ]["item3"] = 'set position of item "MacStdUser-ReadMeFirst" to {700, 400}' - - DicStdLightHeavyW[ "ports" ]["zip"] = "macbuild/Resources/script-bundle-P.zip" - DicStdLightHeavyW[ "ports" ]["src"] = "script-bundle-P" - DicStdLightHeavyW[ "ports" ]["des"] = "MacPortsUser-ReadMeFirst" - DicStdLightHeavyW[ "ports" ]["item3"] = 'set position of item "MacPortsUser-ReadMeFirst" to {700, 400}' - - DicStdLightHeavyW[ "brew" ]["zip"] = "macbuild/Resources/script-bundle-B.zip" - DicStdLightHeavyW[ "brew" ]["src"] = "script-bundle-B" - DicStdLightHeavyW[ "brew" ]["des"] = "HomebrewUser-ReadMeFirst" - DicStdLightHeavyW[ "brew" ]["item3"] = 'set position of item "HomebrewUser-ReadMeFirst" to {700, 400}' - - DicStdLightHeavyW[ "ana3" ]["zip"] = "macbuild/Resources/script-bundle-A.zip" - DicStdLightHeavyW[ "ana3" ]["src"] = "script-bundle-A" - DicStdLightHeavyW[ "ana3" ]["des"] = "Anaconda3User-ReadMeFirst" - DicStdLightHeavyW[ "ana3" ]["item3"] = 'set position of item "Anaconda3User-ReadMeFirst" to {700, 400}' - - DicStdLightHeavyW[ "brewH" ]["zip"] = "macbuild/Resources/script-bundle-H.zip" - DicStdLightHeavyW[ "brewH" ]["src"] = "script-bundle-H" - DicStdLightHeavyW[ "brewH" ]["des"] = "Homebrew-HUser-ReadMeFirst" - DicStdLightHeavyW[ "brewH" ]["item3"] = 'set position of item "Homebrew-HUser-ReadMeFirst" to {700, 400}' + DicStdLightHeavyW[ "std" ] = dict() # ST-* + DicStdLightHeavyW[ "ports" ] = dict() # LW-* + DicStdLightHeavyW[ "brew" ] = dict() # LW-* + DicStdLightHeavyW[ "ana3" ] = dict() # LW-* + DicStdLightHeavyW[ "brewH" ] = dict() # HW-* + # "pbrew" is the alternative of "brew" using MacPorts' Qt and Homebrew's (Ruby, Python) + # "pbrewHW" is the alternative of "brewH" using MacPorts' Qt and Homebrew's Python + DicStdLightHeavyW[ "pbrew" ] = dict() # LW-* + DicStdLightHeavyW[ "pbrewHW" ] = dict() # HW-* + + DicStdLightHeavyW[ "std" ]["zip"] = "macbuild/Resources/script-bundle-S.zip" + DicStdLightHeavyW[ "std" ]["src"] = "script-bundle-S" + DicStdLightHeavyW[ "std" ]["des"] = "MacStdUser-ReadMeFirst" + DicStdLightHeavyW[ "std" ]["item3"] = 'set position of item "MacStdUser-ReadMeFirst" to {700, 400}' + + DicStdLightHeavyW[ "ports" ]["zip"] = "macbuild/Resources/script-bundle-P.zip" + DicStdLightHeavyW[ "ports" ]["src"] = "script-bundle-P" + DicStdLightHeavyW[ "ports" ]["des"] = "MacPortsUser-ReadMeFirst" + DicStdLightHeavyW[ "ports" ]["item3"] = 'set position of item "MacPortsUser-ReadMeFirst" to {700, 400}' + + DicStdLightHeavyW[ "brew" ]["zip"] = "macbuild/Resources/script-bundle-B.zip" + DicStdLightHeavyW[ "brew" ]["src"] = "script-bundle-B" + DicStdLightHeavyW[ "brew" ]["des"] = "HomebrewUser-ReadMeFirst" + DicStdLightHeavyW[ "brew" ]["item3"] = 'set position of item "HomebrewUser-ReadMeFirst" to {700, 400}' + + DicStdLightHeavyW[ "ana3" ]["zip"] = "macbuild/Resources/script-bundle-A.zip" + DicStdLightHeavyW[ "ana3" ]["src"] = "script-bundle-A" + DicStdLightHeavyW[ "ana3" ]["des"] = "Anaconda3User-ReadMeFirst" + DicStdLightHeavyW[ "ana3" ]["item3"] = 'set position of item "Anaconda3User-ReadMeFirst" to {700, 400}' + + DicStdLightHeavyW[ "brewH" ]["zip"] = "macbuild/Resources/script-bundle-H.zip" + DicStdLightHeavyW[ "brewH" ]["src"] = "script-bundle-H" + DicStdLightHeavyW[ "brewH" ]["des"] = "Homebrew-HUser-ReadMeFirst" + DicStdLightHeavyW[ "brewH" ]["item3"] = 'set position of item "Homebrew-HUser-ReadMeFirst" to {700, 400}' + + DicStdLightHeavyW[ "pbrew" ]["zip"] = "macbuild/Resources/script-bundle-B.zip" + DicStdLightHeavyW[ "pbrew" ]["src"] = "script-bundle-B" + DicStdLightHeavyW[ "pbrew" ]["des"] = "HomebrewUser-ReadMeFirst" + DicStdLightHeavyW[ "pbrew" ]["item3"] = 'set position of item "HomebrewUser-ReadMeFirst" to {700, 400}' + + DicStdLightHeavyW[ "pbrewHW" ]["zip"] = "macbuild/Resources/script-bundle-H.zip" + DicStdLightHeavyW[ "pbrewHW" ]["src"] = "script-bundle-H" + DicStdLightHeavyW[ "pbrewHW" ]["des"] = "Homebrew-HUser-ReadMeFirst" + DicStdLightHeavyW[ "pbrewHW" ]["item3"] = 'set position of item "Homebrew-HUser-ReadMeFirst" to {700, 400}' #------------------------------------------------------------------------------ ## To check the contents of the package directory @@ -199,18 +213,15 @@ def SetGlobals(): # The package directory name should look like: # * ST-qt5MP.pkg.macos-Monterey-release-RsysPsys # * LW-qt5Ana3.pkg.macos-Monterey-release-Rana3Pana3 -# * LW-qt5Brew.pkg.macos-Monterey-release-Rhb33Phb311 --- (1) +# * LW-qt6Brew.pkg.macos-Monterey-release-Rhb33Phb311 --- (1) # * LW-qt5MP.pkg.macos-Monterey-release-Rmp33Pmp311 -# * HW-qt5Brew.pkg.macos-Monterey-release-RsysPhb311 +# * HW-qt6Brew.pkg.macos-Monterey-release-RsysPhb311 # # * ST-qt6MP.pkg.macos-Monterey-release-RsysPsys -# * LW-qt6Ana3.pkg.macos-Monterey-release-Rana3Pana3 -# * LW-qt6Brew.pkg.macos-Monterey-release-Rhb33Phb311 # * LW-qt6MP.pkg.macos-Monterey-release-Rmp33Pmp311 -# * HW-qt6Brew.pkg.macos-Monterey-release-RsysPhb311 # # Generated DMG will be, for example, -# (1) ---> LW-klayout-0.28.17-macOS-Monterey-1-qt5Brew-Rhb33Phb311.dmg +# (1) ---> LW-klayout-0.29.0-macOS-Monterey-1-qt6Brew-Rhb33Phb311.dmg # # @return on success, positive integer in [MB] that tells approx. occupied disc space; # on failure, -1 @@ -251,16 +262,13 @@ def CheckPkgDirectory(): # [2] Identify (Qt, Ruby, Python) from PkgDir # * ST-qt5MP.pkg.macos-Monterey-release-RsysPsys # * LW-qt5Ana3.pkg.macos-Monterey-release-Rana3Pana3 - # * LW-qt5Brew.pkg.macos-Monterey-release-Rhb33Phb311 + # * LW-qt6Brew.pkg.macos-Monterey-release-Rhb33Phb311 # * LW-qt5MP.pkg.macos-Monterey-release-Rmp33Pmp311 - # * HW-qt5Brew.pkg.macos-Monterey-release-RsysPhb311 + # * HW-qt6Brew.pkg.macos-Monterey-release-RsysPhb311 # * EX-qt5MP.pkg.macos-Monterey-release-Rhb33Pmp311 # # * ST-qt6MP.pkg.macos-Monterey-release-RsysPsys - # * LW-qt6Ana3.pkg.macos-Monterey-release-Rana3Pana3 - # * LW-qt6Brew.pkg.macos-Monterey-release-Rhb33Phb311 # * LW-qt6MP.pkg.macos-Monterey-release-Rmp33Pmp311 - # * HW-qt6Brew.pkg.macos-Monterey-release-RsysPhb311 #----------------------------------------------------------------------------------------------- patQRP = u'(ST|LW|HW|EX)([-])([qt5|qt6][0-9A-Za-z]+)([.]pkg[.])([A-Za-z]+[-][A-Za-z]+[-]release[-])([0-9A-Za-z]+)' regQRP = re.compile(patQRP) @@ -299,7 +307,7 @@ def CheckPkgDirectory(): LatestOSHomebrew = Platform == LatestOS LatestOSHomebrew &= PackagePrefix == "LW" - LatestOSHomebrew &= QtIdentification in [ "qt5Brew", "qt6Brew" ] + LatestOSHomebrew &= QtIdentification in [ "qt5Brew", "qt6Brew", "qt5MP", "qt6MP" ] # "qt[5|6]MP" are the alternatives LatestOSHomebrew &= RubyPythonID in [ "Rhb33Phb311", "Rhb33Phb39", "Rhb33Phbauto" ] LatestOSAnaconda3 = Platform == LatestOS @@ -309,8 +317,8 @@ def CheckPkgDirectory(): LatestOSHomebrewH = Platform == LatestOS LatestOSHomebrewH &= PackagePrefix == "HW" - LatestOSHomebrewH &= QtIdentification in [ "qt5Brew", "qt6Brew" ] - LatestOSHomebrewH &= RubyPythonID in [ "RsysPhb311", "RsysPhb39", "RsysPhbauto" ] # Sys-Homebre hybrid + LatestOSHomebrewH &= QtIdentification in [ "qt5Brew", "qt6Brew", "qt5MP", "qt6MP" ] # "qt[5|6]MP" are the alternatives + LatestOSHomebrewH &= RubyPythonID in [ "RsysPhb311", "RsysPhb39", "RsysPhbauto" ] # Sys-Homebrew hybrid if LatestOSSys: mydic = DicStdLightHeavyW["std"] diff --git a/macbuild/nightlyBuild.py b/macbuild/nightlyBuild.py index 7ffb3d4160..3d6100b309 100755 --- a/macbuild/nightlyBuild.py +++ b/macbuild/nightlyBuild.py @@ -57,15 +57,18 @@ def Test_My_Platform( platforms=[ 'Monterey', 'Ventura', 'Sonoma' ] ): # @return a dictionary; key=integer, value=mnemonic #------------------------------------------------------------------------------ def Get_Build_Target_Dict(): - buildTargetDic = dict() - buildTargetDic[0] = 'std' - buildTargetDic[1] = 'ports' - buildTargetDic[2] = 'brew' - buildTargetDic[3] = 'brewHW' - buildTargetDic[4] = 'ana3' - - buildTargetDic[5] = 'brewA' - buildTargetDic[6] = 'brewAHW' + buildTargetDic = dict() + buildTargetDic[0] = 'std' + buildTargetDic[1] = 'ports' + buildTargetDic[2] = 'brew' + buildTargetDic[3] = 'brewHW' + buildTargetDic[4] = 'ana3' + + buildTargetDic[5] = 'brewA' + buildTargetDic[6] = 'brewAHW' + + buildTargetDic[12] = 'pbrew' # use MacPorts' Qt and Homebrew's (Ruby, Python) + buildTargetDic[13] = 'pbrewHW' # use MacPorts' Qt and Homebrew's Python return buildTargetDic #------------------------------------------------------------------------------ @@ -97,25 +100,32 @@ def Get_Build_Options( targetDic, platform ): buildOp[(qtVer, "ports")] = [ '-q', '%sMacPorts' % qtType, '-r', 'MP33', '-p', 'MP311' ] logfile[(qtVer, "ports")] = "%sMP.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "Rmp33Pmp311") elif target == "brew": - buildOp[(qtVer, "brew")] = [ '-q', '%sBrew' % qtType, '-r', 'HB33', '-p', 'HB311' ] + buildOp[(qtVer, "brew")] = [ '-q', '%sBrew' % qtType, '-r', 'HB33', '-p', 'HB311' ] logfile[(qtVer, "brew")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "Rhb33Phb311") elif target == "brewHW": - buildOp[(qtVer, "brewHW")] = [ '-q', '%sBrew' % qtType, '-r', 'sys', '-p', 'HB311' ] + buildOp[(qtVer, "brewHW")] = [ '-q', '%sBrew' % qtType, '-r', 'sys', '-p', 'HB311' ] logfile[(qtVer, "brewHW")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "RsysPhb311") elif target == "ana3": - buildOp[(qtVer, "ana3")] = [ '-q', '%sAna3' % qtType, '-r', 'Ana3', '-p', 'Ana3' ] + buildOp[(qtVer, "ana3")] = [ '-q', '%sAna3' % qtType, '-r', 'Ana3', '-p', 'Ana3' ] logfile[(qtVer, "ana3")] = "%sAna3.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "Rana3Pana3") elif target == "brewA": - buildOp[(qtVer, "brewA")] = [ '-q', '%sBrew' % qtType, '-r', 'HB33', '-p', 'HBAuto' ] + buildOp[(qtVer, "brewA")] = [ '-q', '%sBrew' % qtType, '-r', 'HB33', '-p', 'HBAuto' ] logfile[(qtVer, "brewA")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "Rhb33Phbauto") elif target == "brewAHW": - buildOp[(qtVer, "brewAHW")] = [ '-q', '%sBrew' % qtType, '-r', 'sys', '-p', 'HBAuto' ] + buildOp[(qtVer, "brewAHW")] = [ '-q', '%sBrew' % qtType, '-r', 'sys', '-p', 'HBAuto' ] logfile[(qtVer, "brewAHW")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "RsysPhbauto") + elif target == "pbrew": + buildOp[(qtVer, "pbrew")] = [ '-q', '%sMacPorts' % qtType, '-r', 'HB33', '-p', 'HB311' ] + logfile[(qtVer, "pbrew")] = "%sMP.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "Rhb33Phb311") + elif target == "pbrewHW": + buildOp[(qtVer, "pbrewHW")] = [ '-q', '%sMacPorts' % qtType, '-r', 'sys', '-p', 'HB311' ] + logfile[(qtVer, "pbrewHW")] = "%sMP.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "RsysPhb311") if WithPymod: buildOp[(qtVer,"ports")] = buildOp[(qtVer,"ports")] + ['--buildPymod'] buildOp[(qtVer,"brew")] = buildOp[(qtVer,"brew")] + ['--buildPymod'] buildOp[(qtVer,"ana3")] = buildOp[(qtVer,"ana3")] + ['--buildPymod'] + buildOp[(qtVer,"pbrew")] = buildOp[(qtVer,"pbrew")] + ['--buildPymod'] return (buildOp, logfile) @@ -152,6 +162,10 @@ def Get_QAT_Directory( targetDic, platform ): dirQAT[(qtVer, "brewA")] = '%sBrew.build.macos-%s-release-Rhb33Phbauto.macQAT' % (qtType.lower(), platform) elif target == "brewAHW": dirQAT[(qtVer, "brewAHW")] = '%sBrew.build.macos-%s-release-RsysPhbauto.macQAT' % (qtType.lower(), platform) + elif target == "pbrew": + dirQAT[(qtVer, "pbrew")] = '%sMP.build.macos-%s-release-Rhb33Phb311.macQAT' % (qtType.lower(), platform) + elif target == "pbrewHW": + dirQAT[(qtVer, "pbrewHW")] = '%sMP.build.macos-%s-release-RsysPhb311.macQAT' % (qtType.lower(), platform) return dirQAT @@ -182,19 +196,19 @@ def Get_Package_Options( targetDic, platform, srlDMG, makeflag ): for key in targetDic.keys(): target = targetDic[key] if target == "std": - packOp[(qtVer, "std")] = [ '-p', 'ST-%sMP.pkg.macos-%s-release-RsysPsys' % (qtType.lower(), platform), + packOp[(qtVer, "std")] = [ '-p', 'ST-%sMP.pkg.macos-%s-release-RsysPsys' % (qtType.lower(), platform), '-s', '%d' % srlDMG, '%s' % flag ] elif target == "ports": - packOp[(qtVer, "ports")] = [ '-p', 'LW-%sMP.pkg.macos-%s-release-Rmp33Pmp311' % (qtType.lower(), platform), + packOp[(qtVer, "ports")] = [ '-p', 'LW-%sMP.pkg.macos-%s-release-Rmp33Pmp311' % (qtType.lower(), platform), '-s', '%d' % srlDMG, '%s' % flag ] elif target == "brew": - packOp[(qtVer, "brew")] = [ '-p', 'LW-%sBrew.pkg.macos-%s-release-Rhb33Phb311' % (qtType.lower(), platform), + packOp[(qtVer, "brew")] = [ '-p', 'LW-%sBrew.pkg.macos-%s-release-Rhb33Phb311' % (qtType.lower(), platform), '-s', '%d' % srlDMG, '%s' % flag ] elif target == "brewHW": - packOp[(qtVer, "brewHW")] = [ '-p', 'HW-%sBrew.pkg.macos-%s-release-RsysPhb311' % (qtType.lower(), platform), + packOp[(qtVer, "brewHW")] = [ '-p', 'HW-%sBrew.pkg.macos-%s-release-RsysPhb311' % (qtType.lower(), platform), '-s', '%d' % srlDMG, '%s' % flag ] elif target == "ana3": - packOp[(qtVer, "ana3")] = [ '-p', 'LW-%sAna3.pkg.macos-%s-release-Rana3Pana3' % (qtType.lower(), platform), + packOp[(qtVer, "ana3")] = [ '-p', 'LW-%sAna3.pkg.macos-%s-release-Rana3Pana3' % (qtType.lower(), platform), '-s', '%d' % srlDMG, '%s' % flag ] elif target == "brewA": packOp[(qtVer, "brewA")] = [ '-p', 'LW-%sBrew.pkg.macos-%s-release-Rhb33Phbauto' % (qtType.lower(), platform), @@ -202,6 +216,12 @@ def Get_Package_Options( targetDic, platform, srlDMG, makeflag ): elif target == "brewAHW": packOp[(qtVer, "brewAHW")] = [ '-p', 'HW-%sBrew.pkg.macos-%s-release-RsysPhbauto' % (qtType.lower(), platform), '-s', '%d' % srlDMG, '%s' % flag ] + elif target == "pbrew": + packOp[(qtVer, "pbrew")] = [ '-p', 'LW-%sMP.pkg.macos-%s-release-Rhb33Phb311' % (qtType.lower(), platform), + '-s', '%d' % srlDMG, '%s' % flag ] + elif target == "pbrewHW": + packOp[(qtVer, "pbrewHW")] = [ '-p', 'HW-%sMP.pkg.macos-%s-release-RsysPhb311' % (qtType.lower(), platform), + '-s', '%d' % srlDMG, '%s' % flag ] return packOp #------------------------------------------------------------------------------ @@ -227,7 +247,7 @@ def Parse_CommandLine_Arguments(): if platform in [ "Sonoma", "Ventura", "Monterey" ]: targetopt = "0,1,2,3,4" else: - targetopt = None + targetopt = "" Usage = "\n" Usage += "----------------------------------------------------------------------------------------------------------\n" @@ -240,7 +260,7 @@ def Parse_CommandLine_Arguments(): Usage += " --------------------------------------------------------------------------+--------------\n" Usage += " [--qt ] : 5='qt5', 6='qt6' (migration to Qt6 is ongoing) | 5\n" Usage += " [--target ] : 0='std', 1='ports', 2='brew', 3='brewHW', 4='ana3', | '%s'\n" % targetopt - Usage += " 5='brewA', 6='brewAHW' |\n" + Usage += " 5='brewA', 6='brewAHW', 12='pbrew', 13='pbrewHW' |\n" Usage += " * with --qt=6, use --target='0,1,2,3' (4 is ignored) |\n" Usage += " [--qttarget ] : ex. '5,1' for qt=5, target=1 | disabled\n" Usage += " + This option supersedes, if used, the --qt and --target combination. |\n" @@ -266,7 +286,7 @@ def Parse_CommandLine_Arguments(): Usage += " (3) $ ./nightlyBuild.py --test |\n" Usage += " (4) $ ./nightlyBuild.py --check (confirm the QA Test results) |\n" Usage += " (5) $ ./nightlyBuild.py --makedmg 1 |\n" - Usage += " (6) $ ./nightlyBuild.py --upload '0.28.17' |\n" + Usage += " (6) $ ./nightlyBuild.py --upload '0.29.0' |\n" Usage += " (7) $ ./nightlyBuild.py --cleandmg 1 |\n" Usage += "-----------------------------------------------------------------------------+----------------------------\n" @@ -370,7 +390,7 @@ def Parse_CommandLine_Arguments(): targetDic = Get_Build_Target_Dict() Target = list() for idx in targetIdx: - if idx in range(0, 7): + if idx in [0,1,2,3,4,5,6,12,13]: Target.append( targetDic[idx] ) # Populate QtTarget @@ -393,7 +413,7 @@ def Parse_CommandLine_Arguments(): for i in range(0, len(df)): qt = df.iloc[i,0] idx = df.iloc[i,1] - if (qt == 5 and idx in range(0, 7)) or (qt == 6 and idx in [0,1,2,3, 5,6]): + if (qt == 5 and idx in [0,1,2,3,4,5,6,12,13]) or (qt == 6 and idx in [0,1,2,3, 5,6,12,13]): QtTarget.append( (qt, targetDic[idx]) ) elif len(opt.qt_target) > 0: QtTarget = list() @@ -401,7 +421,7 @@ def Parse_CommandLine_Arguments(): for item in opt.qt_target: qt = int(item.split(",")[0]) idx = int(item.split(",")[1]) - if (qt == 5 and idx in range(0, 7)) or (qt == 6 and idx in [0,1,2,3, 5,6]): + if (qt == 5 and idx in [0,1,2,3,4,5,6,12,13]) or (qt == 6 and idx in [0,1,2,3, 5,6,12,13]): QtTarget.append( (qt, targetDic[idx]) ) else: withqttarget = False @@ -462,7 +482,7 @@ def Build_Deploy(): command1 = [ pyBuilder ] + buildOp[(qttype, key)] - if key in [ "std", "brewHW", "brewAHW" ] : + if key in [ "std", "brewHW", "brewAHW", "pbrewHW" ] : command2 = "time" command2 += " \\\n %s" % pyBuilder for option in buildOp[(qttype, key)]: diff --git a/macbuild/nightlyBuild.sample.csv b/macbuild/nightlyBuild.sample.csv index edc13bc0a7..ed0f996c95 100644 --- a/macbuild/nightlyBuild.sample.csv +++ b/macbuild/nightlyBuild.sample.csv @@ -8,18 +8,21 @@ # qtVer,target # where # qtVer = 5 or 6 -# target = [0='std', 1='ports', 2='brew', 3='brewHW', 4='ana3'] +# target = [0='std', 1='ports', 2='brew', 3='brewHW', 4='ana3', +# 12='pbrew', 13='pbrewHW'] # note that # (qtVer,target)=(6,4) will be omitted #------------------------------------------------------------------------------- qtVer,target 5,0 5,1 -5,2 -5,3 +6,2 +6,13 5,4 #6,0 #6,1 #6,2 #6,3 #6,4 +#6,12 +#6,13 diff --git a/macbuild/python3HB.py b/macbuild/python3HB.py index a04f0e64ad..82046c09b9 100755 --- a/macbuild/python3HB.py +++ b/macbuild/python3HB.py @@ -27,17 +27,17 @@ def SetGlobals(): del System, Node, Release, MacVersion, Machine, Processor Usage = "\n" - Usage += "-------------------------------------------------------------------------------------\n" + Usage += "----------------------------------------------------------------------------------------\n" Usage += "<< Usage of 'python3HB.py' >>\n" Usage += " to setup the standardized directory structures for Homebrew's Python 3.x on Mac\n" Usage += "\n" Usage += " option & argument : descriptions | default value\n" - Usage += " -------------------------------------------------------------------+----------\n" + Usage += " -------------------------------------------------------------------+---------------\n" Usage += " <-v|--version >: in ['3.8', '3.9', '3.10', '3.11', '3.12', | ''\n" - Usage += " '3.13'] | ''\n" + Usage += " '3.13'] |\n" Usage += " [-u|-unlink] : unlink only | disabled\n" Usage += " [-?|--?] : print this usage and exit | disabled\n" - Usage += "----------------------------------------------------------------------+--------------\n" + Usage += "----------------------------------------------------------------------+-----------------\n" #------------------------------------------------------------------------------ # Parse the command line arguments