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