target_link_libraries is adding -l when I don't want it to

Sorry I don’t have a short repro for this, but hopefully I can provide enough information to explain the issue.

I have code like this, using cmake 3.21:

cmake_policy(SET CMP0060 NEW)

add_custom_command(
    OUTPUT
        path/to/meow.so
    COMMAND
        ...
)

add_executable(cat cat.cxx)
target_link_libraries(cat PRIVATE path/to/meow.so)

Note it’s meow.so, not libmeow.so.

When I run ninja cat, it fails, because it’s trying to link -lmeow, which is looking for libmeow.so, which is the wrong name of the shared library. meow.so is built though and is in the right place.

When I then run ninja rebuild_cache && ninja cat, the second time around it does actually link path/to/meow.so and everything works as expected.

I had a lot of trouble understanding what the documentation of CMP0060 means, but I thought it intended this to just work?

Alternatively, if I instead do:

add_library(libmeow SHARED IMPORTED)
set_target_properties(libmeow PROPERTIES IMPORTED_LOCATION path/to/meow.so)
target_link_libraries(cat PRIVATE libmeow)

then this works on the first go.

Why doesn’t the first version just work?

Strange. I suspect some of it is that sources are where (IIRC) custom command dependencies are looked up, not link libraries. What you should be able to do is something like this though:

add_custom_command(OUTPUT path/to/meow.so)
add_custom_target(meow)
add_dependencies(meow DEPENDS path/to/meow.so)
add_library(meow::meow SHARED IMPORTED)
add_dependencies(meow::meow meow)

That said, this behavior probably has to do with meow.so existing between the first and second configures.

1 Like

Sorry I don’t follow.

The issue is that instead of just passing path/to/meow.so on the command-line, cmake transforms this into -Lpath/to -lmeow the first time around (which is an invalid transformation because that’s the wrong name).

The second time around (or with the altered form using the IMPORTED_LOCATION), it does correctly just pass path/to/meow.so.

It seems like between CMP0003 and CMP0060, cmake should respect the code I’m actually writing, but that appears to not be the case, and I don’t understand between the description of either of the two policies what the actual behavior is supposed to be.

Yes, this sounds like a bug of some sort. Does what I posted above work (as it is the intended workflow today AFAIK)? We should still look into the issue, but I think it can just be avoided here.