diff --git a/macbuild/ReadMe.md b/macbuild/ReadMe.md
index 454440bb2..e3140a15e 100644
--- a/macbuild/ReadMe.md
+++ b/macbuild/ReadMe.md
@@ -1,12 +1,13 @@
-Relevant KLayout version: 0.27.11
+Relevant KLayout version: 0.28.2
Author: Kazzz-S
-Last modified: 2022-10-10
+Last modified: 2022-12-24
# 1. Introduction
-This directory **`macbuild`** contains different files required for building KLayout (http://www.klayout.de/) version 0.27.11 or later for different 64-bit macOS, including:
+This directory **`macbuild`** contains various files required for building KLayout (http://www.klayout.de/) version 0.28.2 or later for different 64-bit macOS, including:
* Catalina (10.15.7) : the primary development environment
* Big Sur (11.x) : experimental; Apple M1 chip is not tested since the author does not own an M1 Mac
* Monterey (12.x) : -- ditto --
+* Ventura (13.x) : planning
Building KLayout for the previous operating systems listed below should still be possible.
However, they are not actively supported, and DMG packages are not provided.
@@ -43,11 +44,9 @@ If you have installed Anaconda3 under $HOME/opt/anaconda3/, make a symbolic link
```
The migration work to "Qt6" is ongoing. You can try to use it; however, you will encounter some build and runtime errors.
-For example, as of 2021-11-27, MacPorts' Qt6 does not provide `qt6-qtmultimedia`, which causes a build error.
# 3. Script language support: Ruby and Python
Earlier, by default, supported script languages, i.e., Ruby and Python, were those standard ones bundled with the OS.
-This configuration is possible only for macOS Catalina (10.15.7).
```
$ /usr/bin/ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin19]
@@ -55,11 +54,10 @@ $ /usr/bin/ruby -v
$ /usr/bin/python --version
Python 2.7.16
```
-
-Big Sur (11.x) and Monterey (< 12.3) still provide Python 2.7 binaries to run various legacy applications.
-However, the latest Xcode 13.1 does not allow us to link the legacy Python 2.7 library with the newly compiled KLayout binaries.
-Moreover, Monterey (12.3.1) finally eliminated the Python 2.7 binaries.
-Therefore, Homebrew is adopted as the default environment for Big Sur and Monterey.
+This configuration WAS possible only for macOS Catalina (10.15.7).
+However, it is no longer supported since KLayout version 0.28.x~ uses some Python3-specific features.
+Therefore, MacPorts' Ruby 3.1 and Python 3.8 are adopted as the default environment for Catalina.
+In contrast, Homebrew's Ruby 3.1 and Python 3.8 are the default environment for Big Sur and Monterey.
The build script **`build4mac.py`** provides several possible combinations of Qt5, Ruy, and Python modules to accommodate such a slightly complex environment.
Some typical use cases are described in Section 6.
@@ -71,12 +69,12 @@ You need to have the followings:
* 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`** are as shown below.
+# 5. Command-line options of **`build4mac.py`**
**((Notes))** For **Catalina**
```
---------------------------------------------------------------------------------------------------------
<< Usage of 'build4mac.py' >>
- for building KLayout 0.27.11 or later on different Apple macOS / Mac OSX platforms.
+ for building KLayout 0.28 or later on different Apple macOS / Mac OSX platforms.
$ [python] ./build4mac.py
option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details)| default value
@@ -89,16 +87,15 @@ $ [python] ./build4mac.py
: Qt6MacPorts: use Qt6 from MacPorts (*) |
: Qt6Brew: use Qt6 from Homebrew (*) |
: (*) migration to Qt6 is ongoing |
- [-r|--ruby ] : case-insensitive type=['nil', 'Sys', 'MP31', 'HB31', 'Ana3'] | sys
+ [-r|--ruby ] : case-insensitive type=['nil', 'Sys', 'MP31', 'HB31', 'Ana3'] | mp31
: nil: don't bind Ruby |
: Sys: use OS-bundled Ruby [2.0 - 2.6] depending on OS |
: MP31: use Ruby 3.1 from MacPorts |
: HB31: use Ruby 3.1 from Homebrew |
: Ana3: use Ruby 3.1 from Anaconda3 |
- [-p|--python ] : case-insensitive type=['nil', 'Sys', 'MP38', 'HB38', 'Ana3', | sys
+ [-p|--python ] : case-insensitive type=['nil', 'MP38', 'HB38', 'Ana3', | mp38
: HB39', 'HBAuto'] |
: nil: don't bind Python |
- : Sys: use OS-bundled Python 2.7 [ElCapitan -- Catalina] |
: MP38: use Python 3.8 from MacPorts |
: HB38: use Python 3.8 from Homebrew |
: Ana3: use Python 3.8 from Anaconda3 |
@@ -110,7 +107,7 @@ $ [python] ./build4mac.py
[-m|--make ] : option passed to 'make' | '--jobs=4'
[-d|--debug] : enable debug mode build | disabled
[-c|--checkcom] : check command-line and exit without building | disabled
- [-y|--deploy] : deploy executables and dylibs including Qt's Frameworks | disabled
+ [-y|--deploy] : deploy executables and dylibs, including Qt's Frameworks | disabled
[-Y|--DEPLOY] : deploy executables and dylibs for those who built KLayout | disabled
: from the source code and use the tools in the same machine |
: ! After confirmation of the successful build of 'klayout.app', |
@@ -129,7 +126,7 @@ $ [python] ./build4mac.py
```
---------------------------------------------------------------------------------------------------------
<< Usage of 'build4mac.py' >>
- for building KLayout 0.27.11 or later on different Apple macOS / Mac OSX platforms.
+ for building KLayout 0.28 or later on different Apple macOS / Mac OSX platforms.
$ [python] ./build4mac.py
option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details)| default value
@@ -148,10 +145,9 @@ $ [python] ./build4mac.py
: MP31: use Ruby 3.1 from MacPorts |
: HB31: use Ruby 3.1 from Homebrew |
: Ana3: use Ruby 3.1 from Anaconda3 |
- [-p|--python ] : case-insensitive type=['nil', 'Sys', 'MP38', 'HB38', 'Ana3', | hb38
+ [-p|--python ] : case-insensitive type=['nil', 'MP38', 'HB38', 'Ana3', | hb38
: HB39', 'HBAuto'] |
: nil: don't bind Python |
- : Sys: use OS-bundled Python 2.7 [ElCapitan -- Catalina] |
: MP38: use Python 3.8 from MacPorts |
: HB38: use Python 3.8 from Homebrew |
: Ana3: use Python 3.8 from Anaconda3 |
@@ -163,7 +159,7 @@ $ [python] ./build4mac.py
[-m|--make ] : option passed to 'make' | '--jobs=4'
[-d|--debug] : enable debug mode build | disabled
[-c|--checkcom] : check command-line and exit without building | disabled
- [-y|--deploy] : deploy executables and dylibs including Qt's Frameworks | disabled
+ [-y|--deploy] : deploy executables and dylibs, including Qt's Frameworks | disabled
[-Y|--DEPLOY] : deploy executables and dylibs for those who built KLayout | disabled
: from the source code and use the tools in the same machine |
: ! After confirmation of the successful build of 'klayout.app', |
@@ -179,41 +175,10 @@ $ [python] ./build4mac.py
```
# 6. Use-cases
-In this section, the actual file names and directory names are those obtained on macOS Catalina.
+In this section, the actual file and directory names are those obtained on macOS Catalina.
On different OS, those names differ accordingly.
-### 6A. Standard build using the OS-bundled Ruby and Python
-0. Install MacPorts, then install Qt5 by
-```
-$ sudo port install coreutils
-$ sudo port install findutils
-$ sudo port install qt5
-```
-1. Invoke **`build4mac.py`** with the default options: **((Notes))** only for Catalina
-```
-$ cd /where/'build.sh'/exists
-$ ./build4mac.py
-```
-2. Confirm successful build (it will take about one hour, depending on your machine spec).
-3. Run **`build4mac.py`** again with the same options used in 1. PLUS "-y" to deploy executables and libraries (including Qt's framework) under **`klayout.app`** bundle.
- The buddy command-line tools (strm*) will also be deployed in this step.
-```
-$ ./build4mac.py -y
-```
- The application bundle **`klayout.app`** is located under:
- **`ST-qt5MP.pkg.macos-Catalina-release-RsysPsys`** directory, where the three name parts below are important.
-* "ST-" means that this is a standard package (LW-, HW-, and EX- are other possibilities explained below).
-* "qt5MP" means that Qt5 from MacPorts is used.
-* "RsysPsys" means that Ruby is OS-bundled; Python is OS-bundled.
-4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
-
-If you use the "-Y" option instead of the "-y" in Step-3, the Qt5 framework is NOT deployed in the application bundle.
-Then the directory name will be **`LW-qt5MP.pkg.macos-Catalina-release-RsysPsys`**, where
-* "LW-" means that this is a lightweight package.
-
-#### If you build KLayout from the source code AND run it on the same machine, the "-Y" option is highly recommended.
-
-### 6B. Fully MacPorts-flavored build with MacPorts Ruby 3.1 and MacPorts Python 3.8
+### 6A. Fully MacPorts-flavored build with MacPorts Ruby 3.1 and MacPorts Python 3.8
0. Install MacPorts, then install Qt5, Ruby 3.1, and Python 3.8 by
```
$ sudo port install coreutils
@@ -229,7 +194,7 @@ $ cd /where/'build.sh'/exists
$ ./build4mac.py -q qt5macports -r mp31 -p mp38
```
2. Confirm successful build (it will take about one hour, depending on your machine spec).
-3. Run **`build4mac.py`** again with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.
+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, \*.egg) will be built and deployed under **klayout.app/Contents/pymod-dist/**.
@@ -238,12 +203,12 @@ $ ./build4mac.py -q qt5macports -r mp31 -p mp38 -Y
```
The application bundle **`klayout.app`** is located under:
**`LW-qt5MP.pkg.macos-Catalina-release-Rmp31Pmp38`** directory, where
-* "LW-" means that this is a lightweight package.
+* "LW-" means this is a lightweight package.
* "qt5MP" means that Qt5 from MacPorts is used.
* "Rmp31Pmp38" means that Ruby is 3.1 from MacPorts; Python is 3.8 from MacPorts.
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
-### 6C. Fully Homebrew-flavored build with Homebrew Ruby 3.1 and Homebrew Python 3.8
+### 6B. Fully Homebrew-flavored build with Homebrew Ruby 3.1 and Homebrew Python 3.8
0. Install Homebrew, then install Qt5, Ruby 3.1, and Python 3.8 by
```
$ brew install qt@5
@@ -256,7 +221,7 @@ $ cd /where/'build.sh'/exists
$ ./build4mac.py -q qt5brew -r hb31 -p hb38
```
2. Confirm successful build (it will take about one hour, depending on your machine spec).
-3. Run **`build4mac.py`** again with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.
+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, \*.egg) will be built and deployed under **klayout.app/Contents/pymod-dist/**.
@@ -265,12 +230,12 @@ $ ./build4mac.py -q qt5brew -r hb31 -p hb38 -Y
```
The application bundle **`klayout.app`** is located under:
**`LW-qt5Brew.pkg.macos-Catalina-release-Rhb31Phb38`** directory, where
-* "LW-" means that this is a lightweight package.
+* "LW-" means this is a lightweight package.
* "qt5Brew" means that Qt5 from Homebrew is used.
* "Rhb31Phb38" means that Ruby is 3.1 from Homebrew; Python is 3.8 from Homebrew.
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
-### 6D. Partially Homebrew-flavored build with System Ruby and Homebrew Python 3.8
+### 6C. Partially Homebrew-flavored build with System Ruby and Homebrew Python 3.8
0. Install Homebrew, then install Qt5 and Python 3.8 by
```
$ brew install qt@5
@@ -282,7 +247,7 @@ $ cd /where/'build.sh'/exists
$ ./build4mac.py -q qt5brew -r sys -p hb38
```
2. Confirm successful build (it will take about one hour, depending on your machine spec).
-3. Run **`build4mac.py`** again with the same options used in 1. PLUS "-y" to deploy executables and libraries (including Qt and Python frameworks) under the **`klayout.app`** bundle.
+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.
```
@@ -290,7 +255,7 @@ $ ./build4mac.py -q qt5brew -r sys -p hb38 -y
```
The application bundle **`klayout.app`** is located under:
**`HW-qt5Brew.pkg.macos-Catalina-release-RsysPhb38`** directory, where
-* "HW-" means that this is a heavyweight package because both Qt5 and Python Frameworks are deployed.
+* "HW-" means this is a heavyweight package because both Qt5 and Python Frameworks are deployed.
* "qt5Brew" means that Qt5 from Homebrew is used.
* "RsysPhb38" means that Ruby is OS-bundled; Python is 3.8 from Homebrew.
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
@@ -298,7 +263,7 @@ $ ./build4mac.py -q qt5brew -r sys -p hb38 -y
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.1 and Anaconda3 Python 3.8
+### 6D. Fully Anaconda3-flavored build with Anaconda3 Ruby 3.1 and Anaconda3 Python 3.8
0. Install Anaconda3, then install Ruby 3.1 by
```
$ conda install ruby
@@ -309,7 +274,7 @@ $ cd /where/'build.sh'/exists
$ ./build4mac.py -q qt5ana3 -r ana3 -p ana3
```
2. Confirm successful build (it will take about one hour, depending on your machine spec).
-3. Run **`build4mac.py`** again with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.
+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, \*.egg) will be built and deployed under **klayout.app/Contents/pymod-dist/**.
@@ -318,7 +283,7 @@ $ ./build4mac.py -q qt5ana3 -r ana3 -p ana3 -Y
```
The application bundle **`klayout.app`** is located under:
**`LW-qt5Ana3.pkg.macos-Catalina-release-Rana3Pana3`** directory, where
-* "LW-" means that this is a lightweight package.
+* "LW-" means this is a lightweight package.
* "qt5Ana3" means that Qt5 from Anaconda3 is used.
* "Rana3Pana3" means that Ruby (3.1) is from Anaconda3; Python (3.8) is from Anaconda3.
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
@@ -327,15 +292,15 @@ $ ./build4mac.py -q qt5ana3 -r ana3 -p ana3 -Y
export PYTHONHOME=$HOME/opt/anaconda3
```
-### 6F. Other combinations
-Logically, several different module combinations other than 6A through 6E are possible, including `nil` choice.
+### 6E. Other combinations
+Logically, several module combinations other than 6A through 6D are possible, including `nil` choice.
The resultant package directory name will begin with **`EX-`** (exceptional) if you choose such a combination.
----
# 7. Making a DMG installer
You can make a DMG installer using another Python script **`makeDMG4mac.py`**.
-This script requires a directory generated by **`build4mac.py`** with the [-y|-Y] option (refer to 6A through 6E).
+This script requires a directory generated by **`build4mac.py`** with the [-y|-Y] option (refer to 6A through 6D).
1. Make a symbolic link (if it does not exist) from the parent directory (where **`build.sh`** exists) to **`makeDMG4mac.py`**, that is,
```
@@ -344,11 +309,11 @@ makeDMG4mac.py -> macbuild/makeDMG4mac.py
2. Invoke **`makeDMG4mac.py`** with -p and -m options, for example,
```
$ cd /where/'build.sh'/exists
-$ ./makeDMG4mac.py -p ST-qt5MP.pkg.macos-Catalina-release-RsysPsys -m
+$ ./makeDMG4mac.py -p LW-qt5MP.pkg.macos-Catalina-release-Rmp31Pmp38 -m
```
This command will generate the two files below:
-* **`ST-klayout-0.27.11-macOS-Catalina-1-qt5MP-RsysPsys.dmg`** ---(1) the main DMG file
-* **`ST-klayout-0.27.11-macOS-Catalina-1-qt5MP-RsysPsys.dmg.md5`** ---(2) MD5-value text file
+* **`LW-klayout-0.28.2-macOS-Catalina-1-qt5MP-Rmp31Pmp38.dmg`** ---(1) the main DMG file
+* **`LW-klayout-0.28.2-macOS-Catalina-1-qt5MP-Rmp31Pmp38.dmg.md5`** ---(2) MD5-value text file
# Known issues
Because we assume some specific versions of non-OS-standard Ruby and Python, updating MacPorts, Homebrew, or Anaconda3 may cause build- and link errors.
@@ -356,7 +321,7 @@ In such cases, you need to update the dictionary contents of **`build4mac_env.py
# Final comments
No need to say KLayout is a great tool!
-With the object-oriented script language (both Ruby and Python) support, our error-prone layout jobs can be greatly simplified and sped up.
+With the object-oriented script language (both Ruby and Python) support, our error-prone layout jobs can be significantly simplified and sped up.
Building KLayout from its source code is not difficult. Try it with your favorite environment!
[End of File]
diff --git a/macbuild/Resources/icon-resources/klayout-Ana3.Rocket.icns b/macbuild/Resources/icon-resources/klayout-Ana3.Rocket.icns
new file mode 100644
index 000000000..dec4a09fc
Binary files /dev/null and b/macbuild/Resources/icon-resources/klayout-Ana3.Rocket.icns differ
diff --git a/macbuild/Resources/icon-resources/klayout-Ana3.Rocket.logoist b/macbuild/Resources/icon-resources/klayout-Ana3.Rocket.logoist
new file mode 100644
index 000000000..c9dfc7d98
Binary files /dev/null and b/macbuild/Resources/icon-resources/klayout-Ana3.Rocket.logoist differ
diff --git a/macbuild/Resources/icon-resources/klayout-Ana3.Rocket.png b/macbuild/Resources/icon-resources/klayout-Ana3.Rocket.png
new file mode 100644
index 000000000..9e337c277
Binary files /dev/null and b/macbuild/Resources/icon-resources/klayout-Ana3.Rocket.png differ
diff --git a/macbuild/Resources/icon-resources/klayout-HB.Rocket.icns b/macbuild/Resources/icon-resources/klayout-HB.Rocket.icns
new file mode 100644
index 000000000..3fc84bf08
Binary files /dev/null and b/macbuild/Resources/icon-resources/klayout-HB.Rocket.icns differ
diff --git a/macbuild/Resources/icon-resources/klayout-HB.Rocket.logoist b/macbuild/Resources/icon-resources/klayout-HB.Rocket.logoist
new file mode 100644
index 000000000..22e9adc0d
Binary files /dev/null and b/macbuild/Resources/icon-resources/klayout-HB.Rocket.logoist differ
diff --git a/macbuild/Resources/icon-resources/klayout-HB.Rocket.png b/macbuild/Resources/icon-resources/klayout-HB.Rocket.png
new file mode 100644
index 000000000..6f472f92d
Binary files /dev/null and b/macbuild/Resources/icon-resources/klayout-HB.Rocket.png differ
diff --git a/macbuild/Resources/icon-resources/klayout-Ports.Rocket.icns b/macbuild/Resources/icon-resources/klayout-Ports.Rocket.icns
new file mode 100644
index 000000000..83f6b138a
Binary files /dev/null and b/macbuild/Resources/icon-resources/klayout-Ports.Rocket.icns differ
diff --git a/macbuild/Resources/icon-resources/klayout-Ports.Rocket.logoist b/macbuild/Resources/icon-resources/klayout-Ports.Rocket.logoist
new file mode 100644
index 000000000..48e3cb9d9
Binary files /dev/null and b/macbuild/Resources/icon-resources/klayout-Ports.Rocket.logoist differ
diff --git a/macbuild/Resources/icon-resources/klayout-Ports.Rocket.png b/macbuild/Resources/icon-resources/klayout-Ports.Rocket.png
new file mode 100644
index 000000000..ddcdeb4e2
Binary files /dev/null and b/macbuild/Resources/icon-resources/klayout-Ports.Rocket.png differ
diff --git a/macbuild/Resources/script-bundle-A.zip b/macbuild/Resources/script-bundle-A.zip
index 7b3cce1b4..f71bc03e5 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 47e09bc21..5d212776d 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
new file mode 100644
index 000000000..3961b86b1
Binary files /dev/null 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 9a5446ba7..553743469 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-bundles.zip b/macbuild/Resources/script-bundles.zip
index bb82e0847..99fdc745c 100644
Binary files a/macbuild/Resources/script-bundles.zip and b/macbuild/Resources/script-bundles.zip differ
diff --git a/macbuild/build4mac.py b/macbuild/build4mac.py
index 6996a7ce0..8a5fdc4a0 100755
--- a/macbuild/build4mac.py
+++ b/macbuild/build4mac.py
@@ -38,16 +38,16 @@ def GenerateUsage(platform):
myRuby = "hb31"
myPython = "hb38"
moduleset = ('qt5Brew', 'HB31', 'HB38')
- else: # with Xcode [ .. 12.4]
+ else: # with Xcode [ .. 12.4]; 'sys' for Python has been abolished in 0.28
myQt56 = "qt5macports"
- myRuby = "sys"
- myPython = "sys"
- moduleset = ('qt5MP', 'Sys', 'Sys')
+ myRuby = "mp31"
+ myPython = "mp38"
+ moduleset = ('qt5MP', 'MP31', 'MP38')
usage = "\n"
usage += "---------------------------------------------------------------------------------------------------------\n"
usage += "<< Usage of 'build4mac.py' >>\n"
- usage += " for building KLayout 0.27.11 or later on different Apple macOS / Mac OSX platforms.\n"
+ usage += " for building KLayout 0.28 or later on different Apple macOS / Mac OSX platforms.\n"
usage += "\n"
usage += "$ [python] ./build4mac.py\n"
usage += " option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details)| default value\n"
@@ -66,10 +66,9 @@ def GenerateUsage(platform):
usage += " : MP31: use Ruby 3.1 from MacPorts | \n"
usage += " : HB31: use Ruby 3.1 from Homebrew | \n"
usage += " : Ana3: use Ruby 3.1 from Anaconda3 | \n"
- usage += " [-p|--python ] : case-insensitive type=['nil', 'Sys', 'MP38', 'HB38', 'Ana3', | %s \n" % myPython
+ usage += " [-p|--python ] : case-insensitive type=['nil', 'MP38', 'HB38', 'Ana3', | %s \n" % myPython
usage += " : HB39', 'HBAuto'] | \n"
usage += " : nil: don't bind Python | \n"
- usage += " : Sys: use OS-bundled Python 2.7 [ElCapitan -- Catalina] | \n"
usage += " : MP38: use Python 3.8 from MacPorts | \n"
usage += " : HB38: use Python 3.8 from Homebrew | \n"
usage += " : Ana3: use Python 3.8 from Anaconda3 | \n"
@@ -81,10 +80,10 @@ def GenerateUsage(platform):
usage += " [-m|--make ] : option passed to 'make' | '--jobs=4'\n"
usage += " [-d|--debug] : enable debug mode build | disabled\n"
usage += " [-c|--checkcom] : check command-line and exit without building | disabled\n"
- usage += " [-y|--deploy] : deploy executables and dylibs including Qt's Frameworks | disabled\n"
+ usage += " [-y|--deploy] : deploy executables and dylibs, including Qt's Frameworks | disabled\n"
usage += " [-Y|--DEPLOY] : deploy executables and dylibs for those who built KLayout | disabled\n"
usage += " : from the source code and use the tools in the same machine | \n"
- usage += " : ! After confirmation of the uccessful build of 'klayout.app', | \n"
+ usage += " : ! After confirmation of the successful build of 'klayout.app', | \n"
usage += " : rerun this script with BOTH: | \n"
usage += " : 1) the same options used for building AND | \n"
usage += " : 2) <-y|--deploy> OR <-Y|--DEPLOY> | \n"
@@ -387,7 +386,7 @@ def Parse_CLI_Args(config):
p.add_option( '-p', '--python',
dest='type_python',
- help="Python type=['nil', 'Sys', 'MP38', 'HB38', 'Ana3', 'HB39', 'HBAuto']" )
+ help="Python type=['nil', 'MP38', 'HB38', 'Ana3', 'HB39', 'HBAuto']" )
p.add_option( '-P', '--buildPymod',
action='store_true',
@@ -461,8 +460,8 @@ def Parse_CLI_Args(config):
checkusage = False )
else: # with Xcode [ .. 12.4]
p.set_defaults( type_qt = "qt5macports",
- type_ruby = "sys",
- type_python = "sys",
+ type_ruby = "mp31",
+ type_python = "mp38",
build_pymod = False,
no_qt_binding = False,
no_qt_uitools = False,
@@ -562,7 +561,7 @@ def Parse_CLI_Args(config):
# (C) Determine the Python type
candidates = dict()
candidates['NIL'] = 'nil'
- candidates['SYS'] = 'Sys'
+ # candidates['SYS'] = 'Sys' # has been abolished in 0.28
candidates['MP38'] = 'MP38'
candidates['HB38'] = 'HB38'
candidates['ANA3'] = 'Ana3'
@@ -875,9 +874,29 @@ def Build_pymod(parameters):
return 0
#--------------------------------------------------------------------
- # [2] Get the new directory names (dictionary) for "dist"
+ # [2] Get the new directory names (dictionary) for "dist" and
+ # set the CPATH environment variable for including
+ # required to build the pymod of 0.28 or later
#--------------------------------------------------------------------
PymodDistDir = parameters['pymod_dist']
+ # Using MacPorts
+ if PymodDistDir[ModulePython] == 'dist-MP3':
+ addIncPath = "/opt/local/include"
+ # Using Homebrew
+ elif PymodDistDir[ModulePython] == 'dist-HB3':
+ addIncPath = "%s/include" % DefaultHomebrewRoot # defined in "build4mac_env.py"
+ # Using Anaconda3
+ elif PymodDistDir[ModulePython] == 'dist-ana3':
+ addIncPath = "/Applications/anaconda3/include"
+ else:
+ addIncPath = ""
+ if not addIncPath == "":
+ try:
+ cpath = os.environ['CPATH']
+ except KeyError:
+ os.environ['CPATH'] = addIncPath
+ else:
+ os.environ['CPATH'] = "%s:%s" % (addIncPath, cpath)
#--------------------------------------------------------------------
# [3] Set different command line parameters for building
@@ -1491,6 +1510,36 @@ def Deploy_Binaries_For_Bundle(config, parameters):
# in "/usr/local/opt/python@3.8/lib/"
# Python.framework -> ../Frameworks/Python.framework/ <=== this symbolic was needed
# pkgconfig/
+ #
+ # Use the "python3HB.py" tool to make different symbolic links [*] including the above one.
+ # Catalina0{kazzz-s} lib (1)% pwd
+ # /usr/local/opt/python@3.8/lib
+ # Catalina0{kazzz-s} lib (2)% ll
+ # total 0
+ # drwxr-xr-x 4 kazzz-s admin 128 12 16 21:40 .
+ # drwxr-xr-x 13 kazzz-s admin 416 12 12 23:08 ..
+ # [*] lrwxr-xr-x 1 kazzz-s admin 31 12 16 21:40 Python.framework -> ../Frameworks/Python.framework/
+ # drwxr-xr-x 4 kazzz-s admin 128 12 12 23:08 pkgconfig
+ #
+ # Catalina0{kazzz-s} Python.framework (3)% pwd
+ # /usr/local/opt/python@3.8/Frameworks/Python.framework/Versions
+ # Catalina0{kazzz-s} Versions (4)% ll
+ # total 0
+ # drwxr-xr-x 4 kazzz-s admin 128 12 16 21:40 .
+ # drwxr-xr-x 6 kazzz-s admin 192 12 16 21:40 ..
+ # drwxr-xr-x 9 kazzz-s admin 288 12 12 23:08 3.8
+ # [*] lrwxr-xr-x 1 kazzz-s admin 4 12 16 21:40 Current -> 3.8/
+ #
+ # Catalina0{kazzz-s} Python.framework (5)% pwd
+ # /usr/local/opt/python@3.8/Frameworks/Python.framework
+ # Catalina0{kazzz-s} Python.framework (6)% ll
+ # total 0
+ # drwxr-xr-x 6 kazzz-s admin 192 12 16 21:40 .
+ # drwxr-xr-x 3 kazzz-s admin 96 12 12 23:07 ..
+ # [*] lrwxr-xr-x 1 kazzz-s admin 25 12 16 21:40 Headers -> Versions/Current/Headers/
+ # [*] lrwxr-xr-x 1 kazzz-s admin 23 12 16 21:40 Python -> Versions/Current/Python
+ # [*] lrwxr-xr-x 1 kazzz-s admin 27 12 16 21:40 Resources -> Versions/Current/Resources/
+ # drwxr-xr-x 4 kazzz-s admin 128 12 16 21:40 Versions
#-----------------------------------------------------------------------------------------------
deploymentPython38HB = (ModulePython == 'Python38Brew')
deploymentPythonAutoHB = (ModulePython == 'PythonAutoBrew')
@@ -1550,43 +1599,49 @@ def Deploy_Binaries_For_Bundle(config, parameters):
os.chmod( targetDirM + "/start-console.py", 0o0755 )
os.chmod( targetDirM + "/klayout_console", 0o0755 )
- print(" [9.2] Relinking dylib dependencies inside Python.framework" )
- print(" [9.2.1] Patching Python Framework" )
+ print( " [9.2] Relinking dylib dependencies inside Python.framework" )
+ print( " [9.2.1] Patching Python Framework" )
depdict = WalkFrameworkPaths( pythonFrameworkPath )
appPythonFrameworkPath = '@executable_path/../Frameworks/Python.framework/'
- PerformChanges(depdict, [(HBPythonFrameworkPath, appPythonFrameworkPath, False)], bundleExecPathAbs)
+ PerformChanges( depdict, [(HBPythonFrameworkPath, appPythonFrameworkPath, False)], bundleExecPathAbs )
- print(" [9.2.2] Patching /usr/local/opt/ libs")
- usrLocalPath = '/usr/local/opt/'
+ print( " [9.2.2] Patching 'Python' itself in Python Framework" )
+ filterreg = r'\t+%s/(opt|Cellar)' % DefaultHomebrewRoot
+ Patch_Python_In_PythonFramework( pythonFrameworkPath, filter_regex=filterreg )
+
+ print( " [9.2.3] Patching %s/opt/ libs" % DefaultHomebrewRoot ) # eg. DefaultHomebrewRoot == "/usr/local"
+ usrLocalPath = '%s/opt/' % DefaultHomebrewRoot
appUsrLocalPath = '@executable_path/../Frameworks/'
- replacePairs = [(usrLocalPath, appUsrLocalPath, True)]
- depdict = WalkFrameworkPaths(pythonFrameworkPath, search_path_filter=r'\t+/usr/local/(opt|Cellar)')
- PerformChanges(depdict, replacePairs, bundleExecPathAbs)
+ replacePairs = [ (usrLocalPath, appUsrLocalPath, True) ]
+ filterreg = r'\t+%s/(opt|Cellar)' % DefaultHomebrewRoot
+ depdict = WalkFrameworkPaths( pythonFrameworkPath, search_path_filter=filterreg )
+ PerformChanges( depdict, replacePairs, bundleExecPathAbs )
- print(" [9.2.3] Patching openssl@1.1, gdbm, readline, sqlite, xz")
- usrLocalPath = '/usr/local/opt'
+ print( " [9.2.4] Patching openssl@1.1, gdbm, readline, sqlite, xz" )
+ usrLocalPath = '%s/opt/' % DefaultHomebrewRoot
appUsrLocalPath = '@executable_path/../Frameworks/'
- replacePairs = [(usrLocalPath, appUsrLocalPath, True)]
- replacePairs.extend([(openssl_version, '@executable_path/../Frameworks/openssl@1.1', True)
- for openssl_version in glob.glob('/usr/local/Cellar/openssl@1.1/*')])
- depdict = WalkFrameworkPaths([pythonFrameworkPath + '/../openssl@1.1',
- pythonFrameworkPath + '/../gdbm',
- pythonFrameworkPath + '/../readline',
- pythonFrameworkPath + '/../sqlite',
- pythonFrameworkPath + '/../xz'], search_path_filter=r'\t+/usr/local/(opt|Cellar)')
+ replacePairs = [ (usrLocalPath, appUsrLocalPath, True) ]
+ replacePairs.extend( [ (openssl_version, '@executable_path/../Frameworks/openssl@1.1', True)
+ for openssl_version in glob.glob( '%s/Cellar/openssl@1.1/*' % DefaultHomebrewRoot ) ] )
+ filterreg = r'\t+%s/(opt|Cellar)' % DefaultHomebrewRoot
+ depdict = WalkFrameworkPaths( [pythonFrameworkPath + '/../openssl@1.1',
+ pythonFrameworkPath + '/../gdbm',
+ pythonFrameworkPath + '/../readline',
+ pythonFrameworkPath + '/../sqlite',
+ pythonFrameworkPath + '/../xz'], search_path_filter=filterreg )
- PerformChanges(depdict, replacePairs, bundleExecPathAbs)
+ PerformChanges( depdict, replacePairs, bundleExecPathAbs )
- print(" [9.3] Relinking dylib dependencies for klayout")
+ print( " [9.3] Relinking dylib dependencies for klayout" )
klayoutPath = bundleExecPathAbs
- depdict = WalkFrameworkPaths(klayoutPath, filter_regex=r'klayout$')
- PerformChanges(depdict, [(HBPythonFrameworkPath, appPythonFrameworkPath, False)], bundleExecPathAbs)
+ depdict = WalkFrameworkPaths( klayoutPath, filter_regex=r'klayout$' )
+ PerformChanges( depdict, [(HBPythonFrameworkPath, appPythonFrameworkPath, False)], bundleExecPathAbs )
libKlayoutPath = bundleExecPathAbs + '../Frameworks'
- depdict = WalkFrameworkPaths(libKlayoutPath, filter_regex=r'libklayout')
- PerformChanges(depdict, [(HBPythonFrameworkPath, appPythonFrameworkPath, False)], bundleExecPathAbs)
+ depdict = WalkFrameworkPaths( libKlayoutPath, filter_regex=r'libklayout' )
+ PerformChanges( depdict, [(HBPythonFrameworkPath, appPythonFrameworkPath, False)], bundleExecPathAbs )
- print(" [9.4] Patching site.py, pip/, and distutils/")
+ print( " [9.4] Patching site.py, pip/, and distutils/" )
site_module = "%s/Versions/%s/lib/python%s/site.py" % (pythonFrameworkPath, pythonHBVer, pythonHBVer)
with open(site_module, 'r') as site:
buf = site.readlines()
diff --git a/macbuild/build4mac_env.py b/macbuild/build4mac_env.py
index 35f40a072..06cd5e733 100755
--- a/macbuild/build4mac_env.py
+++ b/macbuild/build4mac_env.py
@@ -178,7 +178,7 @@ RubyMonterey = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions/
# install with 'sudo port install ruby31'
# [Key Type Name] = 'MP31'
Ruby31MacPorts = { 'exe': '/opt/local/bin/ruby3.1',
- 'inc': '/opt/local/include/ruby-3.1.2',
+ 'inc': '/opt/local/include/ruby-3.1.3',
'lib': '/opt/local/lib/libruby.3.1.dylib'
}
diff --git a/macbuild/build4mac_util.py b/macbuild/build4mac_util.py
index 42f016f0d..022805ffb 100755
--- a/macbuild/build4mac_util.py
+++ b/macbuild/build4mac_util.py
@@ -61,8 +61,8 @@ def DecomposeLibraryDependency( depstr ):
#----------------------------------------------------------------------------------------
def PrintLibraryDependencyDictionary( depdic, pathdic, namedic ):
keys = depdic.keys()
- print("")
- print("##### Contents of <%s> #####:" % namedic )
+ print( "" )
+ print( "##### Contents of <%s> #####:" % namedic )
for key in keys:
supporters = depdic[key]
keyName = os.path.basename(key)
@@ -158,8 +158,9 @@ def SetChangeLibIdentificationName( executable, relativedir ):
for lib in deplibs:
#-----------------------------------------------------------
# [1] Set the identification names for the library
+ # $ install_name_tool [-id name] input
#-----------------------------------------------------------
- nameOld = "klayout.app/Contents/Frameworks/%s" % lib
+ nameOld = "klayout.app/Contents/Frameworks/%s" % lib # input file
nameNew = "@executable_path/%s/%s" % ( relativedir, lib )
command = "%s %s %s" % ( cmdNameId, nameNew, nameOld )
if subprocess.call( command, shell=True ) != 0:
@@ -169,6 +170,7 @@ def SetChangeLibIdentificationName( executable, relativedir ):
#-----------------------------------------------------------
# [2] Make the application aware of the new identification
+ # $ install_name_tool [-change old new] input
#-----------------------------------------------------------
nameOld = "%s" % lib
nameNew = "@executable_path/%s/%s" % ( relativedir, lib )
@@ -182,6 +184,8 @@ def SetChangeLibIdentificationName( executable, relativedir ):
#----------------------------------------------------------------------------------------
## To make a library dependency dictionary by recursively walk down the lib hierarchy
+# DefaultHomebrewRoot = '/opt/homebrew' "arm64" Apple Silicon
+# DefaultHomebrewRoot = '/usr/local' "x86_64" Intel Mac
#
# @param[in] dylibPath: dylib path
# @param[in] depth: hierarchy depth (< 5)
@@ -189,7 +193,7 @@ def SetChangeLibIdentificationName( executable, relativedir ):
#
# @return a dictionary
#----------------------------------------------------------------------------------------
-def WalkLibDependencyTree( dylibPath, depth=0, filter_regex=r'\t+/usr/local/opt' ):
+def WalkLibDependencyTree( dylibPath, depth=0, filter_regex=r'\t+%s/opt' % DefaultHomebrewRoot ):
otoolCm = 'otool -L %s | grep -E "%s"' % (dylibPath, filter_regex)
otoolOut = os.popen( otoolCm ).read()
exedepdic = DecomposeLibraryDependency( dylibPath + ":\n" + otoolOut )
@@ -201,7 +205,7 @@ def WalkLibDependencyTree( dylibPath, depth=0, filter_regex=r'\t+/usr/local/opt'
for idx, lib in enumerate(deplibs):
lib = str(lib)
if lib != list(keys)[0]:
- deplibs[idx] = WalkLibDependencyTree(lib, depth+1, filter_regex)
+ deplibs[idx] = WalkLibDependencyTree( lib, depth+1, filter_regex )
if depth == 0:
return deplibs
return exedepdic
@@ -210,6 +214,8 @@ def WalkLibDependencyTree( dylibPath, depth=0, filter_regex=r'\t+/usr/local/opt'
#----------------------------------------------------------------------------------------
## To make a library dependency dictionary by recursively walk down the Framework
+# DefaultHomebrewRoot = '/opt/homebrew' "arm64" Apple Silicon
+# DefaultHomebrewRoot = '/usr/local' "x86_64" Intel Mac
#
# @param[in] frameworkPaths: Framework path
# @param[in] filter_regex: filter regular expression
@@ -218,9 +224,8 @@ def WalkLibDependencyTree( dylibPath, depth=0, filter_regex=r'\t+/usr/local/opt'
# @return a dictionary
#----------------------------------------------------------------------------------------
def WalkFrameworkPaths( frameworkPaths, filter_regex=r'\.(so|dylib)$',
- search_path_filter=r'\t+/usr/local/opt' ):
-
- if isinstance(frameworkPaths, str):
+ search_path_filter=r'\t+%s/opt' % DefaultHomebrewRoot ):
+ if isinstance( frameworkPaths, str ):
frameworkPathsIter = [frameworkPaths]
else:
frameworkPathsIter = frameworkPaths
@@ -229,14 +234,12 @@ def WalkFrameworkPaths( frameworkPaths, filter_regex=r'\.(so|dylib)$',
for frameworkPath in frameworkPathsIter:
# print("Calling:", 'find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex))
- find_grep_results = os.popen('find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex)).read().split('\n')
- framework_files = filter(lambda x: x != '',
- map(lambda x: x.strip(),
- find_grep_results))
+ find_grep_results = os.popen( 'find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex) ).read().split('\n')
+ framework_files = filter( lambda x: x != '', map(lambda x: x.strip(), find_grep_results) )
dependency_dict[frameworkPath] = list()
for idx, file in enumerate(framework_files):
- dict_file = {file: WalkLibDependencyTree(file, filter_regex=search_path_filter)}
+ dict_file = { file: WalkLibDependencyTree( file, filter_regex=search_path_filter ) }
dependency_dict[frameworkPath].append(dict_file)
return dependency_dict
@@ -262,17 +265,17 @@ def WalkDictTree( dependencyDict, visited_files ):
if deplib not in visited_files:
visited_files.append(deplib)
elif isinstance(deplib, dict):
- dependency_list.append(next(iter(deplib)))
- libNameChanges.extend(WalkDictTree(deplib, visited_files))
+ dependency_list.append( next(iter(deplib)) )
+ libNameChanges.extend( WalkDictTree(deplib, visited_files) )
else:
#raise RuntimeError("Unexpected value: %s" % deplib)
pass
else:
- raise RuntimeError("Unexpected value: %s" % dependencies)
+ raise RuntimeError( "Unexpected value: %s" % dependencies )
if len(dependency_list) > 0:
- libNameChanges.append((lib, dependency_list))
+ libNameChanges.append( (lib, dependency_list) )
else:
- libNameChanges.append((lib, ))
+ libNameChanges.append( (lib, ) )
visited_files.append(lib)
return libNameChanges
@@ -300,7 +303,7 @@ def FindFramework( path, root_path ):
#----------------------------------------------------------------------------------------
def ResolveExecutablePath( path, executable_path ):
""" Transforms @executable_path into executable_path"""
- p = path.replace("@executable_path", "/%s/" % executable_path)
+ p = path.replace( "@executable_path", "/%s/" % executable_path )
return p
#----------------------------------------------------------------------------------------
@@ -314,11 +317,11 @@ def ResolveExecutablePath( path, executable_path ):
# * ('lib.dylib',)
#----------------------------------------------------------------------------------------
def DetectChanges(frameworkDependencyDict):
- visited_files = list()
+ visited_files = list()
libNameChanges = list()
for framework, libraries in frameworkDependencyDict.items():
for libraryDict in libraries:
- libNameChanges.extend(WalkDictTree(libraryDict, visited_files))
+ libNameChanges.extend( WalkDictTree(libraryDict, visited_files) )
return libNameChanges
#----------------------------------------------------------------------------------------
@@ -456,11 +459,96 @@ def GenerateInfoPlist( keydic, templfile ):
t = string.Template(template)
s = t.substitute( EXECUTABLE = val_exe,
- ICONFILE = val_icon,
- BUNDLENAME = val_bname,
- VERSION = val_ver)
+ ICONFILE = val_icon,
+ BUNDLENAME = val_bname,
+ VERSION = val_ver )
return s
+#----------------------------------------------------------------------------------------
+## To patch 'Python' itself in Python Framework
+#
+# A relatively new Python 3.x may depend on other dylib(s) under /usr/local/opt/.
+# This was first found in:
+# Catalina0{kazzz-s} klayout (1)% python3
+# Python 3.8.16 (default, Dec 12 2022, 14:07:09)
+# [Clang 12.0.0 (clang-1200.0.32.29)] on darwin
+# Type "help", "copyright", "credits" or "license" for more information.
+# >>>
+#
+# Catalina0{kazzz-s} Current (2)% pwd
+# /usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/Current
+#
+# Catalina0{kazzz-s} Current (3)% ll
+# total 5024
+# drwxr-xr-x 7 kazzz-s admin 224 Dec 16 23:02 .
+# drwxr-xr-x 4 kazzz-s admin 128 Dec 16 21:40 ..
+# lrwxr-xr-x 1 kazzz-s admin 17 Dec 17 08:46 Headers -> include/python3.8
+# -rwxr-xr-x 1 kazzz-s admin 2571960 Dec 12 23:08 Python
+# drwxr-xr-x 3 kazzz-s admin 96 Dec 12 23:08 include
+# drwxr-xr-x 5 kazzz-s admin 160 Dec 12 23:08 lib
+# drwxr-xr-x 3 kazzz-s admin 96 Dec 12 23:08 share
+#
+# Catalina0{kazzz-s} Current (4)% otool -L Python
+# Python:
+# /usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/Python (compatibility version 3.8.0, current version 3.8.0)
+# /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1675.129.0)
+# [*] /usr/local/opt/gettext/lib/libintl.8.dylib (compatibility version 12.0.0, current version 12.0.0)
+# /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1)
+#
+# This library dependency [*] has to be changed as shown below:
+# Catalina0{kazzz-s} Current (5)% install_name_tool -change \
+# /usr/local/opt/gettext/lib/libintl.8.dylib \
+# @executable_path/../Frameworks/libintl.8.dylib \
+# Python
+#
+# Catalina0{kazzz-s} Current (6)% otool -L Python
+# Python:
+# /usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/Python (compatibility version 3.8.0, current version 3.8.0)
+# /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1675.129.0)
+# [*] @executable_path/../Frameworks/libintl.8.dylib (compatibility version 12.0.0, current version 12.0.0)
+# /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1)
+#
+#
+# @param[in] pythonFrameworkPath: Python Framework path
+# @param[in] filter_regex: filter regular expression
+#
+# @return 0 on succcess; non-zero on failure
+#----------------------------------------------------------------------------------------
+def Patch_Python_In_PythonFramework( pythonFrameworkPath, filter_regex=r'\t+%s/opt' % DefaultHomebrewRoot ):
+ #----------------------------------------------------------------------
+ # [1] Get Python's dependency
+ #----------------------------------------------------------------------
+ target = "%s/Python" % pythonFrameworkPath
+ otoolCm = 'otool -L %s | grep -E "%s"' % (target, filter_regex)
+ otoolOut = os.popen( otoolCm ).read()
+ exedepdic = DecomposeLibraryDependency( target + ":\n" + otoolOut )
+ keys = exedepdic.keys()
+ deplibs = exedepdic[ list(keys)[0] ]
+ # print(deplibs)
+ # [ '/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/Python',
+ # '/usr/local/opt/gettext/lib/libintl.8.dylib'
+ # ]
+
+ #----------------------------------------------------------------------
+ # [2] Change the library name
+ #----------------------------------------------------------------------
+ cmdNameChg = XcodeToolChain['nameCH']
+
+ for lib in deplibs:
+ basename = os.path.basename(lib)
+ if basename == "Python": # self
+ continue
+ else:
+ nameOld = "%s" % lib
+ nameNew = "@executable_path/../Frameworks/%s" % basename
+ command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, target )
+ if subprocess.call( command, shell=True ) != 0:
+ msg = "!!! Failed to make 'Python' aware of the new identification name <%s> of supporter <%s> !!!"
+ print( msg % (nameNew, lib), file=sys.stderr )
+ return 1
+ # for-lib
+ return 0
+
#----------------
# End of File
#----------------
diff --git a/macbuild/makeDMG4mac.py b/macbuild/makeDMG4mac.py
index 135ec007e..984b99146 100755
--- a/macbuild/makeDMG4mac.py
+++ b/macbuild/makeDMG4mac.py
@@ -59,10 +59,11 @@ def SetGlobals():
global VolumeDMG # the volume name of DMG
global TargetDMG # the name of target DMG file
global RootApplications # reserved directory name for applications
- global LatestOSMacPorts # True if 'LatestOS with MacPorts'
- global LatestOSHomebrew # True if 'LatestOS with Homebrew'
- global LatestOSAnaconda3 # True if 'LatestOS with Anaconda3'
- global DicLightWeight # dictionary for LW-* packages
+ global LatestOSMacPorts # True if 'LatestOS with MacPorts' and targeting LW-*
+ global LatestOSHomebrew # True if 'LatestOS with Homebrew' and targeting LW-*
+ global LatestOSAnaconda3 # True if 'LatestOS with Anaconda3' and targeting LW-*
+ global LatestOSHomebrewH # True if 'LatestOS with Homebrew' and targeting HW-*
+ global DicLightHeavyW # dictionary for LW-* and HW-* packages
global Item3AppleScript # ITEM_3 in the Apple script
# auxiliary variables on platform
global System # 6-tuple from platform.uname()
@@ -76,13 +77,13 @@ def SetGlobals():
Usage = "\n"
Usage += "---------------------------------------------------------------------------------------------------------\n"
Usage += "<< Usage of 'makeDMG4mac.py' >>\n"
- Usage += " for making a DMG file of KLayout 0.27.11 or later on different Apple macOS / Mac OSX platforms.\n"
+ Usage += " for making a DMG file of KLayout 0.28 or later on different Apple macOS / Mac OSX platforms.\n"
Usage += "\n"
Usage += "$ [python] ./makeDMG4mac.py\n"
Usage += " option & argument : descriptions | default value\n"
Usage += " ----------------------------------------------------------------------------------+-----------------\n"
Usage += " <-p|--pkg > : package directory created by `build4mac.py` with [-y|-Y] | ``\n"
- Usage += " : like 'ST-qt5MP.pkg.macos-Catalina-release-RsysPsys' | \n"
+ Usage += " : like 'LW-qt5MP.pkg.macos-Catalina-release-Rmp31Pmp38' | \n"
Usage += " <-c|--clean> : clean the work directory | disabled\n"
Usage += " <-m|--make> : make a compressed DMG file | disabled\n"
Usage += " : <-c|--clean> and <-m|--make> are mutually exclusive | \n"
@@ -168,43 +169,52 @@ def SetGlobals():
LatestOSMacPorts = False
LatestOSHomebrew = False
LatestOSAnaconda3 = False
- DicLightWeight = dict()
+ LatestOSHomebrewH = False
+ DicLightHeavyW = dict()
Item3AppleScript = ""
- # Populate DicLightWeight
- DicLightWeight[ "ports" ] = dict()
- DicLightWeight[ "brew" ] = dict()
- DicLightWeight[ "ana3" ] = dict()
- DicLightWeight[ "ports" ]["zip"] = "macbuild/Resources/script-bundle-P.zip"
- DicLightWeight[ "ports" ]["src"] = "script-bundle-P"
- DicLightWeight[ "ports" ]["des"] = "MacPortsUser-ReadMeFirst"
- DicLightWeight[ "ports" ]["item3"] = 'set position of item "MacPortsUser-ReadMeFirst" to {700, 400}'
+ # Populate DicLightHeavyW
+ DicLightHeavyW[ "ports" ] = dict() # LW-*
+ DicLightHeavyW[ "brew" ] = dict() # LW-*
+ DicLightHeavyW[ "ana3" ] = dict() # LW-*
+ DicLightHeavyW[ "brewH" ] = dict() # HW-*
- DicLightWeight[ "brew" ]["zip"] = "macbuild/Resources/script-bundle-B.zip"
- DicLightWeight[ "brew" ]["src"] = "script-bundle-B"
- DicLightWeight[ "brew" ]["des"] = "HomebrewUser-ReadMeFirst"
- DicLightWeight[ "brew" ]["item3"] = 'set position of item "HomebrewUser-ReadMeFirst" to {700, 400}'
+ DicLightHeavyW[ "ports" ]["zip"] = "macbuild/Resources/script-bundle-P.zip"
+ DicLightHeavyW[ "ports" ]["src"] = "script-bundle-P"
+ DicLightHeavyW[ "ports" ]["des"] = "MacPortsUser-ReadMeFirst"
+ DicLightHeavyW[ "ports" ]["item3"] = 'set position of item "MacPortsUser-ReadMeFirst" to {700, 400}'
- DicLightWeight[ "ana3" ]["zip"] = "macbuild/Resources/script-bundle-A.zip"
- DicLightWeight[ "ana3" ]["src"] = "script-bundle-A"
- DicLightWeight[ "ana3" ]["des"] = "Anaconda3User-ReadMeFirst"
- DicLightWeight[ "ana3" ]["item3"] = 'set position of item "Anaconda3User-ReadMeFirst" to {700, 400}'
+ DicLightHeavyW[ "brew" ]["zip"] = "macbuild/Resources/script-bundle-B.zip"
+ DicLightHeavyW[ "brew" ]["src"] = "script-bundle-B"
+ DicLightHeavyW[ "brew" ]["des"] = "HomebrewUser-ReadMeFirst"
+ DicLightHeavyW[ "brew" ]["item3"] = 'set position of item "HomebrewUser-ReadMeFirst" to {700, 400}'
+
+ DicLightHeavyW[ "ana3" ]["zip"] = "macbuild/Resources/script-bundle-A.zip"
+ DicLightHeavyW[ "ana3" ]["src"] = "script-bundle-A"
+ DicLightHeavyW[ "ana3" ]["des"] = "Anaconda3User-ReadMeFirst"
+ DicLightHeavyW[ "ana3" ]["item3"] = 'set position of item "Anaconda3User-ReadMeFirst" to {700, 400}'
+
+ DicLightHeavyW[ "brewH" ]["zip"] = "macbuild/Resources/script-bundle-H.zip"
+ DicLightHeavyW[ "brewH" ]["src"] = "script-bundle-H"
+ DicLightHeavyW[ "brewH" ]["des"] = "Homebrew-HUser-ReadMeFirst"
+ DicLightHeavyW[ "brewH" ]["item3"] = 'set position of item "Homebrew-HUser-ReadMeFirst" to {700, 400}'
#------------------------------------------------------------------------------
## To check the contents of the package directory
#
# The package directory name should look like:
-# * ST-qt5MP.pkg.macos-Catalina-release-RsysPsys --- (1)
# * LW-qt5Ana3.pkg.macos-Catalina-release-Rana3Pana3
-# * LW-qt5Brew.pkg.macos-Catalina-release-Rhb31Phb38
+# * LW-qt5Brew.pkg.macos-Catalina-release-Rhb31Phb38 --- (1)
# * LW-qt5MP.pkg.macos-Catalina-release-Rmp31Pmp38
+# * HW-qt5Brew.pkg.macos-Catalina-release-RsysPhb38
#
-# * ST-qt6MP.pkg.macos-Catalina-release-RsysPsys
+# * LW-qt6Ana3.pkg.macos-Catalina-release-Rana3Pana3
# * LW-qt6Brew.pkg.macos-Catalina-release-Rhb31Phb38
# * LW-qt6MP.pkg.macos-Catalina-release-Rmp31Pmp38
+# * HW-qt6Brew.pkg.macos-Catalina-release-RsysPhb38
#
# Generated DMG will be, for example,
-# (1) ---> ST-klayout-0.27.11-macOS-Catalina-1-qt5MP-RsysPsys.dmg
+# (1) ---> LW-klayout-0.28.2-macOS-Catalina-1-qt5Brew-Rhb31Phb38.dmg
#
# @return on success, positive integer in [MB] that tells approx. occupied disc space;
# on failure, -1
@@ -224,7 +234,8 @@ def CheckPkgDirectory():
global LatestOSMacPorts
global LatestOSHomebrew
global LatestOSAnaconda3
- global DicLightWeight
+ global LatestOSHomebrewH
+ global DicLightHeavyW
global Item3AppleScript
#-----------------------------------------------------------------------------
@@ -242,17 +253,18 @@ def CheckPkgDirectory():
#-----------------------------------------------------------------------------
# [2] Identify (Qt, Ruby, Python) from PkgDir
- # * ST-qt5MP.pkg.macos-Catalina-release-RsysPsys
# * LW-qt5Ana3.pkg.macos-Catalina-release-Rana3Pana3
# * LW-qt5Brew.pkg.macos-Catalina-release-Rhb31Phb38
+ # * LW-qt5MP.pkg.macos-Catalina-release-Rmp31Pmp38
# * HW-qt5Brew.pkg.macos-Catalina-release-RsysPhb38
- # * EX-qt5MP.pkg.macos-Catalina-release-Rmp31Pmp38
+ # * EX-qt5MP.pkg.macos-Catalina-release-Rhb31Pmp38
#
- # * ST-qt6MP.pkg.macos-Catalina-release-RsysPsys
- # * LW-qt6MP.pkg.macos-Catalina-release-Rmp31Pmp38
+ # * LW-qt6Ana3.pkg.macos-Catalina-release-Rana3Pana3
# * LW-qt6Brew.pkg.macos-Catalina-release-Rhb31Phb38
+ # * LW-qt6MP.pkg.macos-Catalina-release-Rmp31Pmp38
+ # * HW-qt6Brew.pkg.macos-Catalina-release-RsysPhb38
#-----------------------------------------------------------------------------
- patQRP = u'(ST|LW|HW|EX)([-])([qt5|qt6][0-9A-Za-z]+)([.]pkg[.])([A-Za-z]+[-][A-Za-z]+[-]release[-])([0-9A-Za-z]+)'
+ patQRP = u'(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)
if not regQRP.match(PkgDir):
print( "! Cannot identify (Qt, Ruby, Python) from the package directory name" )
@@ -292,8 +304,13 @@ def CheckPkgDirectory():
LatestOSAnaconda3 &= QtIdentification in ["qt5Ana3"]
LatestOSAnaconda3 &= RubyPythonID in ["Rana3Pana3"]
+ LatestOSHomebrewH = Platform == LatestOS
+ LatestOSHomebrewH &= PackagePrefix == "HW"
+ LatestOSHomebrewH &= QtIdentification in ["qt5Brew", "qt6Brew"]
+ LatestOSHomebrewH &= RubyPythonID in ["RsysPhb38", "RsysPhb39", "RsysPhbauto"] # Sys-Homebre hybrid
+
if LatestOSMacPorts:
- mydic = DicLightWeight["ports"]
+ mydic = DicLightHeavyW["ports"]
srcDir = PkgDir + "/" + mydic["src"]
desDir = PkgDir + "/" + mydic["des"]
if OpMake:
@@ -308,7 +325,7 @@ def CheckPkgDirectory():
Item3AppleScript = mydic["item3"]
if LatestOSHomebrew:
- mydic = DicLightWeight["brew"]
+ mydic = DicLightHeavyW["brew"]
srcDir = PkgDir + "/" + mydic["src"]
desDir = PkgDir + "/" + mydic["des"]
if OpMake:
@@ -323,7 +340,22 @@ def CheckPkgDirectory():
Item3AppleScript = mydic["item3"]
if LatestOSAnaconda3:
- mydic = DicLightWeight["ana3"]
+ mydic = DicLightHeavyW["ana3"]
+ srcDir = PkgDir + "/" + mydic["src"]
+ desDir = PkgDir + "/" + mydic["des"]
+ if OpMake:
+ with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
+ zip_ref.extractall(PkgDir)
+ os.rename( srcDir, desDir )
+ if OpClean:
+ if os.path.isdir(srcDir):
+ shutil.rmtree(srcDir)
+ if os.path.isdir(desDir):
+ shutil.rmtree(desDir)
+ Item3AppleScript = mydic["item3"]
+
+ if LatestOSHomebrewH:
+ mydic = DicLightHeavyW["brewH"]
srcDir = PkgDir + "/" + mydic["src"]
desDir = PkgDir + "/" + mydic["des"]
if OpMake:
@@ -525,7 +557,7 @@ def MakeTargetDMGFile(msg=""):
# Figures below were determined by experiments for best fit
applescript = t.safe_substitute(
ORGX='50', ORGY='100',
- WIN_WIDTH='1000', WIN_HEIGHT='500',
+ WIN_WIDTH='1000', WIN_HEIGHT='540',
FULL_PATH_DS_STORE='/Volumes/%s/.DS_Store' % VolumeDMG,
BACKGROUND_PNG_FILE=BackgroundPNG,
ITEM_1='%s' % BundleName, X1='900', Y1='165',
diff --git a/macbuild/nightlyBuild.py b/macbuild/nightlyBuild.py
index 7fa596637..326704096 100755
--- a/macbuild/nightlyBuild.py
+++ b/macbuild/nightlyBuild.py
@@ -52,7 +52,7 @@ def Test_My_Platform( platforms=['Catalina', 'BigSur', 'Monterey' ] ):
#------------------------------------------------------------------------------
def Get_Build_Target_Dict():
buildTargetDic = dict()
- buildTargetDic[0] = 'std'
+ # buildTargetDic[0] = 'std' # has been abolished in 0.28
buildTargetDic[1] = 'ports'
buildTargetDic[2] = 'brew'
buildTargetDic[3] = 'brewHW'
@@ -200,7 +200,7 @@ def Parse_CommandLine_Arguments():
if platform in [ "Monterey", "BigSur" ]:
targetopt = "1,2,3,4"
elif platform in ["Catalina"]:
- targetopt = "0,1,2,3,4"
+ targetopt = "1,2,3,4"
else:
targetopt = ""
@@ -213,7 +213,7 @@ def Parse_CommandLine_Arguments():
Usage += " option & argument : comment on option if any | default value\n"
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 += " [--target ] : 1='ports', 2='brew', 3='brewHW', 4='ana3', | '%s'\n" % targetopt
Usage += " 5='brewA', 6='brewAHW' | \n"
Usage += " * with --qt=6, use --target='2,3' (4 is ignored) | \n"
Usage += " [--build] : build and deploy | disabled\n"
@@ -233,7 +233,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.27.11' | \n"
+ Usage += " (6) $ ./nightlyBuild.py --upload '0.28.2' | \n"
Usage += " (7) $ ./nightlyBuild.py --cleandmg 1 | \n"
Usage += "---------------------------------------------------------------------------+----------------------\n"
@@ -319,7 +319,7 @@ def Parse_CommandLine_Arguments():
targetDic = Get_Build_Target_Dict()
Target = list()
for idx in sorted( list( set( [ int(item) for item in opt.targets.split(",") ] ) ) ):
- if idx in range(0, 7):
+ if idx in range(1, 7): # '0' has been abolished in 0.28
Target.append( targetDic[idx] )
Build = opt.build
diff --git a/macbuild/python3HB.py b/macbuild/python3HB.py
new file mode 100755
index 000000000..882328ec4
--- /dev/null
+++ b/macbuild/python3HB.py
@@ -0,0 +1,174 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+#==============================================================================
+# File: macbuild/python3HB.py
+#
+# Descriptions: A handy tool to setup the standardized directory structures
+# for Homebrew's Python 3.x
+#==============================================================================
+import os
+import sys
+import platform
+import optparse
+
+#------------------------------------------------------------------------------
+# Set global variables
+#------------------------------------------------------------------------------
+def SetGlobals():
+ global DefaultHomebrewRoot
+ global Usage
+
+ (System, Node, Release, MacVersion, Machine, Processor) = platform.uname()
+ if Machine == "arm64": # Apple Silicon!
+ DefaultHomebrewRoot = '/opt/homebrew'
+ else:
+ DefaultHomebrewRoot = '/usr/local'
+ del System, Node, Release, MacVersion, Machine, Processor
+
+ 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 += " <-v|--version >: in ['3.8', '3.9', '3.10', '3.11'] | ''\n"
+ Usage += " [-u|-unlink] : unlink only | disabled\n"
+ Usage += " [-?|--?] : print this usage and exit | disabled\n"
+ Usage += "--------------------------------------------------------------+----------------------\n"
+
+#------------------------------------------------------------------------------
+# Parse the command line arguments
+#------------------------------------------------------------------------------
+def Parse_CLI_Args():
+ global Version
+ global UnlinkOnly
+
+ p = optparse.OptionParser( usage=Usage )
+
+ p.add_option( '-v', '--version',
+ dest='version',
+ help="python3 version=['3.8', '3.9', '3.10', '3.11']" )
+
+ p.add_option( '-u', '--unlink',
+ action='store_true',
+ dest='unlink',
+ default=False,
+ help='unlink only' )
+
+ p.add_option( '-?', '--??',
+ action='store_true',
+ dest='checkusage',
+ default=False,
+ help='check usage' )
+
+ p.set_defaults( version = "",
+ unlink = False,
+ checkusage = False )
+
+ opt, args = p.parse_args()
+ if (opt.checkusage):
+ print(Usage)
+ sys.exit(0)
+
+ Version = opt.version
+ UnlinkOnly = opt.unlink
+ if not Version in [ '3.8', '3.9', '3.10', '3.11' ]:
+ print( "! Unsupported Python 3 version <%s>" % Version )
+ print(Usage)
+ sys.exit(0)
+
+#------------------------------------------------------------------------------
+# Set the directory structures
+#------------------------------------------------------------------------------
+def SetDirectoryStructures():
+ #----------------------------------------------------------
+ # [1] Check the root directory of python@${Version}
+ #----------------------------------------------------------
+ root = "%s/opt/python@%s" % (DefaultHomebrewRoot, Version)
+ if not os.path.isdir(root):
+ print( "! Found no such a directory <%s>" % root )
+ sys.exit(0)
+
+ #----------------------------------------------------------
+ # [2] Go to "lib/" and make
+ # Python.framework -> ../Frameworks/Python.framework/
+ #----------------------------------------------------------
+ os.chdir( root )
+ os.chdir( "lib/" )
+ try:
+ os.remove( "Python.framework" )
+ except FileNotFoundError:
+ pass
+ if not UnlinkOnly:
+ os.symlink( "../Frameworks/Python.framework/", "Python.framework" )
+
+ #----------------------------------------------------------
+ # [3] Go to "bin/" and make
+ # ./python${version} -> python3
+ # ./pip${version} -> pip3
+ #----------------------------------------------------------
+ os.chdir( root )
+ os.chdir( "bin/" )
+ try:
+ os.remove( "python3" )
+ os.remove( "pip3" )
+ except FileNotFoundError:
+ pass
+ if not UnlinkOnly:
+ os.symlink( "./python%s" % Version, "python3" )
+ os.symlink( "./pip%s" % Version, "pip3" )
+
+ #----------------------------------------------------------
+ # [4] Go to "Frameworks/Python.framework/" and delete
+ # three symbolic links
+ #----------------------------------------------------------
+ os.chdir( root )
+ os.chdir( "Frameworks/Python.framework/" )
+ try:
+ os.remove( "Headers" )
+ os.remove( "Resources" )
+ os.remove( "Python" )
+ except FileNotFoundError:
+ pass
+
+ #----------------------------------------------------------
+ # [5] Go to "Versions/" and make
+ # Current -> ${Version}/
+ #----------------------------------------------------------
+ os.chdir( root )
+ os.chdir( "Frameworks/Python.framework/Versions/" )
+ try:
+ os.remove( "Current" )
+ except FileNotFoundError:
+ pass
+ if not UnlinkOnly:
+ os.symlink( "%s/" % Version, "Current" )
+
+ #----------------------------------------------------------
+ # [6] Go to "Frameworks/Python.framework/" and make
+ # three symbolic links
+ #----------------------------------------------------------
+ if not UnlinkOnly:
+ os.chdir( root )
+ os.chdir( "Frameworks/Python.framework/" )
+ os.symlink( "Versions/Current/Headers/", "Headers" )
+ os.symlink( "Versions/Current/Resources/", "Resources" )
+ os.symlink( "Versions/Current/Python", "Python" )
+
+#------------------------------------------------------------------------------
+# The main function
+#------------------------------------------------------------------------------
+def Main():
+ SetGlobals()
+ Parse_CLI_Args()
+ SetDirectoryStructures()
+
+#===================================================================================
+if __name__ == "__main__":
+ Main()
+
+#---------------
+# End of file
+#---------------