28

As I understand it INTERFACE libraries are like Visual Studio property sheets, so very useful. We can use it to link with static libs and propagate properties.

But IMPORTED targets bother me : I can't see a problem which can be solved with IMPORTED target only.

BenjaminB
  • 1,809
  • 3
  • 18
  • 32
  • 2
    @Antonio What does this question have to do with Visual Studio to be tagged as such? – Angew is no longer proud of SO Apr 15 '16 at 14:00
  • @Angew It refers to Visual Studio property sheets, of which I know nothing. Although I know about CMake, I cannot fully grasp this question. Said in other words, to fully answer this question knowledge about Visual Studio is also necessary. – Antonio Apr 15 '16 at 14:56

2 Answers2

30

When you create an imported target, you're telling CMake: I have this { static library | shared library | module library | executable } already built in this location on disk. I want to be able to treat it just like a target built by my own buildsystem, so take note that when I say ImportedTargetName, it should refer to that binary on disk (with the associated import lib if applicable, and so on).

When you create an interface library, you're telling CMake: I have this set of properties (include directories etc.) which clients can use, so if they "link" to my interface library, please propagate these properties to them.

The fundamental difference is that interface libraries are not backed by anything on disk, they're just a set of requirements/properties. You can set the INTERFACE_LINK_LIBRARIES property on an interface library if you really want to, but that's not really what they were designed for. They're to encapsulate client-consumable properties, and make sense primarily for things like header-only libraries in C++.

Also notice that an interface library is a library—there's no such thing as an interface executable, but you can indeed have imported executables. E.g. a package config file for Bison could define an imported target for the Bison executable, and your project could then use it for custom commands:

# In Bison package config file:
add_executable(Bison IMPORTED)
set_property(TARGET Bison PROPERTY IMPORTED_LOCATION ...)

# In your project:
find_package(Bison)
add_custom_command(
  OUTPUT parser.c
  COMMAND Bison tab.y -o parser.c
  DEPENDS tab.y
  ...
)

(Bison is used just as an example of something you might want to use in custom commands, and the command line is probably not right for it).

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • This is a very nice explanation. Why is the cmake documentation so lacking when it comes to explanations like this? – natersoz Jun 25 '21 at 12:58
19

It seems like there is a lot of overlap. Say you have a shared library and headers on disk and you want to make it available so that bits of your CMake can do this

target_link_libraries(my_target foo)

and automatically link with it and get the necessary include directories.

You can do it either like this:

find_package(Foo)

add_library(foo SHARED IMPORTED)
set_target_properties(foo PROPERTIES
    IMPORTED_LOCATION ${FOO_LIBRARIES} # The DLL, .so or .dylib
    INTERFACE_INCLUDE_DIRECTORIES ${FOO_INCLUDE_DIR}
    INTERFACE_COMPILE_DEFINITIONS "ENABLE_FOO"
)

Or like this:

add_library(foo INTERFACE)
target_link_libraries(foo INTERFACE ${FOO_LIBRARIES})
target_include_directories(foo INTERFACE ${FOO_INCLUDE_DIR})
target_compile_definitions(foo INTERFACE "-DENABLE_FOO")

They both work and behave identically as far as I can tell. There is even an 'imported interface library' available via add_library(foo INTERFACE IMPORTED) though that didn't seem to work and I have no idea what it is for.

Frankly the docs don't really explain which you should use for libraries, and I'm afraid I don't find Angew's "that's not really what they were designed for" very compelling.

I guess use either. I think the interface library is easier to understand and more consistent with the use of INTERFACE properties from internal libraries.

Timmmm
  • 88,195
  • 71
  • 364
  • 509
  • `INTERFACE IMPORTED` is, for example, for if you're wrapping your OS's packaged Perl library into a target with `add_library`, so that your targets can link against it. You want an ephemeral target that causes certain definitions, includes, and link args to attach, and you want to indicate that it has no build rules of its own. – alexchandel Jul 25 '23 at 21:27
  • Also, you should use the functions like [`target_link_libraries()`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html#command:target_link_libraries) rather than directly writing variables. Otherwise your code will break when CMake's internals change. – alexchandel Jul 25 '23 at 21:29