-
-
Save Kolcha/3ccd533123b773ba110b8fd778b1c2bf to your computer and use it in GitHub Desktop.
#!/bin/zsh | |
# standalone script to build qBittorent for macOS (including Apple Silicon based Macs) | |
# | |
# only Xcode must be installed (Xcode 12 is required to produce arm64 binaries) | |
# all required dependencies and tools are automatically downloaded and used only from script's working directory | |
# (can be specified), nothing is installed into the system | |
# working directory is removed on completion if it was not specified | |
# | |
# by default script produces binaries for the architecture it was launched on, but cross-compilation is also supported | |
# in both directions, i.e. x86_64 -> arm64 and arm64 -> x86_64 | |
# | |
# following conventions are used in the script: | |
# - variables names are in snake-case (special variables are an exception) | |
# - variables starting with '_' (underscore) should be considered "internal" | |
# - variables without '_' prefix can be considered "options" or "default values" | |
# | |
# script accepts few arguments which can customize its behavior the same way as editing "option" variables, | |
# see 'command line arguments parsing' section for details and possible options | |
# | |
# script is not interactive and doesn't ask anything, it just automates build routine | |
# it can be launched multiple times with the same or different set of arguments, this may be useful for development | |
# environment setup for example (just pass some working directory, and it will contain everything required for | |
# qBittorrent development) | |
# moreover, passing the same working directory with other arguments allows you to get environment with few different | |
# Qt and/or libtorrent versions (or libraries for different architectures) that you can switch easily | |
# | |
# script is "smart enough" to download and build only required parts (which it considers "missing", but not due to | |
# dependency change) in case when the same working directory is specified multiple times | |
# qBittorrent is compiled in any case, result .dmg file is overridden if required | |
# ===================================================================================================================== | |
# software versions to use | |
qbittorrent_ver=master # qBittorrent https://github.com/qbittorrent/qBittorrent/releases | |
openssl_ver=3.0.11 # OpenSSL https://www.openssl.org/source/ | |
boost_ver=1.83.0 # Boost https://www.boost.org/ | |
libtorrent_ver=2.0.9 # libtorrent https://github.com/arvidn/libtorrent/releases | |
qt_ver=6.5.3 # Qt https://code.qt.io/cgit/qt/qt5.git/refs/tags | |
cmake_ver=3.27.6 # CMake https://cmake.org/download/ | |
# build environment variables | |
target_arch=$(uname -m) # target architecture, host by default | |
min_macos_ver=11.0 # minimum version of the target platform | |
# ===================================================================================================================== | |
work_dir="" # working directory, all files will be placed here | |
prod_dir="${HOME}/Downloads" # output directory for result qBittorrent .dmg image | |
universal_arch_tag="universal" # value used as arch to build a universal binary | |
# --------------------------------------------------------------------------------------------------------------------- | |
# command line arguments parsing | |
# https://stackoverflow.com/questions/402377/using-getopts-to-process-long-and-short-command-line-options | |
_die() { echo "$*" >&2; exit 2; } | |
_needs_arg() { if [ -z "$OPTARG" ]; then _die "No arg for --$OPT option"; fi; } | |
_no_arg() { if [ -n "$OPTARG" ]; then _die "No arg allowed for --$OPT option"; fi; } | |
while getopts ha:w:o:-: OPT; do | |
if [ "$OPT" = "-" ]; then | |
OPT="${OPTARG%%=*}" | |
OPTARG="${OPTARG#$OPT}" | |
OPTARG="${OPTARG#=}" | |
fi | |
case "$OPT" in | |
h | help ) | |
echo "no help there! but script accepts few command line agruments, just open it to find them :)" | |
exit 0 | |
;; | |
a | target-arch ) _needs_arg; target_arch="$OPTARG" ;; | |
w | workdir ) _needs_arg; work_dir="${OPTARG%/}" ;; | |
o | outdir ) _needs_arg; prod_dir="${OPTARG%/}" ;; | |
qbittorrent ) _needs_arg; qbittorrent_ver="$OPTARG" ;; | |
openssl ) _needs_arg; openssl_ver="$OPTARG" ;; | |
boost ) _needs_arg; boost_ver="$OPTARG" ;; | |
libtorrent ) _needs_arg; libtorrent_ver="$OPTARG" ;; | |
qt ) _needs_arg; qt_ver="$OPTARG" ;; | |
cmake ) _needs_arg; cmake_ver="$OPTARG" ;; | |
macos ) _needs_arg; min_macos_ver="$OPTARG" ;; | |
??* ) _die "Illegal option --$OPT" ;; # bad long option | |
? ) exit 2 ;; # bad short option (error reported via getopts) | |
esac | |
done | |
shift $((OPTIND-1)) | |
# --------------------------------------------------------------------------------------------------------------------- | |
set -o errexit # exit immediately if a command exits with a non-zero status | |
set -o nounset # treat unset variables as an error when substituting | |
set -o xtrace # print commands and their arguments as they are executed | |
set -o pipefail # the return value of a pipeline is the status of the last command to exit with a non-zero status | |
# --------------------------------------------------------------------------------------------------------------------- | |
# working directory setup | |
if [[ -z ${work_dir} ]] | |
then | |
work_dir=$(mktemp -d) | |
_remove_work_dir=1 | |
else | |
mkdir -p "${work_dir}" | |
_remove_work_dir=0 | |
fi | |
# output directory setup | |
[[ -d "${prod_dir}" ]] || mkdir -p "${prod_dir}" | |
# get rid of symlinks in paths, Qt6 build system fails if they are faced... requires zsh! | |
work_dir=${work_dir:A} | |
prod_dir=${prod_dir:A} | |
cd "${work_dir}" | |
_src_dir="${work_dir}/src" # sources will be downloaded here | |
_tmp_dir="${work_dir}/build-${target_arch}" # build intermediates will placed here | |
_lib_dir="${work_dir}/lib-${target_arch}" # compiled libraries and headers go here | |
_qbt_dmg_path="${prod_dir}/qBittorrent-${qbittorrent_ver}-macOS-${target_arch}.dmg" | |
[[ "${target_arch}" == "${universal_arch_tag}" ]] && target_arch="x86_64;arm64" | |
# --------------------------------------------------------------------------------------------------------------------- | |
# download everything required (only missing parts will be downloaded) | |
mkdir -p ${_src_dir} | |
pushd "${_src_dir}" > /dev/null | |
_qbt_src_dir_name="qBittorrent-${qbittorrent_ver}" | |
_qbt_src_dir="${_src_dir}/${_qbt_src_dir_name}" | |
_qbt_tmp_dir="${_tmp_dir}/${_qbt_src_dir_name}" | |
# anything known to git (i.e. branch names or tags) can be used as 'version' | |
[[ -d ${_qbt_src_dir} ]] || curl -L https://github.com/qbittorrent/qBittorrent/archive/{$qbittorrent_ver}.tar.gz | tar xz | |
_ssl_src_dir_name="openssl-${openssl_ver}" | |
_ssl_src_dir="${_src_dir}/${_ssl_src_dir_name}" | |
_ssl_tmp_dir="${_tmp_dir}/${_ssl_src_dir_name}" | |
_ssl_lib_dir="${_lib_dir}/${_ssl_src_dir_name}" | |
[[ -d ${_ssl_src_dir} ]] || curl -L https://www.openssl.org/source/openssl-${openssl_ver}.tar.gz | tar xz | |
_boost_ver_u=${boost_ver//./_} | |
_boost_src_dir_name="boost_${_boost_ver_u}" | |
_boost_src_dir="${_src_dir}/${_boost_src_dir_name}" | |
# boost will NOT be compiled, only headers are enough, since 1.69.0 Boost.System is header-only | |
[[ -d ${_boost_src_dir} ]] || curl -L https://boostorg.jfrog.io/artifactory/main/release/${boost_ver}/source/boost_${_boost_ver_u}.tar.bz2 | tar xj | |
_lt_src_dir_name="libtorrent-rasterbar-${libtorrent_ver}" | |
_lt_src_dir="${_src_dir}/${_lt_src_dir_name}" | |
_lt_tmp_dir="${_tmp_dir}/${_lt_src_dir_name}" | |
_lt_lib_dir="${_lib_dir}/${_lt_src_dir_name}" | |
# use libtorrent release archives, because GitHub doesn't include submodules into generated archives, | |
# but since 2.0 libtorrent has few, and they are required for compilation | |
[[ -d ${_lt_src_dir} ]] || curl -L https://github.com/arvidn/libtorrent/releases/download/v${libtorrent_ver}/libtorrent-rasterbar-${libtorrent_ver}.tar.gz | tar xz | |
# Qt6 requires ninja build system. even this is not strict requirement, but why not to satisfy it? | |
# download ninja sources and later build them for required architecture, use master branch | |
_ninja_ver="master" # ninja https://github.com/ninja-build/ninja/releases | |
_ninja_src_dir_name="ninja-${_ninja_ver}" | |
_ninja_src_dir="${_src_dir}/${_ninja_src_dir_name}" | |
_ninja_tmp_dir="${work_dir}/build-$(uname -m)/${_ninja_src_dir_name}" | |
# anything known to git (i.e. branch names or tags) can be used as 'version' | |
[[ -d ${_ninja_src_dir} ]] || curl -L https://github.com/ninja-build/ninja/archive/{$_ninja_ver}.tar.gz | tar xz | |
# unfortunately, Qt repository must be cloned... it is much easier rather to deal with release archive | |
_qt_src_dir_name="qt-${qt_ver}" | |
_qt_src_dir="${_src_dir}/${_qt_src_dir_name}" | |
_qt_tmp_dir="${_tmp_dir}/${_qt_src_dir_name}" | |
_qt_lib_dir="${_lib_dir}/${_qt_src_dir_name}" | |
if ! [[ -d ${_qt_src_dir} ]] | |
then | |
git clone https://code.qt.io/qt/qt5.git ${_qt_src_dir_name} | |
cd ${_qt_src_dir_name} | |
git checkout "v${qt_ver}" # use only tags, not branches | |
perl init-repository --module-subset=qtbase,qtsvg,qttools,qttranslations | |
cd .. | |
fi | |
popd > /dev/null # back to working directory | |
# download CMake, 3.19.2 and above is required for Apple Silicon support | |
_cmake_dir_name="cmake-${cmake_ver}-macos-universal" | |
[[ -d ${_cmake_dir_name} ]] || curl -L https://github.com/Kitware/CMake/releases/download/v${cmake_ver}/cmake-${cmake_ver}-macos-universal.tar.gz | tar xz | |
cmake="${work_dir}/${_cmake_dir_name}/CMake.app/Contents/bin/cmake" | |
# Qt6 uses CMake as build system, but also provides convenient configure script | |
# this script relies on cmake executable in PATH | |
export PATH="$(dirname ${cmake})":$PATH | |
# Qt6 requires ninja build system. even this is not strict requirement, but why not to satisfy it? | |
# even more, ninja can be used to build almost any cmake-based project | |
# ninja is a build tool, so it must be compiled only for build host architecture, so that's why CMAKE_OSX_ARCHITECTURES is omitted | |
if ! [[ -d ${_ninja_tmp_dir} ]] | |
then | |
${cmake} -S ${_ninja_src_dir} -B ${_ninja_tmp_dir} -D CMAKE_VERBOSE_MAKEFILE=ON -D CMAKE_OSX_DEPLOYMENT_TARGET=${min_macos_ver} -D CMAKE_BUILD_TYPE=Release | |
${cmake} --build ${_ninja_tmp_dir} -j$(sysctl -n hw.ncpu) | |
fi | |
# to be able to use ninja, it must be available in PATH | |
export PATH=${_ninja_tmp_dir}:$PATH | |
# --------------------------------------------------------------------------------------------------------------------- | |
# everything is prepared now, time to start the build | |
# | |
# all dependencies are built as static libraries, the main reason for that was a possibility to use LTO | |
# | |
# all options used at configuration step are set only based on only my opinion or preference, there are no strict | |
# reasons for most of options in most cases | |
# OpenSSL doesn't provide the way to build an universal binary in one build step, so the only one way to get it - | |
# is build for each architecture separately and then merge architecture-specific binaries into one universal binary | |
function build_openssl_arch() | |
{ | |
local arch=$1 | |
local ssl_lib_dir="${work_dir}/lib-${arch}/${_ssl_src_dir_name}" | |
local ssl_tmp_dir="${work_dir}/build-${arch}/${_ssl_src_dir_name}" | |
if ! [[ -d ${ssl_lib_dir} ]] | |
then | |
rm -rf ${ssl_tmp_dir} && mkdir -p $_ && cd $_ | |
"${_ssl_src_dir}/Configure" no-comp no-dynamic-engine no-tests no-shared no-zlib --openssldir=/etc/ssl --prefix=${ssl_lib_dir} -mmacosx-version-min=${min_macos_ver} darwin64-${arch}-cc | |
make -j$(sysctl -n hw.ncpu) | |
make install_sw | |
cd - | |
fi | |
} | |
# OpenSSL is used by Qt, which is compiled as universal binaries in case of cross-compilation | |
# so OpenSSL is also must be universal binary when it is used for cross-compilation | |
[[ "${target_arch}" != "$(uname -m)" ]] && _ssl_lib_dir="${work_dir}/lib-${universal_arch_tag}/${_ssl_src_dir_name}" | |
if ! [[ -d ${_ssl_lib_dir} ]] | |
then | |
if [[ "${target_arch}" == "$(uname -m)" ]] | |
then | |
build_openssl_arch ${target_arch} | |
else | |
build_openssl_arch x86_64 | |
build_openssl_arch arm64 | |
mkdir -p "${_ssl_lib_dir}/lib" | |
# copy include directory (includes are the same for each arch) | |
cp -r "${work_dir}/lib-x86_64/${_ssl_src_dir_name}/include" "${_ssl_lib_dir}/" | |
# create universal binaries using lipo | |
lipo -create "${work_dir}/lib-x86_64/${_ssl_src_dir_name}/lib/libcrypto.a" "${work_dir}/lib-arm64/${_ssl_src_dir_name}/lib/libcrypto.a" -output "${_ssl_lib_dir}/lib/libcrypto.a" | |
lipo -create "${work_dir}/lib-x86_64/${_ssl_src_dir_name}/lib/libssl.a" "${work_dir}/lib-arm64/${_ssl_src_dir_name}/lib/libssl.a" -output "${_ssl_lib_dir}/lib/libssl.a" | |
fi | |
fi | |
if ! [[ -d ${_lt_lib_dir} ]] | |
then | |
rm -rf ${_lt_tmp_dir} | |
${cmake} -S ${_lt_src_dir} -B ${_lt_tmp_dir} -D CMAKE_VERBOSE_MAKEFILE=ON -D CMAKE_PREFIX_PATH="${_boost_src_dir};${_ssl_lib_dir}" -D CMAKE_CXX_STANDARD=14 -D CMAKE_CXX_EXTENSIONS=OFF -D CMAKE_OSX_DEPLOYMENT_TARGET=${min_macos_ver} -D CMAKE_OSX_ARCHITECTURES=${target_arch} -D CMAKE_BUILD_TYPE=Release -D BUILD_SHARED_LIBS=OFF -D deprecated-functions=OFF -D CMAKE_INSTALL_PREFIX=${_lt_lib_dir} | |
${cmake} --build ${_lt_tmp_dir} -j$(sysctl -n hw.ncpu) | |
${cmake} --install ${_lt_tmp_dir} | |
fi | |
_qt_arch=${target_arch} | |
# Qt6 supports universal binaries out of the box, and in case of cross-compilation | |
# it is easier to build universal binaries rather than only for target architecture | |
if [[ "${target_arch}" != "$(uname -m)" ]] | |
then | |
_qt_arch="x86_64;arm64" | |
_qt_tmp_dir="${work_dir}/build-${universal_arch_tag}/${_qt_src_dir_name}" | |
_qt_lib_dir="${work_dir}/lib-${universal_arch_tag}/${_qt_src_dir_name}" | |
fi | |
if ! [[ -d ${_qt_lib_dir} ]] | |
then | |
rm -rf ${_qt_tmp_dir} && mkdir -p $_ && cd $_ | |
"${_qt_src_dir}/configure" -prefix ${_qt_lib_dir} -release -static -appstore-compliant -no-pch -no-dbus -no-icu -qt-pcre -system-zlib -ssl -openssl-linked -no-securetransport -no-cups -qt-libpng -qt-libjpeg -no-feature-testlib -no-feature-concurrent -no-feature-androiddeployqt -no-feature-assistant -no-feature-designer -no-feature-pixeltool -- -D CMAKE_VERBOSE_MAKEFILE=ON -D CMAKE_PREFIX_PATH="${_ssl_lib_dir}" -D CMAKE_OSX_ARCHITECTURES=${_qt_arch} | |
${cmake} --build . --parallel | |
${cmake} --install . | |
cd - | |
fi | |
# build qBittorrent each time script launched | |
rm -rf ${_qbt_tmp_dir} | |
${cmake} -S ${_qbt_src_dir} -B ${_qbt_tmp_dir} -D CMAKE_VERBOSE_MAKEFILE=ON -D CMAKE_PREFIX_PATH="${_boost_src_dir};${_ssl_lib_dir};${_lt_lib_dir};${_qt_lib_dir}" -D CMAKE_OSX_DEPLOYMENT_TARGET=${min_macos_ver} -D CMAKE_OSX_ARCHITECTURES=${target_arch} -D CMAKE_BUILD_TYPE=Release -D QT6=ON | |
${cmake} --build ${_qbt_tmp_dir} -j$(sysctl -n hw.ncpu) | |
# build result .dmg image containing qBittorrent | |
pushd ${_qbt_tmp_dir} > /dev/null | |
mv qbittorrent.app qBittorrent.app | |
codesign --deep --force --verify --verbose --sign "-" qBittorrent.app | |
hdiutil create -srcfolder qBittorrent.app -nospotlight -layout NONE -fs HFS+ -format ULFO -ov ${_qbt_dmg_path} | |
popd > /dev/null | |
# only automatically created directory will be removed | |
[[ $_remove_work_dir -eq 0 ]] || rm -rf ${work_dir} |
Versioning is inefficient. If, for example, you want to upgrade qt (with a cached working directory), you would still have to download 700mb, instead of a simple checkout. Should I try to improve the script?
script was initially designed to work with "snapshots" (aka archives), but Qt unfortunately is an exception where I download whole repository. you are right, it can be improved using git pull
+ git checkout
, feel free to do that for your purpose, I don't maintain this script anymore as so as don't have personal Apple devices (but have 2 MacBooks from work).
Infact, I don't see why homebrew isn't used, as it would be much more efficient to use precompiled dependencies.
this is the main feature of this script. Homebrew is good when you need some command line tools only for usage on your particular machine, and it is completely unacceptable when you want to build something for distribution (especially GUI apps). in my opinion, Homebrew is evil and even the thing that should not exist. you can use it, but there is nothing to do with this script, just build qBittorrent as for Linux (the wrong way in case of macOS, but it will work definitely, but only for your particular machine).
this was the only script I could find. The official build guides didn't cut it.
yes, this script is unique, and only the one guide (which is appeared based on this script) was written by me more than year ago and now slightly outdated (because it covers Qt 5, not Qt 6) and with Qt 6 everything became more simpler - just build everything using CMake (except OpenSSL, damn it!).
I had no plans to update this guide because it is more valuable now due to unique information about how to build Qt 5 for Apple M1 (what was considered impossible). even more, it seems that qBittorrent guys disabled/restricted Wiki editing by everyone, so for now it is even impossible for me.
so, as I mentioned above, you can use Homebrew if you liked it and happy with achieved results and just follow any guide for Linux.
I see now how homebrew will not work for anything which is not your architecture; it didn't cross my mind, because I was aiming to use it locally.
I think I will spend a little time refactoring this script tomorrow to implement git checkout and the other things I talked about – the build times should be much faster.
I made a fork with improvements.
Git clones are partial (saves ALOT of disk/network, especially when cloning qt, and qbittorrent to some degree), build cache is not (that is never) cleaned every time, more dependencies automatically point to the latest version (but still stable), git is used everywhere to allow easy editing, and the script never overwrites any sources, and zsh is not required any more. There are some other small changes which would take forever to list. The diff should still be somewhat readable.
I strongly recommend to use my fork if building with qt6.
(Funny story: I have not tested universal or cross compilation because I find the noise my laptop makes when compiling qt terrifying. That noise is also why I have strove to use build caching to the maximum.)
Thank you.
That new script is working but I want to use older qBittorrent which I think is only supporting QT5.
I used older script and seeing errors:
15 warnings generated. make[4]: *** [sub-cocoa-make_first] Error 2 make[3]: *** [sub-platforms-make_first] Error 2 make[3]: *** Waiting for unfinished jobs.... rm -f /Users/alecrobertson/Desktop/qbt/build-arm64/qt-5.15.2/qtbase/plugins/sqldrivers/libqsqlite.a /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar cq -S /Users/alecrobertson/Desktop/qbt/build-arm64/qt-5.15.2/qtbase/plugins/sqldrivers/libqsqlite.a .obj/qsql_sqlite.o .obj/smain.o .obj/sqlite3.o .obj/moc_qsql_sqlite_p.o /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib -s -no_warning_for_no_symbols /Users/alecrobertson/Desktop/qbt/build-arm64/qt-5.15.2/qtbase/plugins/sqldrivers/libqsqlite.a make[2]: *** [sub-plugins-make_first] Error 2 make[1]: *** [sub-src-make_first] Error 2 make: *** [module-qtbase-make_first] Error 2
That is because Qt 5.15.2 cannot be built with Xcode 13.
You need to use a small patch to avoid this and you need to apply it after you initialized the Qt repository in the script.
You can also look up my fork of this script which contains the necessary patching for Qt 5.
I'm using this fork to build qBittorent stable versions for myself, since Qt 6 versions are unusable until the next qBittorrent release.
Also a tip: you maybe want to use Qt 5.15.5-lts-lgpl
(newest open source Qt 5), since 5.15.3+ versions resolved a lot of small UI glitches, like the About menu's tabs. By the way, the script in both cases attempting to build whatever is currently on the master
branch instead of the latest stable by default, so you probably want to set some parameters for the stable version builds.
For example:
./build_qbt_dmg.sh --qbittorrent=release-4.4.3.1 --openssl=1.1.1q --libtorrent=2.0.7 --qt=5.15.5-lts-lgpl --cmake=3.24.0 --boost=1.79.0
P.S.: libtorrent_commit
parameter in my script is an optional one, and what it does is conform qBittorrent's weirdness about using specific libtorrent commits for stable releases. It'll overwrite whatever you write in libtorrent version, and if you want to use stable libtorrent releases, just leave it empty and do not define it.
Does someone have a link to the latest dmg for arm64?
Does someone have a link to the latest dmg for arm64?
On the official website all download links are 'universal' builds nowadays, which includes both x86_64 and arm64 in one app.
Works beautifully on Apple M2, MacOS Sonoma 14.5. Installed Xcode 15.4 and set following to compile a bleeding edge version of qBittorrent:
qbittorrent_ver=master
openssl_ver=3.3.1
boost_ver=1.85.0
libtorrent_ver=2.0.10
qt_ver=6.7.2
cmake_ver=3.29.6
Thank you so much @Kolcha
Working on Apple Intel, Sonoma 14.5, Xcode 15.4
qbittorrent_ver=release-4.6.5
openssl_ver=3.3.0
boost_ver=1.85.0
libtorrent_ver=2.0.10
qt_ver=6.7.2
cmake_ver=3.29.2
🥹 I have been waiting for the autoscroll feature to be fixed for two years.... Qt version 6.7.2 fixes it and your script allowed me to build it. Thanks @Kolcha
Versioning is inefficient. If, for example, you want to upgrade qt (with a cached working directory), you would still have to download 700mb, instead of a simple checkout. Should I try to improve the script?
In fact, I don't see why homebrew isn't used, as it would be much more efficient to use precompiled dependencies.
I know it depends on what the user wants, but this was the only script I could find. The official build guides didn't cut it.
edit: I can't even work around by editing the folders (eg pulling in changes from remote) because it is overwritten. That should also preferablly require changing the folder names to the project name (versionless) and referring to versions as branches (where applicable).
edit2: I worked around it by removing all sections with curl or git (only do this after downloading the dependencies for the first time). Works fine, I can play around with the code and build it. The build process is still suprisingly long, for changing only one file; I may have missed some other optimization. (see nest edit.)
edit3: Perfect workaround found. If you are editting a file, without creating new ones, then cmake does not have to generate a new makefile. Make can be run from the build directory. (I have not tested it, but I don't think it is worth cleaning the build directory every time the script is run. That is why it takes so long each time.) (I have tested it, it works as expected. However I think its likely old headers etc. remain; can be manually cleaned to fix.)