Control what is installed / packaged

Hello,

I’ve writtem some install logic and cpack logic for my application. It generally works, but it literally installs everything.

I use FetchContent whenever possible so all my dependencies are subdirectories. If I install my application everything from these dependencies will get installed as well including documentation, header files, cmake scripts and other stuff.

How can I just install my application and everything that is necessary for it from the dependencies. But exclude all not needed things like header files or documentation?

Thanks!

The subprojects would need to offer options for you to disable their install rules or, if it works, you can use install components to install just what you need. I don’t think CMake has a way to say “ignore install rules for this directory”, but maybe some custom install code that calls return () before all of the subdirectories run could work?

2 Likes

Hmm my own install target has a component, so I could just install that target. But then shared libraries are missing for instance.

I though maybe using “RUNTIME_DEPENDENCIES” would help with this, but for some reasons it doesn’t.

install(TARGETS BeansApp COMPONENT Beans 
  RUNTIME_DEPENDENCIES
    PRE_EXCLUDE_REGEXES "api-ms-" "ext-ms-"
    POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
    DIRECTORIES $<TARGET_FILE_DIR:Qt6::Core>
    FRAMEWORK DESTINATION Beans.app/Contents/Frameworks
)

Shouldn’t this be able to find my shared dependencies? Or at least try to find them. It searches for Qt6 and also installs that sucessfully, but it doesn’t search for all linked libraries, which came via FetchContent. At least they are not installed neither is there an error message.

Directory based Ignoring, no matter if build in or manual, would probably not helper either. The libraries often have all their install stuff in one directory. And they also don’t use Components.

I suppose the best way would be if they all use Components, but it would be insane to open Pull Requests for all the dependencies. Furthermore the Component name is free to choose, so even if they all specify components, it would be quite some work to figure out what components are needed exactly.

Couldn’t cmake provide an option to automatically install shared target dependencies. So for example look for all shared targets and then only execute install(target …) commands found for these targets and ignore everything else?

Actually I had a look again at runtime dependencies and the issue seems to be the RUNTIME_DEPENDENCIES of install. The manual approach works:

install(CODE [[
  file(GET_RUNTIME_DEPENDENCIES
    LIBRARIES "$<TARGET_FILE:BeansApp>"
    RESOLVED_DEPENDENCIES_VAR _r_deps
    UNRESOLVED_DEPENDENCIES_VAR _u_deps
    DIRECTORIES "$<TARGET_FILE_DIR:Qt6::Core>"
    PRE_EXCLUDE_REGEXES "api-ms-" "ext-ms-"
    POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
  )
  foreach(_file ${_r_deps})
    file(INSTALL
      DESTINATION "${CMAKE_INSTALL_PREFIX}/bin"
      TYPE SHARED_LIBRARY
      FILES "${_file}"
    )
  endforeach()
  list(LENGTH _u_deps _u_length)
  if("${_u_length}" GREATER 0)
    message(WARNING "Unresolved dependencies detected!")
  endif()
]] COMPONENT Beans)

Here is a small test with a comparison:

As can be seen the install commands puts the third party library I tested here in a “POST_EXCLUDE_FILES_STRICT”. Is this intentional?

I would guess that it is skipping recursive scanning to avoid double installation. You could add your own install rules for targets in the subdirectories so that you can bypass whatever other rules are there.