Using PUBLIC FILE_SET HEADERS with dependent targets

Hey folks, I’m in a bit of bind trying to understand target_sources(<name> PUBLIC FILE_SET HEADERS ... and how a target dependent on a library that uses this works.

Here’s my situation, setup, and issue.
I’ve got a third party library which we’ve introduced CMake to and has a directory structure as follows:

  • library/
    • CMakeLists.txt - has the following:
      add_library(...) and target_sources(library PUBLIC FILE_SET HEADER BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
    • inc/
      • CMakeLists.txt (includes a bunch of subdirectories)
      • Framework
        • Framework.hpp
        • Framework.cpp
        • CMakeLists.txt - has the following:
          target_sources(library PUBLIC FILE_SET HEADERS FILES ${HXX_FILES} PRIVATE ${OUT_CXX_FILES})
          target_include_directories(${MAX_LIB_TARGET} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
      • Utility/
        • CMakeLists.txt - has a similar layout to Framework with source files, but also has subdirectories which follow the same structure
        • Math/
          • CMakeLists.txt - …

So, this library builds correctly, and it installs properly into the /usr/local/... directories.
Now, the application that depends on this library uses CPM for a couple reasons, but one of them is that if the version cannot be found locally then CPM is a nice wrapper to go pull the correct one.
As it stands, if the available version is locally installed, then the application builds and links correctly.

However, if I try to use an upstream version, or local source, I end up with issues where the application cannot find the header files. In fact, the path to the header files is not even on the command line for gcc (neither -I or -isystem).
Here is what the application looks like

  • app/
    • CMakeLists.txt
      add_executable(app app.cpp)
      target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
      target_link_libraries(app PRIVATE library)

That’s it. There’s not a whole lot else.
Can someone help me determine if what I’m trying to do is possible with CMake. I believe it is, but I’m lost in terms of setting up the CMakeLists.txt correctly.

Cheers

Just bumping to see if anyone has feedback or ideas on this?

Can you print out the include directory properties of your library like so, in app/CMakeLists.txt:

cmake_print_properties(TARGETS library  PROPERTIES
                       INTERFACE_INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES)

That may give you an idea

This does not give the right path to consumers. Since you are using FILE_SET HEADERS, I think you just want to set BASE_DIRS and install the FILE_SET. That will set up the include directory usage requirements automatically.

If that doesn’t work, please provide an example that can be executed directly to aid in figuring out what’s up.

You may try it like this snippet:

# ...
# Write spglib_export.h to the current binary directory
include(GenerateExportHeader)
generate_export_header(Spglib_symspg
	EXPORT_FILE_NAME spglib_export.h
	EXPORT_MACRO_NAME API_SPGLIB
)
configure_file(spglib.h spglib.h COPYONLY)

target_sources(Spglib_symspg
	PUBLIC
		FILE_SET HEADERS
		BASE_DIRS ${CMAKE_CURRENT_BINARY_DIR}
		FILES
			${CMAKE_CURRENT_BINARY_DIR}/spglib_export.h
			${CMAKE_CURRENT_BINARY_DIR}/spglib.h
)
target_include_directories(Spglib_symspg
		PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
		PUBLIC
		"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
		"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
# ...

This is what FILE_SET TYPE HEADERS should do automatically (with a PRIVATE fileset for the source tree at least).

1 Like

Yes, it works.