Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the differences between IMPORTED target and INTERFACE libraries?

Tags:

cmake

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.

like image 577
BenjaminB Avatar asked Apr 15 '16 13:04

BenjaminB


People also ask

What is imported target?

IMPORTED targets are used to convert files outside of a CMake project into logical targets inside of the project. IMPORTED targets are created using the IMPORTED option of the add_executable() and add_library() commands. No build files are generated for IMPORTED targets.

What is an interface library?

Definition. The interface library is a partly integration scenario-driven and partly functionally-driven inventory of interfaces that helps to facilitate the communication between two or more communication partners.

What is Interface library in CMake?

Interface Libraries add_library(<name> INTERFACE) Creates an Interface Library. An INTERFACE library target does not compile sources and does not produce a library artifact on disk. However, it may have properties set on it and it may be installed and exported.


2 Answers

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).

like image 197
Angew is no longer proud of SO Avatar answered Oct 22 '22 13:10

Angew is no longer proud of SO


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.

like image 16
Timmmm Avatar answered Oct 22 '22 13:10

Timmmm