CMake FetchContent() build misses vtkCommonDataModelModule.h

I am trying to change my build system to use CMake’s FetchContent(...) method. I specify the git repository and a git tag.

When I start compiling I get the following:

D:\temp\buildme2\vtk-fss_deps\vtkrepo-src\Common\Core../DataModel/vtkDataObject.h(37): fatal error C1083: Cannot open include file: ‘vtkCommonDataModelModule.h’: No such file or directory

The build works fine when I use git submodule with the same git tag.

I assume I am missing a CMake variable which will generate vtkCommonDataModelModule.h during the configuration process. Any ideas which variable that could be?

There’s a missing / in that path:

D:\temp\buildme2\vtk-fss_deps\vtkrepo-src\Common\Core../DataModel/vtkDataObject.h

It seems that vtkCommonDataModel isn’t enabled? That should never happen as both are forced on (in a non-tools-only build).

Good spotting on the missing /. However this may be a separate issue; I get the same error under linux and there it is not missing any forward slashes:

In file included from /home/peter/source/build-volsung-dependencies-Qt_5_15_2_GCC_64bit-Debug/vtk-fss/_deps/vtkrepo-src/Common/Core/vtkInformationDataObjectKey.cxx:18:
/home/peter/source/build-volsung-dependencies-Qt_5_15_2_GCC_64bit-Debug/vtk-fss/_deps/vtkrepo-src/Common/Core/…/DataModel/vtkDataObject.h:37:10: fatal error: vtkCommonDataModelModule.h: No such file or directory

Also after getting this error I explicitly set the CMake variable to force building of vtkCommonDataModule but it made no difference:

set(VTK_MODULE_ENABLE_VTK_CommonDataModel YES CACHE BOOL “override” FORCE)

Further checks: The file vtkCommonDataModelModule.h exists, but it can’t be found when building vtkInformationDataObjectKey.cxx. It is referenced via an include:

#include “vtkCommonDataModelModule.h” // For export macro

So it looks like the file is generated correctly, but the Common/Core module has not set the list of include directories for its dependencies correctly?

The generated file is

<root>/_deps/vtkrepo-build/vtkCommonDataModel/vtkCommonDataModelModule.h

but the include directive for the compiler is

-I<root>/_deps/vtkrepo-build/vtkCommonCore/../DataModel

The relative path set by -I is correct but it is missing the vtkCommon part of it, i.e. correctly it should be

-I<root>/_deps/vtkrepo-build/vtkCommonCore/../vtkCommonDataModel

This is controlled by the CMakeLists.txt file for Common/Core:

# We can't check for the target since we're before VTK::CommonDataModel in the
# dependency graph.
if (VTK_MODULE_ENABLE_VTK_CommonDataModel)
  list(APPEND vtk_include_dirs
    "${CMAKE_CURRENT_BINARY_DIR}/../DataModel")
  set_property(SOURCE vtkInformationDataObjectKey.cxx
    PROPERTY
      COMPILE_DEFINITIONS vtkCommonDataModel_ENABLED)
endif ()

Changing the above line to

"${CMAKE_CURRENT_BINARY_DIR}/../vtkCommonDataModel")

allows the build to succeed.

Is this a bug which needs fixing, or is/was it intentional?

What is making the file in vtkCommonDataModel in the first place? It should be in a DataModel directory.

The filename is defined in <vtk-source>/CMake/vtkModule.cmake:

 set(_vtk_add_module_module_header_name
    "${_vtk_add_module_library_name}Module.h")
  if (NOT _vtk_add_module_HEADER_ONLY AND NOT _vtk_add_module_third_party)
    set(_vtk_add_module_generated_header
      "${CMAKE_CURRENT_BINARY_DIR}/${_vtk_add_module_module_header_name}")
    list(APPEND _vtk_add_module_HEADERS
      "${_vtk_add_module_generated_header}")
  endif ()

