Messing around with linkers & CMake
Tijl Coosemans
tijl at FreeBSD.org
Wed Apr 19 18:39:12 UTC 2017
On Wed, 19 Apr 2017 20:06:06 +0200 Adriaan de Groot <groot at kde.org> wrote:
> 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),
Adding -B${LOCALBASE}/bin to LDFLAGS should do the trick. It's used in
a few places in the ports tree.
> - 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".
More information about the kde-freebsd
mailing list