Mac Binary Package (Apple M1 and Mac x86_64)
Macos binary packages are built with the
script which, near the end of its operation,
involves code signing, package signing, and notarization.
The build will be universal2 and work on arm64 and x86_64 architectures
(if the pythons used are themselves, universal2).
Preparing your Mac development environment for correct functioning of
the script requires installing a few extra Dependencies beyond the
normal user source build,
obtaining an Apple Developer Program membership,
and requesting two signing certificates from Apple. Those actions are
described in separate sections below.
On an Apple M1 or x86_64,
the script, by default, creates, e.g.,
where the information between nrn and macosx comes from
the number after macos refers to the
the next item(s) before py indicate the architectures on which
the program can run (i.e.
and the numbers after the py indicate the python versions that are
compatible with this package. Those python versions must be installed on
the developer machine.
The script will build a universal pkg only
if all the Python’s are themselves universal.
Presently, one must manually make sure that all the python builds used
the same MACOSX_DEPLOYMENT_TARGET. You can check both of these with
python3 -c 'import sysconfig; print(sysconfig.get_platform())'
A space separated list of python executable arguments can be used in
place of the internal default lists.
$NRN_SRC is the location of the
$HOME/neuron/nrn. The script makes sure
exists and uses that folder to configure and build the software. The
software is installed in
At time of writing, the cmake command in the script that is used to configure the build is
cmake .. -DCMAKE_INSTALL_PREFIX=$NRN_INSTALL \ -DNRN_ENABLE_MPI_DYNAMIC=ON \ -DPYTHON_EXECUTABLE=`which python3` -DNRN_ENABLE_PYTHON_DYNAMIC=ON \ -DNRN_PYTHON_DYNAMIC="$pythons" \ -DIV_ENABLE_X11_DYNAMIC=ON \ -DNRN_ENABLE_CORENEURON=OFF \ -DNRN_RX3D_OPT_LEVEL=2 \ $archs_cmake \ -DCMAKE_PREFIX_PATH=/usr/X11 \ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
The default variables above will be
A universal build is possible with
but the installations of python on your machine must also be universal.
The MPI library does not have to be universal if configuring with
-DNRN_ENABLE_MPI_DYNAMIC=ON as the library is not linked against
during the build.
make -j install is used to build and install in
make macpkg ( see
src/mac/CMakeLists.txt ) is used to:
activate the apps
codesign all the binaries
- Codesigning all binaries in the package is a prerequisite for
notarization and not necessary if the package is not notarized. In
that case it is a bit more trouble for users to install as they must
ignore the scary message that pops up before the installer
and know to right click on that message, then
Open. Then accept the option to
- To prevent Notarization failure the binaries need hardened runtime enabled
and then some of the binaries need some special entitlements enabled.
These entitlements are specified in
src/mac/nrn_entitlements.plistand allow use of the Apple Events, Just in time compilation, and disable library validation. The user will be asked to accept the first time these entitlements are invoked.
- Codesigning all binaries in the package is a prerequisite for notarization and not necessary if the package is not notarized. In that case it is a bit more trouble for users to install as they must ignore the scary message that pops up before the installer and know to right click on that message, then click
create NEURON.pkg .
request Apple to notarize NEURON.pkg
If notarizaton fails, it is occasionally due to Apple changing the contracts and demanding that “You must first sign the relevant contracts online. (1048)”. In that case, go to appstoreconnect.apple.com to accept the legal docs. For other notarization failures, one must consult the LogFileURL which can be obtained with
% xcrun altool --notarization-info $RequestIdentifier \ --username "email@example.com" \ --password "`cat ~/.ssh/notarization-password`" No errors getting notarization info. Date: 2022-01-02 23:38:12 +0000 Hash: 7254157952d4f3573c2804879cf6da8d... LogFileURL: https://osxapps-ssl.itunes.apple.com/itunes-assets... RequestUUID: 152f0f0e-af58-4d22-b291-6a441825dd20 Status: invalid Status Code: 2 Status Message: Package Invalid
where RequestIdentifer (the RequestUUID) appears in the email sent back in response to the notarization request.
The script ends by printing:
Until we figure out how to automatically staple the notarization the following two commands must be executed manually. xcrun stapler staple $PACKAGE_FILE_NAME cp $PACKAGE_FILE_NAME $HOME/$PACKAGE_FULL_NAME
where the variables are filled out and can be copy/pasted to your terminal after Apple sends an email declaring that notarization was successful.
The email from Apple usually takes just a few minutes but can be hours.
I’ve been uploading the
$PACKAGE_FULL_NAME as an artifact for a
Release version from https://github.com/neuronsimulatior/nrn by choosing
Releases, choosing the proper Release tag (e.g. Release 8.0a), Edit release,
and clicking in the “Attach binaries …” near the bottom of the page.
This uses Apple M1 as the example but mostly the same for an x86_64 mac.
lipo tells what architecture a binary must be run on. For example,
lipo -archs `which python3` x86_64 arm64
which is generally the case for all Big Sur mac software. On the other
brew install ... executables and libraries are
generally only for the architecture indicated by
uname -m. That is
ok for openmpi but since the various python libraries are linked against
during build to create the version specific neuron modules, those python
installers also have to be universal. Fortunately, universal python versions
can be found at python.org at least for
(as of 2022-01-01) python3.8, python3.9, and python3.10.
- Sadly, notarization requires
altoolwhich is not distributed with the command line tools. So one needs to install the full xcode (at least version 12) from the App Store. That is very large and may take an hour or so to download. (should be checked to see if this is still the case.)
- Sadly, notarization requires
Install latest XQuartz release. At least XQuartz-2.8.0_rc1
brew install coreutils cmake bison flex open-mpi
Python 3.8 is already installed as /usr/bin/python3 and is universal2.
The normal source build explains how to install brew and add it to the PATH.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" echo 'eval $(/opt/homebrew/bin/brew shellenv)' >> $HOME/.zprofile eval $(/opt/homebrew/bin/brew shellenv)
Default build uses universal pythons from python.org. I also redundantly include their python3.8 as I find it more convenient to be able to explicitly specify the full name as python3.8.
All pythons used for building need numpy installed, e.g.
pip3.9 install --user --upgrade pip pip3.9 install --user numpy
At least one python3 in your PATH needs cython installed. And, to avoid compile errors, the minimum version is 0.29.26
python3.10 -m pip install --user cython
Signing and Notarization
Notarization needs a $99/year Apple Developer Program membership. Certificates last 5 years.
The most clearly explained recipe for notarization that I found is Notarizing installers for macOS Catalina .
However it took me while to figure out that it takes two certificates from apple. I.e. A “developerID_application.cer” to sign all the binaries before the pkg is built and a “developerID_installer.cer” to sign the pkg. Certificates can be obtained through Keychain by creating a certificate signing request On receipt of the certificates, I added to my keychain by clicking on them.
And one must manage an App specific password
to request notarization from Apple.
I put the password in
$HOME/.ssh/notarization-password which is where
src/mac/nrn_notarize.sh expects it.
Notarization requires that we “enable hardened runtime” which is done during the binary signing, but that results in issues with regard to apple events and mismatched, unsigned, and non-system libraries (as well as preventing JIT compilation). At this point How to add entitlements… was very helpful with regard to picking entitlements to develop a nrn_entitlements.plist to relax the strict hardened runtime.