Building KiCad 7 for Mac OS X 10.15

2023-08-30

If you are both a KiCad user and a Mac user, you probably know that the KiCad 7 released a while back finally have native support for ARM Macs. This unfortuately also means the minimum supported OS version is now macOS 11. If you are like me who are still using old Macs running Mac OS X 10.15 as daily driver, the latest officially released KiCad is now stuck at 6.x.

But it turns out it's actually fairly straight-forward to manually compile KiCad 7 for older Mac OS X. I tried on 10.15 but maybe 10.13 could work as well.

In general you should just follow the official compiling guide, I am just going to add some my own notes as it does not quite work for 10.15 out of the box. Mostly because of the MacPorts vs Homebrew differences. Homebrew has dropped Mac OS X 10.15 support, so MacPorts is probably the best choice for 10.15 as of now, but KiCad is designed to work with Homebrew.

For the dependencies, the same package list for Homebrew could be used for MacPorts:

sudo port install glew bison opencascade glm boost harfbuzz cairo doxygen gettext wget libtool autoconf automake cmake swig openssl unixodbc ninja

In addition to these python-swig should be installed manually as well:

sudo port install swig-python

The dependency build script needs to be patched for MacPorts as by default it would try to detect Homebrew:

diff --git a/build.py b/build.py
index d2c77be..a74a101 100755
--- a/build.py
+++ b/build.py
@@ -403,17 +403,19 @@ def main():
     parsed_args = parse_args(sys.argv[1:])
     print_summary(parsed_args)

-    which_brew = subprocess.check_output("which brew", shell=True).decode('utf-8').strip()
-    brew_prefix = subprocess.check_output("brew --prefix", shell=True).decode('utf-8').strip()
+    #which_brew = subprocess.check_output("which brew", shell=True).decode('utf-8').strip()
+    #brew_prefix = subprocess.check_output("brew --prefix", shell=True).decode('utf-8').strip()

     print(f"The detected host architecture is {get_host_architecture()}")
     print(f"The output of 'arch' is '{get_env_architecture()}'")

-    print(f"The first brew on the path is: {which_brew}")
-    print(f"Its prefix is: {brew_prefix}")
+    #print(f"The first brew on the path is: {which_brew}")
+    #print(f"Its prefix is: {brew_prefix}")

-    brew_macos_arch = get_brew_macos_arch()
-    brew_rosetta = get_brew_rosetta()
+    #brew_macos_arch = get_brew_macos_arch()
+    #brew_rosetta = get_brew_rosetta()
+    brew_macos_arch = "x86_64"
+    brew_rosetta = False
     if parsed_args.arch == "x86_64":
         # on x86_64, we expect brew rosetta to be none (if on x86) or true (if on arm64)
         # and brew macos to contain x86_64
@@ -446,8 +448,11 @@ def main():
             sys.exit(1)


-    gettext_path = "{}/bin".format(subprocess.check_output("brew --prefix gettext", shell=True).decode('utf-8').strip())
-    bison_path = "{}/bin".format(subprocess.check_output("brew --prefix bison", shell=True).decode('utf-8').strip())
+    #gettext_path = "{}/bin".format(subprocess.check_output("brew --prefix gettext", shell=True).decode('utf-8').strip())
+    #bison_path = "{}/bin".format(subprocess.check_output("brew --prefix bison", shell=True).decode('utf-8').strip())
+    gettext_path = "/opt/local/bin"
+    bison_path = "/opt/local/bin"
+
     new_path = ":".join((gettext_path, bison_path, os.environ["PATH"]))
     print(f"Updated PATH is: {new_path}")

(END)

Then the dependency build should work. Once finished go ahead to clone the KiCad repo. Before start building, the FindOCC cmake script needs to be patched to look for MacPorts install path:

diff --git a/cmake/FindOCC.cmake b/cmake/FindOCC.cmake
index af249c9ce2..0a66d989cd 100644
--- a/cmake/FindOCC.cmake
+++ b/cmake/FindOCC.cmake
@@ -116,6 +116,7 @@ else(WIN32)
   FIND_PATH(OCC_INCLUDE_DIR Standard_Version.hxx
     /usr/include/opencascade
     /usr/local/include/opencascade
+    /opt/local/libexec/opencascade/include/opencascade
     /opt/opencascade/include
     /opt/opencascade/inc
   )
@@ -125,6 +126,7 @@ else(WIN32)
     /usr
     /usr/local
     /usr/local/opencascade
+    /opt/local/libexec/opencascade
     /opt/opencascade
     /opt/opencascade/lin64/gcc
     PATH_SUFFIXES lib
(END)

Now the build should just work. You might still want to grab a official release dmg for the bundled symbols and footprints. But this is about it.