Mojo is a programming language in the Python family that is currently under development. It is available both in browsers via Jupyter notebooks, and locally on Linux and macOS. Mojo aims to combine the usability of higher level languages, specifically Python, with the performance of C.
Somebody is excited to install Mojo then import python and run it successfully. But many developers get the crash errors when trying to compile matmul.mojo so I have the steps to install Mojo on Mac M1.
Setup Mojo on your Apple Mac M1
1. Install LLVM
❯ brew install llvm
Find llvm-symbolizer and set environment variables
❯ which llvm-symbolizer
# output (depends on your machine)
/opt/homebrew/opt/llvm/bin/llvm-symbolizer
# Set environment variables
❯ echo 'export LLVM_SYMBOLIZER_PATH=/opt/homebrew/opt/llvm/bin/llvm-symbolizer' >> ~/.zshrc
❯ echo 'export PATH="/opt/homebrew/opt/llvm/bin:$PATH"' >> ~/.zshrc
2. Find libpython path and set environment variables
❯ python3 -c 'from distutils.sysconfig import get_config_var; print(get_config_var("LIBDIR"))'
# output (depends on your machine)
/Library/Frameworks/Python.framework/Versions/3.11/lib
# Set environment variables (in my case I add libpython3.11.dylib to export)
❯ echo 'export MOJO_PYTHON_LIBRARY=/Library/Frameworks/Python.framework/Versions/3.11/lib/libpython3.11.dylib' >> ~/.zshrc
3. Install Modular CLI and Mojo
- Open a terminal and install the
modular
command line tool:
❯ curl -s https://get.modular.com | sh -
- Create a virtual environment (venv):
❯ python3 -m venv mojo-venv && source mojo-venv/bin/activate
- Install the Mojo SDK:
❯ modular install mojo
- Set environment variables so you can access the
mojo
CLI:
MOJO_PATH=$(modular config mojo.path) \
&& echo 'export MODULAR_HOME="'$HOME'/.modular"' >> ~/.zshrc \
&& echo 'export PATH="'$MOJO_PATH'/bin:$PATH"' >> ~/.zshrc \
&& source ~/.zshrc
4. Import a Python module and test to compile it.
numpy.mojo
from python import Python as py
fn main() raises:
var np = py.import_module("numpy")
print(np.random.randn(3,7))
My result:
❯ mojo numpy.mojo
[[ 0.66329923 -0.11868471 -1.06669953 -0.53430519 -0.44231878 0.26146746
-1.61017704]
[-0.03782034 0.96675627 -1.32332878 0.42742955 -1.8118554 -0.15178111
0.38730785]
[-0.42854056 -1.04232756 -0.51043699 -0.77194897 0.65061858 0.48454981
-0.74015433]]
Clone the example repo
❯ git clone https://github.com/modularml/mojo.git
❯ cd mojo/examples
My result for compiling matmul.mojo:
❯ mojo matmul.mojo
CPU Results
Python: 0.006 GFLOPS
Numpy: 194.277 GFLOPS
Naive: 6.036 GFLOPS 1086.61x Python
Vectorized: 24.379 GFLOPS 4388.97x Python
Parallelized: 43.951 GFLOPS 7912.57x Python
Tiled: 46.201 GFLOPS 8317.63x Python
Unrolled: 45.654 GFLOPS 8219.14x Python
Wow!!!… 8219.14x Python
And the Matmul result from Jupyter notebook from my Mac M1.
Wow!!!… 9541.76x Python
Note from Mojo
A few things to note:
- Currently, you cannot import individual members (such as a single Python class or function) — you must import the whole Python module and then access members through the module name.
- Mojo doesn’t yet support top-level code, so the
import_module()
call must be inside another method. This means you may need to import a module multiple times or pass around a reference to the module. This works the same way as Python: importing the module multiple times won't run the initialization logic more than once, so you don't pay any performance penalty. import_module()
may raise an exception (for example, if the module isn't installed). If you're using it inside anfn
function, you need to either handle errors (using atry/except
clause), or add theraises
keyword to the function signature. You'll also see this when calling Python functions that may raise exceptions. (Raising exceptions is much more common in Python code than in the Mojo standard library, which limits their use for performance reasons.)