Messing around with linkers & CMake
Adriaan de Groot
groot at kde.org
Wed Apr 19 18:06:06 UTC 2017
On Saturday 15 April 2017 13:36:40 Koop Mast wrote:
> So I was looking into using binutils from ports to build webkitgtk when
> debug is enabled. With the CMAKE_AR and CMAKE_RANLIB variables I can
> set the binutils ar and ranlib. However the problem is that for some
> reason cmake doesn't have a LINKER variable, which results in it using
> ld from base which doesn't understand thin archives. I tried
> CMAKE_LINKER a while back and that didn't seem to work.
The problem is in several stages:
0) I'm going to assume CMake 3.7.1 is being used, and that you have a C-based
library that you are building.
1) First, the standard definitions can be found in
/usr/local/share/cmake/Modules/CMakeCInformation.cmake , and they define so-
called rule-variables, which are rules that are later expanded by the (Makefile
| Ninja | whatever) generator for specific targets. There is a definition in
there for the rule that creates a shared library:
set(CMAKE_C_CREATE_SHARED_LIBRARY
"<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_C_FLAGS>
<LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS>
<SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
That means that it is really going to use the C compiler (e.g. /usr/bin/cc, if
that is what it found), followed by a bunch of flags and thingies.
There *is* a CMAKE_LINKER variable, but it is not used when creating a C-
language shared library, because the rule variable doesn't use it. So what you
could do, is change the rule for creating a C-language shared library:
set(CMAKE_C_CREATE_SHARED_LIBRARY
"<CMAKE_LINKER> <CMAKE_SHARED_LIBRARY_C_FLAGS>
<LANGUAGE_COMPILE_FLAGS> <
LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> <SONAME_FLAG><TARGET_SONAME>
-o
<TARGET> <OBJECTS> <LINK_LIBRARIES>")
See how I have changed the command at the start? Do this somewhere really
early in the top-level CMakeLists.txt; I'm not sure when the variable is
expanded or its value checked. But this does change the rule for *every* C-
language shared library that is built by the project.
2) It's going to take some futzing to massage the command to work with a/the
linker directly. For example, SONAME_FLAG expands to -Wl,-soname, -- but I
don't think you want to change that variable, you want to DTRT in your command
to create C-language shared libraries:
set(CMAKE_C_CREATE_SHARED_LIBRARY
"<CMAKE_LINKER> <CMAKE_SHARED_LIBRARY_C_FLAGS>
<LANGUAGE_COMPILE_FLAGS> <
LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> -soname <TARGET_SONAME> -o
<TARGET> <OBJECTS> <LINK_LIBRARIES>")
Since you're messing around with commands directly, and don't care for
portability to other systems or compilers *anyway*, you may want to plumb in
values more directly (this example probably does not do what you want):
set(CMAKE_C_CREATE_SHARED_LIBRARY
"/usr/lbin/verify_krb5_conf --dumpconfig <TARGET_SONAME>")
3) You can verify what CMake has decided by subsequently building with
VERBOSE=1, but also remember that CMake writes Makefiles (or Ninja, or
whatever) that re-invoke CMake to run some commands; those commands are
usually read from a text file, and you can look at the text file, too.
For instance, if I have this CMakeLists.txt:
project(kwm) # Kannie Wachten op Meson
add_executable(kwm main.c)
add_library(gt SHARED shared.c)
Then the command that ends up in the Makefile (er .. I may mention Ninja a few
times here, but I've only ever tried Make):
/usr/local/bin/cmake -E cmake_link_script CMakeFiles/gt.dir/link.txt --
verbose=1
So to link my C-language shared library called gt, it calls cmake which reads
a file named link.txt (in a subdir obviously named after the shared library
being built). The content of that file is:
/usr/bin/ld -fPIC -shared -soname libgt.so -o libgt.so
CMakeFiles/gt.dir/shared.c.o
(for this example I used the CMAKE_C_CREATE_SHARED_LIBRARY definition from the
middle of section (2), not the useless one at the end). Now you can map-
backwards that line to the variables expanded from the rule variable for
creating C-language shared libraries.
Use that to your advantage while tweaking the rules. What you *could* even do,
is post-configure edit the generated link.txt files if you can't get the effect
you want from within CMake. That would be "here be dragons" territory, though.
4) So coming back to your original question:
> My question is now does cmake have a variable, or another way, that I
> can set so it uses ld from binutils instead of ld from base?
There's three possible ways:
- find a flag to tell the C compiler to use a different linker (e.g. -fuse-ld,
if you can use that to set the linker to the one from binutils),
- tweak the rule command CMake uses to generate the Makefile rule that builds
the shared library, to use the other linker, for instance by replacing the
part of the rule <CMAKE_C_COMPILER> with something else,
- tweak the generated text file for the command, instead.
I'm going to take a look at variable scope for rule-generation later tonight,
so that you might be able to tweak this for single libraries only, so's to
give you more nuanced control.
So the *actual* answer to your question is "yes".
[ade]
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: This is a digitally signed message part.
URL: <http://mail.kde.org/pipermail/kde-freebsd/attachments/20170419/afdb7d84/attachment.sig>
More information about the kde-freebsd
mailing list