The header name is correct, and ${CMAKE_CURRENT_BINARY_DIR} points to vtkCommonDataModel at this point (tested via printing it out).

Why? How are you building VTK that this gets messed up? I’ll note that VTK is not meant to be built by add_subdirectory. If you want to vendor it, vendor it like ParaView does (see its CMakeLists.txt for the nitty-gritty details).

Not sure what I muck up, that’s the question lol

I have a complicated chain of dependencies for my project, and I want to be able to build them automatically all in one go, one after the other. Therefore I am setting them all up as independent CMakeProjects, where each project contains a CMakeLists.txt which defines how the project will be built.

In short my VTK project looks like this:

project(vtk-fss)

FetchContent_Declare(
    vtkrepo
    GIT_REPOSITORY https://gitlab.kitware.com/vtk/vtk.git
    GIT_TAG xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
)

FetchContent_GetProperties(vtkrepo)
if(NOT vtkrepo_POPULATED)
  # Fetch the content using previously declared details
  FetchContent_Populate(vtkrepo)

  set(CMAKE_PROJECT_NAME VTK)

... 

  set(VTK_MODULE_ENABLE_VTK_eigen YES CACHE BOOL "override" FORCE)
  set(VTK_MODULE_ENABLE_VTK_GeovisCore YES CACHE BOOL "override" FORCE)

 ...

  add_subdirectory(${vtkrepo_SOURCE_DIR} ${vtkrepo_BINARY_DIR})
endif()

If you have a better idea on how to automate this step, i.e. building it from scratch from a particular git tag and being able to modify CMake variables please let me know.

The superbuild is a solution, take a look at the one for ParaView: https://gitlab.kitware.com/paraview/paraview-superbuild/

This is what I referred to as “VTK doesn’t support being used through add_subdirectory”. Either vendor like ParaView does or build it separately.

Big sigh.

Thanks guys, I will look into alternative solutions.

It would be great if you add a section to

https://vtk.org/Wiki/VTK/Configure_and_Build

about how to include VTK as a subproject using a minimalistic example.

It wiki needs a deep clean of old crufy information. The build docs now live in the repo. Vendoring is not something that is 100% supported explicitly or in any stable way (global variables expected to exist or files to include change without much notification). ParaView does it because when we bump VTK we keep it in sync. Note that VTK also does not care about the binary directory you give it; it uses ${CMAKE_BINARY_DIR} for artifacts without a way to override it.

The only road to the supported way is vtk_module_scan and vtk_module_build VTK’s modules yourself.

Agree on better build documentation :slight_smile:
Sorry to have wasted your time on this.

I think I have found a workable solution:

  • use cmake’s FetchContent() to populate a directory in the build tree containing the source of VTK
  • use configure_file() to configure a file containing the initial cache variables, i.e. which modules to build, where to find gdal etc
  • create a custom target which configures the CMakeLists.txt file found directly in the download location from FetchContent() similar to this example:
    add_custom_target(${DEP} ALL
                      COMMAND ${CMAKE_COMMAND} -S "${DEP_OPTIONS_SOURCE_DIR}" -B . -G "${CMAKE_GENERATOR}" -C "${DEP_OPTIONS_INITIAL_CACHE}" -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" -DCMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER}" -DCMAKE_C_COMPILER="${CMAKE_C_COMPILER}" -DCMAKE_INSTALL_PREFIX="${DEP_INSTALL_DIR}" -DCMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}" -DQT_ROOT_DIR="${QT_ROOT_DIR}" -DQT_BASE_VERSION="${QT_BASE_VERSION}"
                      COMMAND ${CMAKE_COMMAND} --build . -j
                      COMMAND ${CMAKE_COMMAND} --install .
                      DEPENDS ${DEP_OPTIONS_DEPENDS}
                      WORKING_DIRECTORY ${DEP_BUILD_DIR}
                      USES_TERMINAL
                     )

This does it for me now, I’m happy :slight_smile: