PRIVATE-becomes-PUBLIC behaviour for static libraries

Hi there,

AFAIK the following code:

target_link_libraries(dcmimage PRIVATE ${PNG_LIBRARIES})

imply that the PNG libraries will be added on the link line when linking against dcmimage. As such it is a expected behavior to have:

> cat cmake\DCMTKTargets.cmake
[...]
# Create imported target DCMTK::dcmimage
add_library(DCMTK::dcmimage STATIC IMPORTED)

set_target_properties(DCMTK::dcmimage PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
  INTERFACE_LINK_LIBRARIES "\$<LINK_ONLY:DCMTK::oflog>;\$<LINK_ONLY:DCMTK::dcmdata>;\$<LINK_ONLY:DCMTK::dcmimgle>;\$<\$<NOT:\$<CONFIG:DEBUG>>:C:/builds/acme-clinical/dicom/dcmtk/obj/vcpkg_installed/x64-windows-static/lib/libpng16.lib>;\$<\$<CONFIG:DEBUG>:C:/builds/acme-clinical/dicom/dcmtk/obj/vcpkg_installed/x64-windows-static/debug/lib/libpng16d.lib>"
)

My issue is that those full paths are messing up my third party project linking against DCMTK, since the file C:/builds/acme-clinical/dicom/dcmtk/obj/vcpkg_installed/x64-windows-static/lib/libpng16.lib is part of one gitlab project while I am building from another one ?

What should I be using here instead (Is there a REALLY_PRIVATE keyword for target_link_libraries…) ?

Thanks for suggestion

those full paths

It is strange that you get full absolute paths there. I also use vcpkg for resolving 3rd-party dependencies in my projects, and I also link to PNG in one of those projects, but what I get is:

set_target_properties(mMap PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
  INTERFACE_LINK_LIBRARIES "\$<LINK_ONLY:someThing>;\$<LINK_ONLY:jpeg-turbo::turbojpeg-static>;\$<LINK_ONLY:draco::draco>;\$<LINK_ONLY:png>;..." # and so on
)

It probably has to do with the way you link to PNG, because I see you are linking to its actual libraries (${PNG_LIBRARIES}) instead of its CMake target.

Is there a REALLY_PRIVATE

As far as I know, there is no such thing, and I probably misunderstood what you are asking here, but it is possible to “hack” this linking out from your library’s exported CMake config with something like this:

# a dirty hack to remove a target from INTERFACE_LINK_LIBRARIES when it isn't actually needed
#
# from CMake 3.27 there is $<COMPILE_ONLY:...>, which should be better way
#
get_target_property(YOUR_PROJECT_INTERFACE_LINK_LIBRARIES ${PROJECT_NAME} INTERFACE_LINK_LIBRARIES)
if(NOT "${YOUR_PROJECT_INTERFACE_LINK_LIBRARIES}" STREQUAL "YOUR_PROJECT_INTERFACE_LINK_LIBRARIES-NOTFOUND")
    list(REMOVE_ITEM YOUR_PROJECT_INTERFACE_LINK_LIBRARIES [=[$<LINK_ONLY:TARGET_YOU_WANT_TO_REMOVE>]=])
    set_target_properties(YOUR_PROJECT
        PROPERTIES
            INTERFACE_LINK_LIBRARIES "${YOUR_PROJECT_INTERFACE_LINK_LIBRARIES}"
    )
endif()

but then in consuming project you will for sure encounter linking problems, as PNG symbols will be missing at the “final” linking.

Either way, hopefully you won’t need to go this way, as your problem is likely because of linking “directly” to the libraries instead of the target.

Indeed ! If I change the following line (*):

DCMTK_TARGET_LINK_LIBRARIES(dcmimage ${LIBTIFF_LIBS} ${LIBPNG_LIBS})

into:

DCMTK_TARGET_LINK_LIBRARIES(dcmimage ${LIBTIFF_LIBS} PNG::PNG)

then everything works as expected (private remains private). thanks for the trick.

Just for my own curiosity where did you see it documented ? This change in behavior does not seems obvious from:

Thanks

(*) git.dcmtk.org Git - dcmtk.git/blob - dcmimage/libsrc/CMakeLists.txt

where did you see it documented

That isn’t something specific to the PNG’s Find* module, it is how target_link_libraries() works in general - there is an explanation there about what one can link to (targets versus libraries).

This is incorrect. PNG::PNG will be properly propagated (PRIVATE-becomes-PUBLIC), but the major change is that the full path is not hard-coded anymore. I can build yet another vcpkg/PNG in my third party application (same exact ABI) and then my original symptoms are now solved.

One last thing for whoever will read this.

After the above change, the following will fails:

find_package(DCMTK)
add_library(foobar DCMTK::dcmimage)

The error will read something like:

-- Configuring done
CMake Error at CMakeLists.txt:2 (add_library):
  Target "foobar" links to target "PNG::PNG" but the target was not found.
  Perhaps a find_package() call is missing for an IMPORTED target, or an
  ALIAS target is missing?
-- Generating done

Pay attention that will be required to add the missing find_package not before the add_library call, but before the actual find_package(DCMTK).

Hopefully useful for someone else.

That’s hardly any news :slight_smile:
This is just how CMake packages/configs work by design: either project maintainer takes care of this in the package config with find_dependency(), or his users will have to add find_package() in their projects.