How to add a dependency on a compiler plugin

Hi,

I have project which builds a compiler plugin (target plugin) and in another directory try to use the plugin (target simple).
Therefore I need the plugin (which is basically just a shared object) to be compiled and linked before the object files of simple are compiled.

Now I’mhaving some trouble communicating this to CMake:

  1. My first attempt was to add add_dependencies(simple plugin). This doesn’t help at all with Ninja, but does build correctly with UNIX Makefiles.
  2. Then I tried to set the OBJECT_DEPENDS source file property for all source files to plugin. This worked great in Ninja, but failed with “No rule to make target ‘plugin’” with Makefiles. This seems fair since “OBJECT_DEPENDS” is documented to contain full-paths. But I couldn’t figure out how to specify the path to the shared object (since generator expressions don’t work here)

Is there some trick to do this robustly?

1 Like

I don’t think so; CMake generally assumes that the compiler is complete and ready-to-use before the build starts. You might be able to leverage FetchContent to ensure the plugin is built at the right time though. @craig.scott Thoughts?

I don’t think FetchContent will help here. It would still add content to the main build and there’s no need to fetch anything in this scenario, so it wouldn’t be giving you anything different to the regular build situation.

Since CMake 3.9.0, there is an optimisation specific to the Ninja generator where even though simple has plugin as a dependency, sources for simple are allowed to be compiled as long as CMake thinks nothing about the compilation of those sources could depend on plugin. Only linking requires plugin to be fully built. See issue 15555 for more details on the reasoning behind the optimisation.

My recollection is that if there is a custom command on one of the two targets (I don’t recall which one), CMake can’t assume that compilation isn’t dependent on plugin and won’t apply that optimisation.
As a potential workaround for Ninja, in addition to using add_dependencies(), do you get the behavior you want if you add a custom command to one of the two targets? I don’t think it actually matters what that custom command does, so you can potentially test this with something like the following:

add_custom_command(TARGET plugin POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E echo "Do-nothing step"
)

I’m not sure which target it needs to be added to, so you will need to try out both and see which one (if either) works. @ben.boeckel it looks like you wrote that optimisation, perhaps you can clarify the above?

Thanks for looking into this. Sadly adding the add_custom_command(TARGET command didn’t seem to have any effect (beside printing the message of course), no matter if it’s added to simple, plugin or both.

I left out POST_BUILD, not sure if that matters. I think it should be on the plugin target too, not the simple target. I updated my example accordingly.

Another thing to try is to make that custom command produce an output that the simple target depends on. That would be the add_custom_command(OUTPUT somefile ...) form. Or maybe try BYPRODUCTS with my earlier example. I’m shooting in the dark a bit here, I don’t recall the exact condition that blocks the optimisation, but I’m pretty sure it relates to custom commands somehow. I wasn’t able to find the posts about it when I went looking before, sorry.

The change is described in this commit message.

Ah. This is something that we probably can address.

I tested both versions and couldn’t see any difference.

I tried that but it only executed the custom command early, but it still didn’t link the plugin early enough. But I found a variant of your suggestion which did work:
I used add_custom_target(plugin_dummy) and then used add_dependencies to make simple depend on plugin_dummy and plugin_dummy depend on plugin. Now the objects from simpleare compiled after plugin is fully build :blush:

Thanks for all your help!

That would be great too!

In order to not lose it, please file an issue for genex support in OBJECT_DEPENDS.

Done. By the way, it there some way to refer to the location of a object file in a generator expression in a source file attribute of the corresponding source file?

No. First because it requires knowing what target the source file is being compiled for:

add_library(foo_shared SHARED foo.c)
add_library(foo_static STATIC foo.c)
# What is `foo.c`'s "object location? It has two here.

This feature request asks for a $<SOURCE_FILE_PROPERTY> genex that could answer such questions though.