Merge pull request #1233 from Kazzz-S/0.28.2-mac1

Revised the build system for macOS to work with KLayout version 0.28 or later
This commit is contained in:
Matthias Köfferlein 2022-12-27 20:12:37 +01:00 committed by GitHub
commit e8cf51df1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 491 additions and 177 deletions

View File

@ -1,12 +1,13 @@
Relevant KLayout version: 0.27.11<br>
Relevant KLayout version: 0.28.2<br>
Author: Kazzz-S<br>
Last modified: 2022-10-10<br>
Last modified: 2022-12-24<br>
# 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. <br>
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.<br>
This configuration is possible only for macOS Catalina (10.15.7).<br>
```
$ /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.<br>
However, the latest Xcode 13.1 does not allow us to link the legacy Python 2.7 library with the newly compiled KLayout binaries.<br>
Moreover, Monterey (12.3.1) finally eliminated the Python 2.7 binaries.<br>
Therefore, Homebrew is adopted as the default environment for Big Sur and Monterey.
This configuration WAS possible only for macOS Catalina (10.15.7).<br>
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.<br>
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 <type>] : case-insensitive type=['nil', 'Sys', 'MP31', 'HB31', 'Ana3'] | sys
[-r|--ruby <type>] : 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 <type>] : case-insensitive type=['nil', 'Sys', 'MP38', 'HB38', 'Ana3', | sys
[-p|--python <type>] : 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>] : 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 <type>] : case-insensitive type=['nil', 'Sys', 'MP38', 'HB38', 'Ana3', | hb38
[-p|--python <type>] : 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>] : 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.<br>
In this section, the actual file and directory names are those obtained on macOS Catalina.<br>
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.<br>
The buddy command-line tools (strm*) will also be deployed in this step.
```
$ ./build4mac.py -y
```
The application bundle **`klayout.app`** is located under:<br>
**`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.<br>
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.<br>
3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.<br>
The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step.<br>
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:<br>
**`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.<br>
3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.<br>
The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step.<br>
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:<br>
**`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.<br>
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.<br>
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:<br>
**`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. <br>
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.<br>
3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.<br>
The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step.<br>
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:<br>
**`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.<br>
### 6E. Other combinations
Logically, several module combinations other than 6A through 6D are possible, including `nil` choice.<br>
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:<br>
* **`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.<br>
@ -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! <br>
With the object-oriented script language (both Ruby and Python) support, our error-prone layout jobs can be greatly simplified and sped up.<br>
With the object-oriented script language (both Ruby and Python) support, our error-prone layout jobs can be significantly simplified and sped up.<br>
Building KLayout from its source code is not difficult. Try it with your favorite environment!
[End of File]

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

View File

@ -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 <type>] : case-insensitive type=['nil', 'Sys', 'MP38', 'HB38', 'Ana3', | %s \n" % myPython
usage += " [-p|--python <type>] : 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>] : 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 <png.h>
# 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 <pymod>
@ -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()

View File

@ -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'
}

View File

@ -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
#----------------

View File

@ -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 <dir>> : 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',

View File

@ -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 <type>] : 5='qt5', 6='qt6' (migration to Qt6 is ongoing) | 5\n"
Usage += " [--target <list>] : 0='std', 1='ports', 2='brew', 3='brewHW', 4='ana3', | '%s'\n" % targetopt
Usage += " [--target <list>] : 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

174
macbuild/python3HB.py Executable file
View File

@ -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 <number>>: 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
#---------------