Installing pycurl on MacOS with Python 3.6+ and newer proved to be tricky, especially since a lot of the available resources seem to be outdated (1, 2, 3).
This gist was last updated at 2020-12-31.
- Remove previously installed Homebrew versions of
curl:
brew uninstall curl
brew uninstall openssl
brew uninstall curl-openssl- Install
openssland acurlversion that uses openssl rather than SecureTransport, which MacOScurluses by default. Note that Homebrew no longer allows options while installing, so it's not possible to dobrew install curl --with-openssl. This was replaced with a different brew formula,curl-openssl, and again replaced on2020-01-20with the current version of justcurl.:
brew install openssl
brew install curl # this is the latest version with openssl- Now we need to use the new curl when installing pycurl. We can also export the path to the new curl to make it used by default:
echo 'export PATH="/usr/local/opt/[email protected]/bin:$PATH"' >> ~/.zshrc # or ~/.bash_profile
echo 'export PATH="/usr/local/opt/curl/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
source ~/.virtualenvs/foo_venv/bin/activate # or whichever venv you're using
export PYCURL_SSL_LIBRARY=openssl
export LDFLAGS="-L/usr/local/opt/curl/lib"
export CPPFLAGS="-I/usr/local/opt/curl/include"
pip install --no-cache-dir --compile --ignore-installed --install-option="--with-openssl" --install-option="--openssl-dir=/usr/local/opt/[email protected]" pycurl- Test with:
python
>>> import pycurl- The original OS X one in
/usr/bin/curl:
$ /usr/bin/curl --version
curl 7.64.1 (x86_64-apple-darwin20.0) libcurl/7.64.1 (SecureTransport) LibreSSL/2.8.3 zlib/1.2.11 nghttp2/1.41.0
Release-Date: 2019-03-27
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS GSS-API HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz MultiSSL NTLM NTLM_WB SPNEGO SSL UnixSockets- The Homebrew one in
/usr/local/opt/curl/bin/curl:
$ /usr/local/opt/curl/bin/curl --version
curl 7.74.0 (x86_64-apple-darwin20.2.0) libcurl/7.74.0 (SecureTransport) OpenSSL/1.1.1i zlib/1.2.11 brotli/1.0.9 zstd/1.4.8 libidn2/2.3.0 libssh2/1.9.0 nghttp2/1.42.0 librtmp/2.3
Release-Date: 2020-12-09
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli GSS-API HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz Metalink MultiSSL NTLM NTLM_WB SPNEGO SSL TLS-SRP UnixSockets zstdAnd our pycurl should use the second one, both at linker level and at compile level.
None of the above solutions worked for me on Mac 12.1 and I was getting error
ImportError: pycurl: libcurl link-time version (7.77.0) is older than compile-time version (7.81.0)I managed to work around it building the exact curl binary I needed (7.77.0) from the libcurl repo and wiring that into pycurl using
install_name_tool. Locations of these will depend on your system but these were my steps. I already had xcode cli tools installed.Idea is:
install_name_tool -change old.dylib new.dylib pycurl.soFor example:
install_name_tool -change /usr/lib/libcurl.4.dylib /usr/local/opt/curl/lib/libcurl.4.dylib /Users/user/Library/Python/2.7/lib/python/site-packages/pycurl.soAnother example on a different mac with python 3.9 and pyenv I ran this:
install_name_tool -change /usr/local/Cellar/curl/7.81.0/lib/libcurl.4.dylib /opt/vagrant/embedded/lib/libcurl.4.dylib /Users/username/.local/share/virtualenvs/website-TeaFLnO_/lib/python3.9/site-packages/pycurl.cpython-39-darwin.sobrew uninstall curl(might not be necessary)install_name_toolto link the dynamic library you need. Usefind \ -nameif to locate the dylib's if needed.autoreconf -fi,./configure --prefix=/usr/local/opt/curl --without-ssl,makepip uninstall pycurl && pip install --no-cache-dir --compile --install-option="--with-openssl" pycurlSanity is restored and everything just works now. Hope this helps someone!