Installed module library can't find imported headers [Ubuntu 22.04 LTS, CMake 3.28.1, Ninja 1.11.1 and Clang 17.0.6]

Using Ubuntu 22.04 LTS, CMake 3.28.1, Ninja 1.11.1 and Clang 17.0.6, I’m trying to create a library using modules, supported under these conditions, as described at import-cmake-the-experiment-is-over.

I managed to successfully create a library with modules, and link it to an executable in the same project.

My library is quite simple:


// robocin/utility/concepts.ixx

module;

#include <concepts>

#include <google/protobuf/message_lite.h>

export module robocin.utility:concepts;

export namespace robocin {

template <class T>

concept protobufish = std::derived_from<std::remove_cvref_t<T>, ::google::protobuf::MessageLite>;

} // namespace robocin


// robocin/utility/utility.ixx

export module robocin.utility;

export import :concepts;

  • Here is my rule responsible for creating a library.
// CMakeLists.txt

robocin_cpp_library(
  NAME utility
  MODS utility.ixx
  concepts.ixx
  DEPS protobuf::libprotobuf
)

robocin_cpp_executable(
  NAME local_target
  SRCS local_target_main.cpp
  DEPS utility
)


// robocin/utility/local_target_main.cpp

#include <iostream>
#include <vector>

import robocin.utility;

int main() { return robocin::protobufish<std::vector<int>>; }

Compile and works as expected.

However, when I tried to install it and use it in an executable in another project, the library created with modules was unable to find the included dependency:

// CMakeLists.txt

robocin_cpp_executable(
  NAME external_target
  SRCS external_target_main.cpp
  DEPS common::utility # utility library generated by robocin/utility project and installed on the system.
)


// experimental/external_target_main.cpp (same as robocin/utility/local_target_main.cpp)

#include <iostream>
#include <vector>

import robocin.utility;

int main() { return robocin::protobufish<std::vector<int>>; }

Compiling output:


[proc] Executing command: /usr/local/bin/cmake --build /workspaces/project/experiments/cpp-modules/build --config Debug --target all -j 6 --

[build] [1/6 16% :: 0.058] Scanning /usr/local/modules/concepts.ixx for CXX dependencies

[build] FAILED: CMakeFiles/common__utility@synth_ee677d4352ba.dir/90ece7fad90b.bmi.ddi

[build] "/usr/bin/clang-scan-deps-17" -format=p1689 -- /usr/bin/clang++ -DROBOCIN_PROJECT_NAME=\"common\" -DROBOCIN_PROJECT_PATH=\"/tmp/common/cpp\" -I/tmp/common/cpp -I/tmp/common/cpp/build -g -std=gnu++23 --precompile -x c++ /usr/local/modules/concepts.ixx -c -o CMakeFiles/common__utility@synth_ee677d4352ba.dir/90ece7fad90b.bmi -MT CMakeFiles/common__utility@synth_ee677d4352ba.dir/90ece7fad90b.bmi.ddi -MD -MF CMakeFiles/common__utility@synth_ee677d4352ba.dir/90ece7fad90b.bmi.ddi.d > CMakeFiles/common__utility@synth_ee677d4352ba.dir/90ece7fad90b.bmi.ddi.tmp && mv CMakeFiles/common__utility@synth_ee677d4352ba.dir/90ece7fad90b.bmi.ddi.tmp CMakeFiles/common__utility@synth_ee677d4352ba.dir/90ece7fad90b.bmi.ddi

[build] Error while scanning dependencies for /usr/local/modules/concepts.ixx:

[build] /usr/local/modules/concepts.ixx:4:10: fatal error: 'google/protobuf/message_lite.h' file not found

[build] ninja: build stopped: subcommand failed.

  • Here is the generated CMake file, which I imagine is imported by the executable for linking dependencies.

Previously this same library was a header, and it worked in both cases.

A complete example with all the files is available on GitHub: robocin/ssl-core/tree/cpp-modules.

Thanks for the report; I don’t have time to dig into it right now, but I added it to my “C++ modules” task pile when I get the chance.

Thanks @ben.boeckel! Something that could also help would be to have a practical example of an installable C++ module library that uses third parties/external dependencies, which is exactly my problem. I can try to understand the error better from a functional example, and if I find the solution, I can clarify the error here to help anyone else who faces the same problem in the future.

As it’s something new, I couldn’t find any examples in this direction.

The export-* tests here might have a simple case to look at. If something more complicated confuses things, let’s figure out where it breaks down.

I attached a small producer + consumer pair of projects to the following issue recently. It may serve to show you how to do things.

https://gitlab.kitware.com/cmake/cmake/-/issues/25594

I looked at the links you pointed out and ended up making some adjustments to my rules because of this, but they didn’t solve the problem I reported.

However, I noticed that when I added the path of the third party libraries to this IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES variable in the auto-generated CMake file, the compilation worked normally.

Trying to figure out how to make it work, I realized that I had to add:

foreach (DEP ${DEPENDENCIES})
  get_target_property(dep_include_dirs ${DEP} INTERFACE_INCLUDE_DIRECTORIES)
  target_include_directories(${LIBRARY_NAME} PRIVATE ${dep_include_dirs})
endforeach ()

Which I didn’t need before for my headers library :thinking:.

Now it seems to work normally.

Do you link to targets for your dependencies? Can you try to boil this down to a minimal example that I can investigate (assuming it is not covered by Craig’s 25594 example)?

@josecruz Any update on a minimal reproducer?

FWIW, this test shows that includes work, but it is its own provided headers. I’ll try to see about adding a test that transitive dependencies get propagated properly.

I’ve made a reproducer case; tracking it down.

Fix is here: https://gitlab.kitware.com/cmake/cmake/-/merge_requests/9265

Sorry for the delay, Ben!

Here’s a minimal example within what I interacted with the problem: GitHub - joseviccruz/cmake-module-error

In this test I use the GoogleTest library, installed in the /opt directory.

The three root scripts execute the installation of a simple library with a header or module in /usr/local and then try to execute that library in another project.