Adding link libraries at build time

Hi,

I’m currently maintaining Corrosion which integrates Rusts cargo build system into CMake.
When linking Rust static libraries into C/C++ code (managed by CMake), we also need to link some system libraries (e.g. pthread). Currently, the required libraries are hardcoded in corrosion, based on what is usually required for the target OS. Ideally though, we would like to ask rustc which libraries we need to link. rustc provides an option --print native-static-libs which prints a list of required libraries.

This list is produced during the actual build of the static library. Using a dummy demo project to get a list of libraries is also not sufficient in all cases, since rustc will actually take all dependencies into consideration and any #[link] attributes in the source code, which may specify libraries to link against. Build-scripts may also add additional libraries to the list of libraries that should be linked.

Is there any way that we could respect this list of required libraries, generated at build-time, and add them to the target CMake C/C++ executable via target_link_libraries()? From my understanding currently there is no way to do this in CMake, unless we would prebuild the Rust project at configure time.

One way you could do this is to add a link option of @rspfile. You probably want to do this as an INTERFACE on the Rust target and write it via some POST_LINK custom command on that target. Or add it to the custom command chain if it is already a chain of custom commands.

Note that because of the build-time discovery, libraries will be duplicated on the command line because sorting and filtering the link line requires generator-time knowledge which has been thrown away by then.

One way you could do this is to add a link option of @rspfile

Thanks, that sounds useful! Is this @rspfile a Windows / MSVC specific linker option? I looked at the documentation for ld and couldn’t find anything which would allow me to load arguments from a file.

CMake uses the compiler frontend, so you actually want gcc and/or clang docs and they support response files. ar supports response files though according to its manpage.

It’s been a while, but I’d like to revive this topic. I’ve been experimenting with response files, but I just can’t get it to work. I’m currently using something that boils down to

target_link_options(${target_name}-static INTERFACE "@$<SHELL_PATH:${rsp_file}>" "LINKER:--verbose")

When I do this, the linker (ld) complains that it can’t find basic libraries like libc.

Excerpt:

attempt to open /usr/lib/x86_64-linux-gnu/libc.so failed
attempt to open /usr/lib/x86_64-linux-gnu/libc.a failed
...
attempt to open /usr/x86_64-linux-gnu/lib64/libc.so failed
attempt to open /usr/x86_64-linux-gnu/lib64/libc.a failed
attempt to open /usr/x86_64-linux-gnu/lib/libc.so failed
attempt to open /usr/x86_64-linux-gnu/lib/libc.a failed
/usr/bin/ld: cannot find -lc: No such file or directory

an ls -l on the same github action, does tell me that the files in question exist:

-rw-r--r-- 1 root root     283 Jan  2 13:22 /usr/lib/x86_64-linux-gnu/libc.so
-rw-r--r-- 1 root root     283 Jan  2 13:22 /usr/lib/x86_64-linux-gnu/libc.so

I’m wondering if this might have anything to do with me using target_link_options() instead of target_link_libraries()? I tried the latter, but it seems I cannot pass any @ response file to target_link_libraries().

What is in the rsp_file? Does the linker behave the same if you provide the flags on the command line directly (manually)?

Thanks a lot - Your comment prompted me to try hardcoding the values. Everything works fine when hardcoding the options via target_link_options and also when hardcoding the contents of the response file. Since I was essentially printf debugging before, it turns out the rsp file contained an ansi escape sequence before the end of the line, which was not visible when printing the contents via CMake.

Adding --color=never to the rustc invocation fixes my problem, although probably I could also try to improve my regex to handle the ansi escape sequence.

Now my only remaining question is:
Is there any way to also get this working for MSVC?
Judging by this MSVC documentation I’m suspecting it is currently not possible to add a compiler response file via CMake - at least it seems that cmake adds link options to the vcxproject file, while msvc only accepts response files “at the command line” (whatever that means in relation with CMake).

I have no idea how to make Visual Studio do it if target_link_options(tgt PRIVATE @rsp) doesn’t work. The Ninja generators execute “at the command line”. MSBuild (inside of VS) does too, but is mediated through the .vc*proj files.