Here is a quick how-to if you want to try out the new (supposedly fast) C/C++ linker https://github.com/rui314/mold
In this document I used Ubuntu-22.04 docker container with
- GCC version 11.2.0
- Clang version 14.0.0
You have three options:
- a) Install
mold
from a package repository (apt install mold
). Note: typically repository versions are pretty old compared to upstream releases. At the time of this writing (2022-07-03) Ubuntu repo provides v1.0.3, while newest Github release is v1.3.1. - b) Download, extract and install a release from Github
- c) Clone the repo and build/install from source. Note: you need a relatively new compiler with C++20 support.
Pick whatever option you are most comfortable with. Just make sure the mold
executable is in your path:
$ mold --version
mold 1.3.1 (71c4c9092271312bcc05724c8ca707487c31bab1; compatible with GNU ld)
You are now ready to configure your own project to use the new linker
In short: to enable mold
for linking, you specify a custom linker via compiler flag -fuse-ld
. The flag is supported by both Clang and GCC (at least with the versions mentioned in the intro).
Note that when I say "compiler flag", it is actually needed during the link step only. It just so happens that the modern GCC/Clang toolchains perform linking by invoking the compiler (as a wrapper), instead of calling the linker directly.
Anyways, to enable mold
as a linker, add the following to your CMake configuration command:
-DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold"
For example:
$ cmake \
-B mybuild \
-G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" \
-DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" \
~/path/to/myproject
The first option applies when linking executables, the latter when linking shared libraries. You may omit either one to suit your needs.
(Next you might ask why is there no variable for specifying -fuse-ld=mold
for static libraries?? Well, the answer is that when static libraries are being built, there is no actual link step; the resulting .a
libraries are just archives of loosely related compiled object files (.o
). The actual linking happens at a later stage, possibly outside of your project.)
Next I will verify that the linker is actually used:
In the above demo project I have the following targets defined in CMakeLists.txt
:
...
add_executable(helloworld-exe helloworld.cc)
add_library(myshared SHARED myshared.cc)
...
Now I build the project the usual way:
$ cmake --build mybuild --verbose --target helloworld-exe --target myshared
[1/4] /usr/bin/clang++ -Dmyshared_EXPORTS -fPIC -MD -MT CMakeFiles/myshared.dir/myshared.cc.o -MF CMakeFiles/myshared.dir/myshared.cc.o.d -o CMakeFiles/myshared.dir/myshared.cc.o -c myshared.cc
[2/4] /usr/bin/clang++ -MD -MT CMakeFiles/helloworld-exe.dir/helloworld.cc.o -MF CMakeFiles/helloworld-exe.dir/helloworld.cc.o.d -o CMakeFiles/helloworld-exe.dir/helloworld.cc.o -c helloworld.cc
[3/4] : && /usr/bin/clang++ -fuse-ld=mold CMakeFiles/helloworld-exe.dir/helloworld.cc.o -o helloworld-exe && :
[4/4] : && /usr/bin/clang++ -fPIC -fuse-ld=mold -shared -Wl,-soname,libmyshared.so -o libmyshared.so CMakeFiles/myshared.dir/myshared.cc.o && :
..and we notice the -fuse-ld=mold
being passed to the compiler, but only for the (final) link step in both cases.
I can also verify that mold
is being used by inspecting the comment section, for example in helloworld-exe
:
$ readelf -p .comment mybuild/bin/helloworld-exe
String dump of section '.comment':
[ 0] GCC: (Ubuntu 11.2.0-19ubuntu1) 11.2.0
[ 26] mold 1.3.1 (71c4c9092271312bcc05724c8ca707487c31bab1; compatible with GNU ld)
[ 75] Ubuntu clang version 14.0.0-1ubuntu1
-
Since the flag
-fuse-ld
is compiler-specific, you really should not hard-code it in yourCMakeLists.txt
files. And only pass it on the command line if you know that your compiler supports it. Non-Clang/GCC compilers may have similar flag, but but the principle (and CMake variables used) should remain the same. -
Don't put something like
add_link_options(-fuse-ld=mold)
in yourCMakeLists.txt
file. You wouldn't hardcode a compiler this way, would you? This kind of information is passed from outside of the project during configuration stage - your project should remain compiler and linker agnostic as much as possible (or at least you should not assume a specific compiler or linker is used). -
Don't attempt to pass the flag via
CMAKE_CXX_FLAGS
or similar. It will result in annoying warnings during compilation since the flag is not actually needed/used during compilation, but only during linking. -
Avoid Setting
CMAKE_CXX_LINK_FLAGS
orCMAKE_C_LINK_FLAGS
. They work, but will only apply for linking C/C++ executables, not shared libraries. -
CMake supports other languages besides C and C++. Using
CMAKE_EXE_LINKER_FLAGS
andCMAKE_SHARED_LINKER_FLAGS
allows you to specify the linker for all targets regardless of language. Although this may cause problems in a mixed language project where not all tools understand the same flag(s). But if you are utilizing only GNU-ish compiler ecosystems (GCC, Clang, GNU Fortran, ...) you can safely pass-fuse-ld
to all of them viaCMAKE_EXE_LINKER_FLAGS
/CMAKE_SHARED_LINKER_FLAGS
variables alone. -
Don't attempt to use
CMAKE_LINKER
. Some online forums may recommend you to setCMAKE_LINKER=/path/to/mold
. However, it is (presumably) some kind of legacy variable and is not supported anymore. In my experiments the variable stopped working during transition from CMake version 3.18 -> 3.22. So, just forget it altogether. -
You may have came across this Stackoverflow question where the top answer recommends changing
CMAKE_CXX_LINK_EXECUTABLE
. However, this is rather heavy-handed (and error prone) way of accomplishing the intended effect. And again, it applies to executables only. Don't do this. See CMake source code to get an idea what the change would do. -
Also, don't attempt to set
-DCMAKE_CXX_LINK_EXECUTABLE=/path/to/mold
- it does not work the way you expect it to. See, CMake source code to get an idea what the variable should contain. -
If you are using VScode, put the option(s) in your settings.json for simplified usage:
"cmake.configureSettings": { ... "CMAKE_C_COMPILER": "clang", "CMAKE_CXX_COMPILER": "clang++", "CMAKE_EXE_LINKER_FLAGS": "-fuse-ld=mold", "CMAKE_SHARED_LINKER_FLAGS": "-fuse-ld=mold" ... }
and then reconfigure your project via the command palette.
This document was written by Markus H (MawKKe).
Feel free to give feedback/improvement suggestions at https://gist.github.com/MawKKe/b8af6c1555f1c7aa4c2760350ed97fff
See also https://github.com/MawKKe and https://gist.github.com/MawKKe for other interesting stuff.
Please note that I am not the author of mold
. I'm just a friendly neighbourhood C++ programmer.
It is now even easier with CMake 3.29.0. Just set the according variable, https://cmake.org/cmake/help/latest/variable/CMAKE_LINKER_TYPE.html.