Is it appropriate to use enable_language in a CMake package file?

We have a library that has a pure-C interface, but is partially written in C++ and uses OpenMP. We generate a CMake package file for this library, so other CMake projects can easily use it.

However, when a C language project tries to use our library, CMake shows an error like this:

  Target "test_prog" links to target "OpenMP::OpenMP_CXX" but the target
  was not found.  Perhaps a find_package() call is missing for an IMPORTED
  target, or an ALIAS target is missing?

This happens only if test_prog's CMakeLists.txt contains:

project(test_prog C)

I.e., it happens when only the C language is enabled, not C++. If the dependent project uses project(test_prog C CXX) or simply project(test_prog), then everything works fine.

However, users of our library are often pure-C projects, and they have no way to know that they are supposed to enable C++ support in CMake. To make things more confusing, out library can be compiled without OpenMP support, in which case this problem doesn’t even appear. Is there a solution to the problem that does not require our users to explicitly enable C++ support?

After some experimentation, I see that I can solve this problem as follows: I find the find_package(OpenMP) line in the ourlib-config.cmake CMake package file, and add enable_language(CXX) beforehand.

Question: Is this the correct solution, i.e. adding enable_language(CXX) to our package file?

The CMake documentation states:

This command must be called in file scope, not in a function call. Furthermore, it must be called in the highest directory common to all targets using the named language directly for compiling sources or indirectly through link dependencies. It is simplest to enable all needed languages in the top-level directory of a project.

This gives me pause. It sounds like enable_language should not be used in a package file.

I would recommend only testing whether a language is enabled in your config package file, not actually enabling a language. If your package requires a language that isn’t enabled, you can halt with a fatal error informing the user they need to enable the language in the top level of the project. You can get the set of enabled languages with the ENABLED_LANGUAGES global property.

Enabling languages in subdirectories rather than at the top level can have some obscure problems. I don’t recall what those are off the top of my head, but last time I looked into what the CMake code does around this, I concluded that you really don’t want to enable a language anywhere other than the very top directory scope (i.e. the top level CMakeLists.txt file).

1 Like