2021-02-14
M1 MacBook 编程环境搭建
该文章写于 M1 芯片刚刚发布之时,部分内容距今已有较大变化,仅供参考。
关于M1芯片的评测网上都有一大堆,但是对于开发者的实际评测和arm架构下的环境配置教程几乎还没有。因此我就分享一下这几天折腾这台M1 MacBook Air的经验,即如何在M1芯片的Mac上配置常用的编程环境。
为充分体现M1芯片的优势,这里的编程环境,大部分只考虑已经支持原生arm版本或可以在M1芯片上成功编译成arm版本的软件。其架构说明一般为 macos-arm64、osx-arm64 或 macOS Universal App。同时还将对arm版本的软件进行性能和续航上的对比评测。
1. 编辑器/IDE
编辑器/IDE的支持情况如下表:
IDE |
支持状况 |
原生arm版(Universal App)下载方式 |
VS Code |
Insider Preview支持arm架构 |
https://code.visualstudio.com/insiders/ |
JetBrains 系列(PyCharm、Intellij IDEA、Clion等) |
原生arm支持 |
不要直接点下载,要点击右边的三角箭头,选择Universal |
XCode |
原生arm支持 |
App Sotre |
Vim |
原生arm支持 |
macOS自带,或通过brew install vim 安装 |
Visual Studio for Mac |
不支持(可通过 Rosetta 2 运行) |
|
Sublime |
不支持(可通过 Rosetta 2 运行) |
|
2. 编程语言
2.1 Homebrew
Homebrew是macOS上常用的软件包管理工具之一,类似于Linux中的apt
或yum
。前两天(2月5日)Homebrew刚刚发布了支持M1芯片的3.0.0正式版。可以打开终端,通过以下命令安装:
| /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
安装时可能无法访问该网站,可通过在家目录下的.bashrc
文件(没有则创建)中加入export HTTPS_PROXY="http://127.0.0.1:代理端口号"
设置bash的HTTP代理
M1芯片的Mac的Homebrew默认安装位置在/opt/homebrew
,而非/usr/local
,也就说明:
- 原来的
/usr/local/bin
对应/opt/homebrew/bin
- 原来的
/usr/local/sbin
对应/opt/homebrew/sbin
- 原来的
/usr/local/lib
对应/opt/homebrew/lib
- 原来的
/usr/local/include
对应/opt/homebrew/include
- 原来的
/usr/local/etc
对应/opt/homebrew/etc
- 以此类推
这个路径为之后的环境配置埋下了很大的坑!要注意。首先是PATH变量,在安装完成后,可以根据安装脚本的提示,将
| eval $(/opt/homebrew/bin/brew shellenv)
|
添加到家目录下的.zprofile
文件。这样即可直接使用brew
命令和/opt/homebrew/bin
下安装的软件。
在Homebrew网站上可以查询到所有可安装的软件包列表,点进去之后可以看到每个软件包对M1芯片的支持情况。虽然它不算编程语言,但是按照逻辑顺序放在这里说。
2.2 Python
以arm架构的3.9.1版本为例,虽然系统有自带的arm版本的python3.8.2,但是不建议使用,因为根据我打开VSCode的警告说,系统自带的Python会缺失部分功能。
2.2.1 通过Homebrew安装
https://formulae.brew.sh/formula/python@3.9
通过
即可安装arm版本的3.9.1,其路径在/opt/homebrew/bin/python3
。
安装好之后,需要通过pip3
安装一些基本的第三方库。由于这里是macos-arm64平台,因此很多库都没有来得及提供该平台的wheel,导致很多库都需要通过手动编译安装,而且编译过程往往出错。下面是常用库的arm版本的安装方法整理:
库名称 |
pip3 install 是否需要编译,编译是否成功 |
安装方法 |
numpy |
需要编译,编译失败 |
通过Homebrew:brew install numpy |
scipy |
需要编译,编译失败 |
通过Homebrew:brew install scipy |
matplotlib |
否(纯Python库) |
|
pandas |
需要编译,编译成功 |
|
sympy |
否(纯Python库) |
|
cv2 (opencv-python) |
没有这个平台的wheel,也没有源代码,无法安装 |
通过Homebrew:brew install opencv |
pycrypto |
需要编译,编译成功 |
|
requests |
否(纯Python库) |
|
flask |
否(纯Python库) |
|
jupyter |
需要编译,编译成功 |
|
scapy |
需要编译,编译成功 |
|
pillow |
需要编译,编译成功 |
|
pwntools |
需要编译,编译失败 |
编译失败的原因是其中的一个依赖cryptography编译失败,提示说是缺少rust语言的编译器,因此先通过brew install rust ,再安装即可成功(编译过程会较长) |
regex |
否(纯Python库) |
|
tensorflow |
需要编译,编译失败 |
根据说明安装Apple发布的tensorflow-macos(仅限python3.8) |
这些库在安装成功后,使用时目前没有发现什么问题。下面是我目前的pip3 list
结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120 | Package Version
------------------- ----------
anyio 2.1.0
appnope 0.1.2
argon2-cffi 20.1.0
astroid 2.4.2
async-generator 1.10
attrs 20.3.0
autopep8 1.5.5
Babel 2.9.0
backcall 0.2.0
bcrypt 3.2.0
bleach 3.3.0
capstone 4.0.2
certifi 2020.12.5
cffi 1.14.4
chardet 4.0.0
click 7.1.2
cryptography 3.4.4
cycler 0.10.0
decorator 4.4.2
defusedxml 0.6.0
entrypoints 0.3
Flask 1.1.2
idna 2.10
intervaltree 3.1.0
ipykernel 5.4.3
ipython 7.20.0
ipython-genutils 0.2.0
ipywidgets 7.6.3
isort 5.7.0
itsdangerous 1.1.0
jedi 0.18.0
Jinja2 2.11.3
json5 0.9.5
jsonschema 3.2.0
jupyter 1.0.0
jupyter-client 6.1.11
jupyter-console 6.2.0
jupyter-core 4.7.1
jupyter-server 1.3.0
jupyterlab 3.0.7
jupyterlab-pygments 0.1.2
jupyterlab-server 2.2.0
jupyterlab-widgets 1.0.0
kiwisolver 1.3.1
lazy-object-proxy 1.4.3
Mako 1.1.4
MarkupSafe 1.1.1
matplotlib 3.3.4
mccabe 0.6.1
mistune 0.8.4
mpmath 1.2.1
nbclassic 0.2.6
nbclient 0.5.2
nbconvert 6.0.7
nbformat 5.1.2
nest-asyncio 1.5.1
netifaces 0.10.9
notebook 6.2.0
numpy 1.20.1
packaging 20.9
pandocfilters 1.4.3
paramiko 2.7.2
parso 0.8.1
pexpect 4.8.0
pickleshare 0.7.5
Pillow 8.1.0
pip 21.0.1
prometheus-client 0.9.0
prompt-toolkit 3.0.14
protobuf 3.14.0
psutil 5.8.0
ptyprocess 0.7.0
pwntools 4.3.1
pybind11 2.6.2
pycodestyle 2.6.0
pycparser 2.20
pycrypto 2.6.1
pyelftools 0.27
Pygments 2.7.4
pylint 2.6.0
PyNaCl 1.4.0
pyparsing 2.4.7
PyQt5 5.15.2
PyQt5-sip 4.19.24
pyrsistent 0.17.3
pyserial 3.5
PySocks 1.7.1
python-dateutil 2.8.1
pytz 2021.1
pyzbar 0.1.8
pyzmq 22.0.2
qtconsole 5.0.2
QtPy 1.9.0
regex 2020.11.13
requests 2.25.1
ROPGadget 6.5
scapy 2.4.4
scipy 1.6.0
Send2Trash 1.5.0
setuptools 52.0.0
six 1.15.0
sniffio 1.2.0
sortedcontainers 2.3.0
sympy 1.7.1
TBB 0.1
terminado 0.9.2
testpath 0.4.4
toml 0.10.2
tornado 6.1
traitlets 5.0.5
unicorn 1.0.2rc3
urllib3 1.26.3
wcwidth 0.2.5
webencodings 0.5.1
Werkzeug 1.0.1
wheel 0.36.2
widgetsnbextension 3.5.1
wrapt 1.12.1
|
2.2.2 通过Miniforge安装
Miniforge是Conda-forge的发型版本。虽然Anaconda没有支持arm,但是miniforge已经支持。可以通过
| brew install --cask miniforge
|
安装miniforge,或者手动去GitHub下载脚本安装。
之后,通过
命令即可安装众多的库的osx-arm64版本。这个方法的好处是不需要编译,支持的包多了很多,可在此处搜索软件包,并点进去查看是否存在osx-arm64版本。2.2.1列表中所有的除了Tensorflow之外,均可安装。Tensorflow在Conda下的安装方法可以参考Apple发布的tensorflow-macos中发布的这个issue(仅限python3.8版本,可通过conda install指定版本安装)
但是!通过这种方式安装的python库,在需要用到lib
目录下的库时,问题就来了!在Mac版本的Python中,find_library
函数的实现并不是查看PATH,而是搜索常用的几个路径,那么显然/opt/homebrew/lib
肯定不在这些常用的路径内,因此在使用如pyzbar
这种库时,就算安装成功,import的时候还是会报错!
解决方法有以下两种:
- 创建
/usr/local/lib
的符号连接,指向/opt/homebrew/lib
:
| sudo ln -s /opt/homebrew/lib /usr/local/lib
|
此外在conda环境下用pip安装,需要编译时,如果提示头文件找不到,也需要将include
目录进行链接:
| sudo ln -s /opt/homebrew/include /usr/local/include
|
- 将Homebrew的安装路径在一开始安装时就手动改为
/usr/local
我就是感觉上述两种做法都不是很优雅,因此还是弃用了conda,直接用Homebrew+pip+手动编译装的各种库。下面是我目前的conda list
结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 | # packages in environment at /opt/homebrew/Caskroom/miniforge/base:
#
# Name Version Build Channel
brotlipy 0.7.0 py39h51e6412_1001 conda-forge
bzip2 1.0.8 h27ca646_4 conda-forge
c-ares 1.17.1 h27ca646_0 conda-forge
ca-certificates 2020.12.5 h4653dfc_0 conda-forge
cairo 1.16.0 h11c81c9_1007 conda-forge
certifi 2020.12.5 py39h2804cbe_1 conda-forge
cffi 1.14.4 py39h702c04f_1 conda-forge
chardet 4.0.0 py39h2804cbe_0 conda-forge
click 7.1.2 pyh9f0ad1d_0 conda-forge
conda 4.9.2 py39h2804cbe_0 conda-forge
conda-package-handling 1.7.2 py39h51e6412_0 conda-forge
cryptography 3.3.1 py39h0bed37e_0 conda-forge
cycler 0.10.0 py_2 conda-forge
ffmpeg 4.3.1 h22aafd7_2 conda-forge
flask 1.1.2 pyh9f0ad1d_0 conda-forge
fontconfig 2.13.1 h751047c_1004 conda-forge
freetype 2.10.4 h17b34a0_1 conda-forge
gettext 0.19.8.1 hea66d9f_1005 conda-forge
gmp 6.2.1 h9f76cd9_0 conda-forge
gmpy2 2.1.0b1 py39ha931add_1 conda-forge
gnutls 3.6.13 h706517b_1 conda-forge
graphite2 1.3.13 h9f76cd9_1001 conda-forge
harfbuzz 2.7.4 head39c9_0 conda-forge
hdf5 1.10.6 nompi_h0fc092c_1114 conda-forge
icu 68.1 h17758a7_0 conda-forge
idna 2.10 pyh9f0ad1d_0 conda-forge
itsdangerous 1.1.0 py_0 conda-forge
jasper 2.0.14 h9af5a26_2 conda-forge
jinja2 2.11.3 pyh44b312d_0 conda-forge
joblib 1.0.1 pyhd8ed1ab_0 conda-forge
jpeg 9d h27ca646_0 conda-forge
kiwisolver 1.3.1 py39h5a63225_1 conda-forge
krb5 1.17.2 h17618d6_0 conda-forge
lame 3.100 h27ca646_1001 conda-forge
lcms2 2.12 had6a04f_0 conda-forge
libblas 3.9.0 8_openblas conda-forge
libcblas 3.9.0 8_openblas conda-forge
libcurl 7.71.1 hd2aec06_8 conda-forge
libcxx 11.0.1 h168391b_0 conda-forge
libedit 3.1.20191231 hc8eb9b7_2 conda-forge
libev 4.33 h642e427_1 conda-forge
libffi 3.3 h9f76cd9_2 conda-forge
libgfortran 5.0.0.dev0 11_0_0_hdc626ea_17 conda-forge
libgfortran5 11.0.0.dev0 hdc626ea_17 conda-forge
libglib 2.66.6 h59da672_3 conda-forge
libiconv 1.16 h642e427_0 conda-forge
liblapack 3.9.0 8_openblas conda-forge
liblapacke 3.9.0 8_openblas conda-forge
libnghttp2 1.43.0 hf3018f0_0 conda-forge
libopenblas 0.3.12 openmp_h2ecc587_1 conda-forge
libopencv 4.5.1 py39hd230a0b_0 conda-forge
libpng 1.6.37 hf7e6567_2 conda-forge
libssh2 1.9.0 h1c49ba1_5 conda-forge
libtiff 4.2.0 h70663a0_0 conda-forge
libwebp-base 1.2.0 h27ca646_0 conda-forge
libxml2 2.9.10 h8f9ca65_3 conda-forge
llvm-openmp 11.0.1 hb3022d6_0 conda-forge
lz4-c 1.9.3 h9f76cd9_0 conda-forge
markupsafe 1.1.1 py39h46acfd9_3 conda-forge
matplotlib 3.3.4 py39hdf13c20_0 conda-forge
matplotlib-base 3.3.4 py39h3e8bbd8_0 conda-forge
mpc 1.1.0 hb760245_1009 conda-forge
mpfr 4.0.2 hbc63f68_1 conda-forge
mpmath 1.2.1 pyhd8ed1ab_0 conda-forge
ncurses 6.2 h9aa5885_4 conda-forge
netifaces 0.10.9 py39h46acfd9_1003 conda-forge
nettle 3.6 hc6a1b29_0 conda-forge
numpy 1.20.0 py39h69a04d8_0 conda-forge
olefile 0.46 pyh9f0ad1d_1 conda-forge
opencv 4.5.1 py39hdf13c20_0 conda-forge
openh264 2.1.1 habe5f53_0 conda-forge
openssl 1.1.1i h27ca646_0 conda-forge
pcre 8.44 hb904e53_0 conda-forge
pillow 8.1.0 py39hf007017_2 conda-forge
pip 20.3.3 pyhd8ed1ab_0 conda-forge
pixman 0.40.0 h27ca646_0 conda-forge
py-opencv 4.5.1 py39hfa6204d_0 conda-forge
pycosat 0.6.3 py39h51e6412_1005 conda-forge
pycparser 2.20 pyh9f0ad1d_2 conda-forge
pycrypto 2.6.1 py39h51e6412_1005 conda-forge
pyopenssl 20.0.1 pyhd8ed1ab_0 conda-forge
pyparsing 2.4.7 pyh9f0ad1d_0 conda-forge
pysocks 1.7.1 py39h0caf4da_2 conda-forge
python 3.9.1 hcbd9b3a_2_cpython conda-forge
python-dateutil 2.8.1 py_0 conda-forge
python_abi 3.9 1_cp39 conda-forge
readline 8.0 hc8eb9b7_2 conda-forge
regex 2020.11.13 py39h46acfd9_1 conda-forge
requests 2.25.1 pyhd3deb0d_0 conda-forge
ruamel_yaml 0.15.80 py39h51e6412_1003 conda-forge
scikit-learn 0.24.1 py39hb966dd2_0 conda-forge
scipy 1.6.0 py39h73ea49b_0 conda-forge
setuptools 49.6.0 py39h0caf4da_2 conda-forge
six 1.15.0 pyh9f0ad1d_0 conda-forge
sqlite 3.34.0 h6d56c25_0 conda-forge
sympy 1.7.1 py39h2804cbe_1 conda-forge
threadpoolctl 2.1.0 pyh5ca1d4c_0 conda-forge
tk 8.6.10 hf7e6567_1 conda-forge
tornado 6.1 py39h46acfd9_1 conda-forge
tqdm 4.55.0 pyhd8ed1ab_0 conda-forge
tzdata 2020f he74cb21_0 conda-forge
urllib3 1.26.2 pyhd8ed1ab_0 conda-forge
werkzeug 1.0.1 pyh9f0ad1d_0 conda-forge
wheel 0.36.2 pyhd3deb0d_0 conda-forge
x264 1!161.3030 h27ca646_0 conda-forge
xz 5.2.5 h642e427_1 conda-forge
yaml 0.2.5 h642e427_0 conda-forge
zlib 1.2.11 h31e879b_1009 conda-forge
zstd 1.4.8 h5b28eab_1 conda-forge
|
2.3 Java
2.3.1 OpenJDK
Homebrew中提供了OpenJDK 15的arm版本:
但是不会安装在macOS的Library
目录下。而且默认不将java
和javac
放入/opt/homebrew/bin
内,因为macOS自带有java
和javac
命令,会在Library
目录下找安装的JDK/JRE来执行。
并且,在IDEA中打开时,要选择JDK。macOS的Finder默认不会显示/opt
这个目录,导致JDK选择困难。因此建议通过下面的方法安装。
2.3.2 Azul Zulu JDK
可在官网下载全部的JDK8~JDK16的macos-arm64版本的JDK。相比于上述只有15的版本友好了很多:
https://www.azul.com/downloads/zulu-community/?package=jdk
2.3.3 maven、gradle
由于都是基于Java的运行环境,因此均可通过Homebrew安装,只要安装的Java的运行环境是arm的即可发挥出M1芯片的全部性能:
| brew install maven
brew install gradle
|
2.4 C/C++
2.4.1 GCC/GDB
目前只能通过Homebrew安装arm版本的GCC,而无法安装GDB:
因此不建议使用GCC。
2.4.2 clang/LLDB
arm版本clang/LLDB的只需安装XCode的命令行工具即可:
VSCode的C/C++插件目前不支持调试功能。是我自己测的,会有报错,然后在GitHub上搜到了issue,大概意思不支持,但是也不确定,可能自己再折腾折腾。
不过这年头谁还不会手动命令行编译调试C/C++呢?或者可以使用XCode配置C/C++开发环境,具体配置方法是建立macOS的command line tool project,然后就可以开始写了。界面和代码补全不输VSCode,而且早就支持了arm版本,更稳定,也支持调试功能。
2.5 NodeJS
从v15版本开始支持,可通过Homebrew直接安装:
2.6 PHP
从PHP8版本开始支持,可通过Homebrew直接安装:
2.7 TexLive(Latex)
根据MacTex的官网,其目前只提供了MacTex2020的intel版本,但是提供了一个补丁用来尝鲜。正式版的支持arm的版本将在今年4月10日随TexLive2021推出。
首先可通过Homebrew安装TexLive:
| brew install --cask mactex-no-gui
|
之后在MacTex官网的About ARM网页 http://www.tug.org/mactex/aboutarm.html 下载补丁mactex-2020-universal.pkg
。即可。
可以配合VSCode的arm预览版的Latex Workshop插件使用。
3. arm版本软件性能评测
将这台M1 MacBook Air(16G内存+1T SSD)运行arm64版本的软件,与我之前使用的 Windows 10 笔记本,CPU:i5-8300H,内存:16G DDR4,显卡:Nvidia GTX 1050Ti,存储:128G SSD+1T 5600转机械硬盘运行x86-64的软件进行简单的对比:
项目 |
16G M1 MacBook Air |
16G i5-8300H 1050Ti Windows 10(过去的经验) |
使用VSCode对Latex Workshop插件,编译23页tex论文,内含大量图表,公式,代码 |
1.9s |
>5s |
使用PyCharm,启动包括Tensorflow、OpenCV、zbar、Flask等框架的Python AI项目,包括后端服务器和前端的可视化界面 |
14s |
>1min |
使用PyCharm IDE,通过自己训练的Tensorflow模型对比两张2000x2000左右大小的两张图片 |
2-3s |
5s |
4. arm版本软件续航评测
从晚上10点左右开始,使用arm版本的Typora一直编写本文章。起始电池电量为78%,截至发稿前,电池电量为66%。
这个是今天早上起来截图的电池电量变化情况: