Search code examples
c++ccmakeclion

Difference between CMake options, environment variables and build options


I'm using CLion in my project and try to get a better understanding which configuration parameter does what. For instance, what corresponds to a #define statement in code, which are equivalent and when to use what. Can anyone shed some light?


Solution

  • I understand your confusion. Let's try to clear things up.

    I guess by build options you mean options you specify as command line parameters when invoking CMake (eg. cmake -DFOO=Bar ..). What this will do is set a variable FOO in the CMake cache to the value Bar. A CMake script may then use this like any other (cached) variable in CMake. Note that cached variables are persisted between different runs of CMake. That means, unless the user deleted their CMake cache in between runs, CMake will remember the option from a previous run, without the user having to restate the option on the command line. However, every time they run CMake for the first time, they need to restate the option.

    CMake options work exactly the same, with the additional convenience that CMake knows that the variable is supposed to be set by the user beforehand. On the command line that doesn't make a difference at all, but if your users are using the ccmake or cmake-gui frontends (or an IDE that knows about CMake options) the option will show up there. So for variables that you expect to be set by the user, don't just use them in the script and pretend that your users will know about them - set a proper CMake option so that the variable shows up in the frontend as a build option for the user.

    Environment variables serve a different purpose - they describe the environment. Unlike build options which are stated for each build individually, environment variables should contain information about the system that never changes. For instance, find_package considers environment variables when searching for dependencies on a system (Package_ROOT, where Package is the name of the dependency). This makes sense because it is likely that you will only have a single installation of that package on your system which will then be used by all projects depending on it. Instead of having to restate the location of the dependency on every fresh CMake run, you set the environment variable once and it will just work from then on out (until you remove the dependency from its original location).

    But wait, what if I want to use a different installation of that dependency only for building project X. I don't want to have to change the environment variable every time I build X and have to change it back after... That's why find_package, in addition to the environment variable, also considers the CMake variable of the same name. That way, a user can still override the system-wide setting from the environment variable through a build specific option. So the two mechanisms are not at all mutually exclusive.

    Think carefully about how your users will want to use the respective options and choose the mechanism(s) accordlingly.