12

Edit: The accepted answer actually shows that it is pretty normally possible to set CMAKE_MODULE_PATH as any other CMake variable e.g. via the -DCMAKE_MODULE_PATH path CLI parameter. It seems that in my case there is some included CMake script that calls set(CMAKE_MODULE_PATH /library_path), which erases all previous paths set to the variable. That's why I couldn't get the variable to do what I wanted it to do. I'll leave the question here in case anybody else faces this kind of situation.


I'm building a (3rd party) project that uses the Protobuf library (but this question is general). My system has a system-wide install of a newer version of Protobuf than the project is compatible with. So I've downloaded and compiled from source an older version of Protobuf.

The project uses CMake, and in its CMakeLists.txt, there is:

find_package(Protobuf REQUIRED)

Which, however, finds the (incompatible) system install. Of course, CMake doesn't know about my custom build of Protobuf. But how do I tell it?

I've created a FindProtobuf.cmake file in, say, ~/usr/share/cmake-3.0/Modules/ and want the build process to use this one for finding Protobuf. But I haven't succeeded forcing CMake to pick up this one and not the system one. I think the reason is quite obvious from the CMake docs of find_package:

The command has two modes by which it searches for packages: “Module” mode and “Config” mode. Module mode is available when the command is invoked with the above reduced signature. CMake searches for a file called Find<package>.cmake in the CMAKE_MODULE_PATH followed by the CMake installation. If the file is found, it is read and processed by CMake. ... If no module is found and the MODULE option is not given the command proceeds to Config mode.

So until I succeed to change CMAKE_MODULE_PATH, CMake will just pick up the FindProtobuf.cmake installed to the default system path and won't ever proceed to the "Config" mode where I could probably make use of CMAKE_PREFIX_PATH.

It's important for me to not edit the CMakeLists.txt since it belongs to a 3rd party project I don't maintain.

What I've tried (all without success):

  • calling CMAKE_MODULE_PATH=~/usr/share/cmake-3.0/Modules cmake ... (the env. variable is not "transferred" to the CMake variable with the same name)
  • calling cmake -DCMAKE_MODULE_PATH=~/usr/share/cmake-3.0/Modules ... (doesn't work, probably by design?)
  • calling Protobuf_DIR=path/to/my/protobuf cmake ... (the project doesn't support this kind of override for Protobuf)

It seems to me that, unfortunately, the only way to alter the CMAKE_MODULE_PATH used by find_package is to alter it from within CMakeLists.txt, which is exactly what I want to avoid.

Do you have any ideas/workarounds on how not to touch the CMakeLists.txt and still convince find_package to find my custom Protobuf?

For reference, the CMake part of this project is on github .

Martin Pecka
  • 2,953
  • 1
  • 31
  • 40
  • 6
    You use **wrong way** for forcing CMake to use non-default installation of protobuf. Instead of replacing `FindProtobuf.cmake` script, you need to hint existsing script to find your Protobuf installation. E.g. you may set *CMAKE_PREFIX_PATH* variable. See question http://stackoverflow.com/questions/34795816/hinting-findname-cmake-files-with-a-custom-directory about more info about such "hinting". – Tsyvarev May 11 '17 at 21:08
  • Thanks, @Tsyvarev, using your suggestion, I persuaded the project to compile. But could you point me to a source explaining why exactly would what I want to do be the wrong way? – Martin Pecka May 12 '17 at 09:28
  • 1
    It is just a general approach: If you can adjust environment to make **existed code** to work, do that instead of *modifying the code*. – Tsyvarev May 12 '17 at 20:12

1 Answers1

5

As a direct answer to your question, yes, you can set CMAKE_MODULE_PATH at the command line by running cmake -DCMAKE_MODULE_PATH=/some/path -S /path/to/src -B /path/to/build.

But that probably doesn't do what you want it to do; see below.


The Bitbucket link you supplied is dead, but here are a few suggestions that might help.

  1. Avoid writing your own find modules, especially when the upstream supplies CMake config modules.
  2. You can direct CMake to your custom Protobuf installation by setting one of CMAKE_PREFIX_PATH or Protobuf_ROOT (v3.12+) to the Protobuf install root.
  3. You can tell find_package to try CONFIG mode first by setting CMAKE_FIND_PACKAGE_PREFER_CONFIG to true (v3.15+). Then set Protobuf_DIR to the directory containing ProtobufConfig.cmake.
  4. Failing all else, you can manually set the variables documented in CMake's own FindProtobuf module, here: https://cmake.org/cmake/help/latest/module/FindProtobuf.html

All these variables can be set at the configure command line with the -D flag.

There are very few environment variables that populate CMake variables to start and I would avoid relying on them. There is an exhaustive list here: https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html. CMAKE_MODULE_PATH is not among them.

Alex Reinking
  • 16,724
  • 5
  • 52
  • 86
  • I updated the link to the migrated location of the repository. Thank you for pointing out the possibilities newer CMake offers. This project is assumed to be built with 3.10, though, and I'd stick with that. But as @Tsyvarev has already suggested, CMAKE_PREFIX_PATH helped here. Setting CMAKE_FIND_PACKAGE_PREFER_CONFIG seems like a really dangerous option which could break a lot of other code (which expects the Find module will be used). Neither of the answers provides a way to alter CMAKE_MODULE_PATH, which was the ultimate goal of the question, so I won't mark your answer as accepted. – Martin Pecka Feb 28 '21 at 19:26
  • 1
    Setting CMAKE_MODULE_PATH with -D at the command line _does_ alter the CMAKE_MODULE_PATH, full stop. Unless there's explicit code in your CMakeLists to override that cache variable that you haven't shown us, that is. – Alex Reinking Feb 28 '21 at 19:28
  • Whether that variable does what you want it to is a different question. This is [XY problem](https://xyproblem.info/) all the way. – Alex Reinking Feb 28 '21 at 19:28
  • 1
    Oh, you're right! So it had to be one of the included CMake scripts that called `set(CMAKE_MODULE_PATH /mypath)` without respecting previous contents of the variable. By doing a quick search, I couldn't find any such script, but it's possible it somehow leaked in... It wouldn't be the first time I saw it... – Martin Pecka Feb 28 '21 at 23:39
  • I edited the question to provide future readers a quick statement that my problems were most probably created by some faulty included CMake script. – Martin Pecka Feb 28 '21 at 23:40