[CMake] Study of Cache Interaction with If Statements

Michael Wild themiwi at gmail.com
Mon Jun 15 01:21:29 EDT 2009


On 12. Jun, 2009, at 19:31, Hostile Fork wrote:

> Hello cmakers,
>
> I have been looking at some unusual ways in which values stored in  
> the cache interact with the 'if' statement.  I'll start with a  
> simple case that matches typical programming intuition:
>
> 	set (VAR1 ON)
> 	set (VAR2 OFF)
> 	if (VAR1)
>        	set (VAR2 ON)
> 		message ("VAR2 is ${VAR2}")
> 	endif (VAR1)
>
> This prints "VAR2 is ON".  But if we use the cache variation for  
> both assignments:
>
> 	set (VAR1 ON)
> 	set (VAR2 OFF CACHE BOOL "Variable 2 Label A")
> 	if (VAR1)
>        	set (VAR2 ON CACHE BOOL "Variable 2 Label B")
>        	message ("VAR2 is ${VAR2}")
> 	endif (VAR1)
>
> ...then if doing a fresh make, this will print "VAR2 is OFF".   
> Running 'cmake -DVAR2=ON' causes it to say "VAR2 is ON".  Running  
> 'cmake -i' reveals the label for VAR2 as "Variable 2 Label A".


That's a good thing! A cache assignment never overwrites a cache value  
unless you use the INTERNAL type or use the FORCE option. Otherwise  
you would make your users very unhappy if they changed some cache  
value and the next CMake-run (which is required for the change to  
become effective) overwrites it again!

>
>
> Looking at a third case:
>
> 	set (VAR1 ON)
> 	set (VAR2 OFF CACHE BOOL "Variable 2")
> 	if (VAR1)
>        	set (VAR2 ON)
>        	message ("VAR2 is ${VAR2}")
> 	endif (VAR1)
>
> ...for a fresh make will print "VAR2 is ON".  Running 'cmake - 
> DVAR2=OFF' does not change this.


This is also intended behaviour. Think of it like this: the cache  
provides a default-value for a variable. The variable can then be  
changed locally by your code. I use this feature quite often to  
construct absolute installation paths. Take e.g. the variable  
INSTALL_CONFIG_PATH which by default is set to "etc" on Unix  
platforms. Relative paths (as this one) should be interpreted as  
relative to CMAKE_INSTALL_PREFIX. However, the user should also be  
able to provide a full path. So, in order for you application to be  
able to find the configuration files, you need to somehow come up with  
the full path. So this is what I do:

set( INSTALL_CONFIG_PATH "etc" CACHE STRING "Installation directory  
for the configuration files" )
if( NOT IS_ABSOLUTE "${INSTALL_CONFIG_PATH}" )
   set( INSTALL_CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/$ 
{INSTALL_CONFIG_PATH}" )
endif( NOT IS_ABSOLUTE "${INSTALL_CONFIG_PATH}" )


This way the user can specify a relative path, but in my CMake code I  
get an absolute path.


>  And just to round out the example set...
>
> 	set (VAR1 OFF)
> 	if (VAR1)
>        	set (VAR2 ON CACHE BOOL "Variable 2")
> 	endif (VAR1)
>
> This will give an interactive prompt for "Variable 2" when using  
> ("cmake -i"), even though the value is never needed.

That is strange. It doesn't happen for me using CMake-2.6.3. Which  
version are you using? Did you have a dirty cache?

>
>
> I'll try and guess a few points:
>
> (1) 'if' cannot control whether something is prompted for in the  
> interactive mode.  one or more appearance of a 'CACHE' by an  
> associated 'set' will trigger a prompt for that variable

No, it should not.

>
>
> (2) it is possible to have multiple cached "set" statements for the  
> same variable... as well as to mix cached and non-cached variable  
> assignments.  but each cached set will always use the cache value

As I explained above, this is a good thing. It would be very confusing  
to the user otherwise. If you need a persistent variable which you can  
overwrite as you like, use the INTERNAL cache type.

>
>
> (3) there is no apparent enforcement of consistency in the cache  
> defaults or labeling... and which default/label wins may not be a  
> well-defined behavior

It is. The first definition wins. If that definition is on the command  
line via -DVAR2=OFF, that is the first definition.

>
>
> I was disappointed about (1), because I have several options which  
> are only relevant if another option is set.  There are also some  
> options which cannot be set together.  So currently I have checks  
> like this in the header file:
>
> 	#if USE_FOO
> 	#	if USE_BAR
> 	#		error Cannot have USE_BAR=1 when USE_FOO=1
> 	#	endif
> 	#else
> 	#	if USE_FOO_OPTIMIZATION
> 	#		error cannot have USE_FOO_OPTIMIZATION=1 when USE_FOO=0
> 	#	endif
> 	#endif
>
> What makes (2) confusing is that when you use CACHE with 'set', it  
> ceases to have very much in common with set(VAR VAL).  Correct me if  
> I'm wrong, but its semantics seem like "Get From Cache And Ignore  
> Val Unless Cache Is Empty And Then Maybe Use Val If There Are No  
> Other Set With Cache Statements Which Supply A Different  
> Val...Otherwise Who Knows" operator.

No, this is more like a "You Should Definitely RTFM And Read The CMake  
Book" case.

>
>
> This might be helped by breaking 'set' into a few smaller commands,  
> such as those which define cache values and which fetch them.  That  
> would also mean that CMake could keep people from thinking (1) is  
> possible by requiring statements which declare cache variables  
> (option, "definecache(?)") to appear at top scope.
>
> Thoughts?  I'm curious if there is any documentation which addresses  
> these kinds of issues.

Read this carefully:
http://www.cmake.org/cmake/help/cmake2.6docs.html#command:set


Michael


More information about the CMake mailing list