78182

How to tell whether CMake used initial value for an option?

Say I have an option "ENABLE_Foo" in CMake:

option(ENABLE_Foo "Tell cmake to enable the package Foo" ON)

I want to detect whether the user specified -DENABLE_Foo=ON or -DENABLE_Foo=OFF, or whether the specified initial value ON is being used.

The reason I want to tell whether the user turned the option on or whether it is turned on by default is because Foo requires an additional package and I want to cover these cases:

1) User did not specify a value for the option ENABLE_Foo:     a) Package Foo is found -> use Foo     b) Package Foo is not found -> silently turn off Foo 2) User specified a value for the option ENABLE_Foo:     a) User said -DENABLE_Foo=ON:         i) Package Foo is found -> use Foo         ii) Package Foo is not found -> fatal error message     b) User said -DENABLE_Foo=OFF -> don't use Foo and don't try to find it

If there is no way to tell whether the option value came from user input or from the initial value, are there other ways to achieve what I have outlined above?

Answer1:

If the user gives -DENABLE_Foo=ON on the command line, an entry for the respective option will be added to the CMake cache. While it is possible to inspect this value before invoking the option command, you cannot distinguish whether the value was originally set by the user on the command line, or by the option command itself on a previous CMake run.

Still, achieving the behavior you described is possible.

The main issue is that you cannot model the configuration options you want with just one flag. You are actually dealing with two different options.

The first is whether support for Foo is desired at all, the second is whether Foo is to be considered an optional or a mandatory dependency. Note that the value of the latter is irrelevant in case support for Foo is disabled. One way to handle this would be to remove the option completely in this case. This allows for the following approach:

if(REQUIRE_Foo) # REQUIRE_Foo implies ENABLE_Foo unset(ENABLE_Foo CACHE) endif() option(ENABLE_Foo "Tell cmake to enable support for package Foo" ON) if(ENABLE_Foo) option(REQUIRE_Foo "Abort the build if Foo is not found." OFF) find_package(Foo) # assuming that FindFoo is a well-behaving find script, # which will set Foo_FOUND appropriately else() unset(REQUIRE_Foo CACHE) set(Foo_FOUND FALSE) endif() if(REQUIRE_Foo AND NOT Foo_FOUND) message(FATAL_ERROR "Required library Foo could not be found") endif()

In case the user wants to require Foo support (your case 2a) they would invoke CMake with -DREQUIRE_Foo=TRUE. In case they want to disable Foo completely (your case 2b) they would use -DENABLE_Foo=FALSE. If the user specifies nothing, you get the behavior from your case 1.

Assuming that the rest of the build system is already prepared to handle the case where Foo was not found (case 1b from your question), this should just work without further changes.

Note that even if you could detect whether the flag was set by the user, it would still be undesirable to implement the original behavior from your question.

Assuming we could detect it, the initial value of REQUIRE_Foo in the above code would be set to true if and only if ENABLE_Foo=ON was set on the command line. Doing this implicitly without also adding the REQUIRE_Foo to the set of configuration options is problematic. A user would experience different behaviors on CMake runs even though the build options are the same. You should avoid magical behavior like this. It will only confuse users and give you a hard time debugging failing CMake runs.

Always make build options that depend on configuration given by the user visible to the user.

Recommend

  • String.padStart() not applying in Angular function
  • How to tell whether CMake used initial value for an option?
  • Stream processing lots of stuff to OVA
  • Capturing the SOAP body from a WCF service
  • why when we write \\n in the file it converts into \\r\\n combination?
  • Java library to escape/clean XML?
  • remove Niqqud from string in javascript
  • SocketChannel: java.io.IOException: An existing connection was forcibly closed by the remote host
  • Request map direct me to Login page in Grails
  • Fastest way to save/load data.table
  • Creating grails binary plugin results in jar file wich contains all groovy files with comments
  • Hide JetBrains annotation on popup JavaDoc in IntelliJ
  • Java NoClassDefFoundError when running jar containing library jar
  • R matching more than 2 conditions and return the response value
  • jQuery ajax security
  • Make background for table rows extend past the bounds of the table
  • How can I see Python's __builtins__ source code?
  • Using LINQ with IBM i
  • Invoking a controller's action by button in View without redirecting to any view
  • Calling a constructor through reflection in scala 2.10
  • Run script file on remote server
  • Iterate twice through a DataReader
  • How does ActiveSupport do month sums?
  • If I am creating a simple client server application in IntelliJ, how should this work?
  • HttpClient: disabling chunked encoding
  • Getting the scrolling offset when storing coordinates
  • Clear fused location provider's location for testing
  • android.support.v7.widget.Toolbar VectorDrawableCompat IllegalStateException when using support lib
  • Ionic 2 storage is not cleaning up on uninstall - Only for signed APK
  • How to define and use opencv mat of user type
  • preg_replace Double Spaces to tab (\\t) at the beginning of a line
  • Cassandra Data Model
  • Updated Ionic CLI but shows previous version (Windows)
  • How to set the response of a form post action to a iframe source?
  • Getting Messege Twice Using IMvxMessenger
  • Change div Background jquery
  • Qt: Run a script BEFORE make
  • reshape alternating columns in less time and using less memory
  • Conditional In-Line CSS for IE and Others?
  • Python/Django TangoWithDjango Models and Databases