Skip to content

Installed package exports no include directory: GNUInstallDirs is included after it is used #18

Description

@petlenz

numsim-core::numsim-core installs without an include directory, so a consumer of the installed package can find it but cannot compile against it.

Symptom

Installing numsim-core and building anything that includes its headers:

fatal error: numsim-core/property_graph/property_traits.h: No such file or directory

The generated numsim-coreTargets.cmake carries no include path at all:

set_target_properties(numsim-core::numsim-core PROPERTIES
  INTERFACE_COMPILE_FEATURES "cxx_std_23"
)

The headers are installed — <prefix>/include/numsim-core/... is fully populated. Only the exported target's INTERFACE_INCLUDE_DIRECTORIES is missing, so nothing tells a consumer where they are.

Cause

CMakeLists.txt uses CMAKE_INSTALL_INCLUDEDIR at line 63:

target_include_directories(${PROJECT_NAME}
    INTERFACE
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)

but include(GNUInstallDirs) — which is what defines that variable — is at line 81, eighteen lines later.

${...} is expanded when the line is read, not when the generator expression is evaluated. At line 63 the variable is still empty, so the expression becomes $<INSTALL_INTERFACE:> and contributes nothing. The install(FILES ... DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/...) call at line 93 is after the include, which is why the headers land correctly and only the export is wrong.

Nothing warns: an empty INSTALL_INTERFACE is legal.

Fix

Move include(GNUInstallDirs) above the target_include_directories() call. Verified on a standalone checkout — same source, only the include hoisted:

set_target_properties(numsim-core::numsim-core PROPERTIES
  INTERFACE_COMPILE_FEATURES "cxx_std_23"
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
)

How it surfaced

Found while making the installed numsim-materials package consumable. That package had its own, separate defect — its generated Config re-found none of its dependencies, so find_package() failed outright with numsim-core::numsim-core missing. With that fixed (NumSim-Stack/numsim-materials#10), a consumer configures successfully and then fails to compile, because the numsim-core target it now resolves carries no header path.

So the two are independent: fixing one exposed the other. This is the remaining blocker to consuming an installed numsim-materials.

Worth checking alongside

Neither project's CI runs install or builds a consumer against the result, which is why both defects sat unnoticed while every in-tree build stayed green — in-tree builds use BUILD_INTERFACE, which was always correct. A CI step that installs and compiles a three-line consumer would have caught both.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions