Blog

Building Azure CLI on Apple Silicon MacOS (M1)

Update 4th Jan 2021: If you don't need Python 3.9, installing azure-cli natively can be done by using this homebrew formula: https://formulae.brew.sh/formula/azure-cli. Note: there's an open issue with upgrading: https://github.com/Azure/azure-cli/issues/16417.

Anyone else having trouble installing Azure CLI natively on Apple Silicon? You may remember some rough edges being mentioned in our previous post. If like me you're a big user of Azure's cloud services and you've got your hands on a new M1 MacBook Pro or MacBook Air, then you might have noticed that installing some software isn't as straight forward as it used to be. In this post I'll take you through the steps I took to install Azure CLI natively on your Apple Silicon Mac.

Official install docs

Note: this post is likely to become old pretty quickly given the pace at which things are being fixed for M1.

Install HomeBrew

As of the last few days, homebrew now supports Apple Silicon Mac natively which means no more manual steps on the M1, just go to the homebrew homepage and install as normal. It should install into /opt/homebrew/, you can test it by running $ brew in the terminal.

Install wget

This step is the simplest in this whole process, savour it:

brew install wget

Install Python 3

Install Python 3 with this command:

brew install python3

It will download and build targetting Apple Silicon ARM. We now need to check you can access python3 via the Terminal and that the right version is being loaded (MacOS comes with older versions of both Python2 and Python3):

type -a python3
python3 is /usr/bin/python3

If a path going via your homebrew folder isn't at the top of the list, e.g. python3 is /opt/homebrew/opt/python@3.9/bin/python3.9 , you can simply create an alias for it in your ~/.zshrc file.

Open ~/.zshrc with either nano or vim:

nano ~/.zshrc

and add these lines:

alias python3='/opt/homebrew/opt/python@3.9/bin/python3.9'
alias pip3='/opt/homebrew/bin/pip3'

Save (Control + O) and exit (Control + X), and run this for the changes to take effect:

source ~/.zshrc

Now check that your homebrew version of python3 is at the top of your type -a list:

type -a python3
python3 is an alias for /opt/homebrew/opt/python@3.9/bin/python3.9
python3 is /usr/bin/python3

You can run the same test for pip3. If the homebrew version is at the top of the type -a pip3 list then you're good to go!

Wall of Compilation Errors: pip3 install azure-cli

Normally it would be enough to run:

pip3 install azure-cli

and this would've been the end of the post had it not been for the wall of compilation errors I received as pip attempted to compile the dependencies for azure-cli. The following packages needed manual intervention:

  • cffi

  • cryptography

  • bcrypt

  • PyNaCl

After spending some hours troubleshooting these errors I was close to throwing in the towel, calling it a day on native brew/python and moving over to rosetta2. And then a breakthrough...

Build cffi

Building and installing the cryptography package requires cffi to be installed, and OpenSSL lib include files to be in your PATH. Both of these need manual attention:

  • cffi doesn't build via pip

  • OpenSSL isn't in the path

To build and install cffi follow these steps:

  1. Install libffi

brew install pkg-config libffi
  1. Take note of the path to this libffi.pc file:

find /opt/homebrew/ | grep "Cellar.*libffi.pc"
/opt/homebrew/Cellar/libffi/3.3/lib/pkgconfig/libffi.pc
  1. Grab the sources from https://pypi.org/project/cffi/:

wget https://files.pythonhosted.org/packages/66/6a/98e023b3d11537a5521902ac6b50db470c826c682be6a8c661549cb7717a/cffi-1.14.4.tar.gz
​
tar -xzvf cffi-1.14.4.tar.gz
cd cffi-1.14.4
  1. Edit setup.py and add the path for libffi.pc that you noted down in step 2 to include_dirs:

setup.py

import sys, os
import subprocess
import errno
​
# on Windows we give up and always import setuptools early to fix things for us
if sys.platform == "win32":
   import setuptools
​
​
sources = ['c/_cffi_backend.c']
libraries = ['ffi']
include_dirs = ['/usr/include/ffi',
               '/usr/include/libffi',
               '/opt/homebrew//Cellar/libffi/3.3/lib/pkgconfig/']
​
...
  1. Build

python3 setup.py install

cffi is done! Now to the next dependency ...

Build cryptography

azure-cli requires an older version (<3.0.0) of cryptography, which in turn needs the OpenSSL library. First grab OpenSSL via brew:

brew install openssl

Grab the lib path:

find /opt/homebrew | grep "Cellar.*openssl.*/lib$"
​
/opt/homebrew/Cellar/openssl@1.1/1.1.1i/lib

Now install version 2.9.2 and reference the OpenSSL lib and include folders from above:

pip3 install cryptography==2.9.2 --global-option=build_ext --global-option="-L/opt/homebrew/Cellar/openssl@1.1/1.1.1i/lib" --global-option="-I/opt/homebrew/Cellar/openssl@1.1/1.1.1i/include"

Only two more dependencies to go.

Build bcrypt and PyNaCl

Both bcrypt and PyNaCl have the same steps:

  • Download sources

  • Manual install

bcrypt

Go to https://pypi.org/project/bcrypt/ and download sources, unpack, and run setup.py:

wget https://files.pythonhosted.org/packages/d8/ba/21c475ead997ee21502d30f76fd93ad8d5858d19a3fad7cd153de698c4dd/bcrypt-3.2.0.tar.gz
​
tar -xzvf bcrypt-3.2.0.tar.gz
cd bcrypt-3.2.0
python3 setup.py install

PyNaCl

Go to https://pypi.org/project/PyNaCl/, get sources and do the same:

wget https://files.pythonhosted.org/packages/cf/5a/25aeb636baeceab15c8e57e66b8aa930c011ec1c035f284170cacb05025e/PyNaCl-1.4.0.tar.gz
​
tar -xzvf PyNaCl-1.4.0.tar.gz
cd PyNaCl-1.4.0
python3 setup.py install

Install azure-cli

Finally, you should have everything you need to install azure-cli via pip. Go ahead and try it:

pip3 install azure-cli

Good luck and thanks for reading!