[Cmake] Setting variables breaks the cache for SUBDIRS?

Zachary Pincus zpincus at stanford.edu
Wed, 14 Apr 2004 10:57:41 -0700


I agree with that setting include directories should probably best be 
done in the top-level CMakeList -- I guess my hope of making things 
totally modular to ease re-factoring, etc, will not see full fruition.

Nevertheless (and as I mentioned before) I brought this up as a 
*separate* issue because I think that in general, the way CMake handles 
SUBDIRS and variables is, while completely logical once explained, 
prone to causing confusing outcomes, and really not explained anywhere 
I could find.

Confusion (1): the SUBDIRS() command is executed *after* the rest of 
the CMakeList, regardless of where in the list it appears. This is only 
minimally documented.

Upshot (1): So there really is no way for sub-directory CMakeLists to 
communicate from "child" to "parent" in the same configuration run.

Confusion (2): how the environment for the SUBDIRS() is set up. I would 
never have guesses that the top-level CMakeList is basically re-run for 
each subdir. This is un-documented, and even runs a bit counter in 
spirit if not in specific assertion to the statement that all 
CMakeLists are run in the same process and that the environment is 
"inherited." As it stands, the subdirs CMakeLists might as well run in 
different processes, and the "re-created" is more appropriate than 
"inherited."

Upshot (2): So there really is no general way for communication between 
"sibling" CMakeLists called via a SUBDIRS() command. The "obvious" 
solution of having one cache variable for all doesn't work because of 
peculiarities in CMake, and the other solutions require each CMakeList 
to have explicit knowledge of what different variable each different 
sibling sets.

So, I again ask the question as to whether there is any real generic 
need for (1) child->parent CMakeList communication, or 
sibling<->sibling communication. If so, there are no mechanisms in 
place for such. If not, then the current setup is fine, if 
counterintuitive for people attempting (fruitlessly) to implement such 
communications.


Zach Pincus

Department of Biochemistry and Program in Biomedical Informatics
Stanford University School of Medicine

On Apr 14, 2004, at 10:14 AM, William A. Hoffman wrote:

> Your original post was about include directories.   In that case, I 
> would
> say that the that include directory should be specified in the highest
> level cmake list file where it is needed, that is what most of our 
> projects
> do.
>
> However, if your really want to have the sub dirs specify project 
> inclues,
> I don't think we need to add more complexity to the cache variables.
> Perhaps you could do what you want using more than one variable.
>
> The behavior is due to the way cmake is parsed.   Each subdir reads the
> parent cmakelist files and executes all inherited commands, so the SET
> at the top gets done for subdir foo and bar, and the last one to 
> execute
> is the one that ends up in the cache.
>
>
> Something like this might work for you:
>
> SET(INCLUDES "${B_INCLUDES};${A_INCLUDES}" CACHE INTERNAL "")
> INCLUDE_DIRECTORIES(${INCLUDES})
> SUBDIRS(a b)
>
> directory b:
> SET(B_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "")
>
> directory a:
> SET(A_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "")
>
>
> However, it still does require that the top level cmake file know about
> the subdir variable names.   I would still say that the top level
> cmakelist file should specify relevant include directories.
>
> -Bill
>
> At 12:31 PM 4/14/2004, Zachary Pincus wrote:
>> Bill,
>>
>> I explained more fully my intention with these cache variables in a 
>> separate email I sent to the CMake list immediately prior to the one 
>> under current discussion (Re: [Cmake] variables set in SUBDIRS() 
>> available to top-level CMakeList?). The thumbnail is thus: I wanted 
>> to have information gathered by CMakeLists caled via SUBDIRS() 
>> somehow percolate to the top-level CMakeList, and I tried to follow 
>> your suggestion of using cache variables, which turned out to be a 
>> bit problematic.
>>
>> Regardless, I brought up this matter separately because I thought 
>> that the behavior was sufficiently odd that it might warrant a 
>> general discussion of how CMake should operate.
>>
>> Specifically, the fact that "set" variables shadow the cache, and 
>> prevent cmake from looking for a variable value in the cache, leads 
>> to strange behavior when different CMakeLists called via SUBDIRS() 
>> attempt to read from and write to a particular cache variable. This 
>> behavior vis a vis cached variables seems imminently reasonable and 
>> works well most of the time, but can lead to the sort of seemingly 
>> counter-intuitive behaviors I demonstrated earlier.
>>
>> There seem to be three possible solutions: one is to say that 
>> different CMakeLists called via SUBDIRS() *must not* attempt lateral 
>> communication via cache variables. The second solution is to somehow 
>> automatically decide whether the cached variable is "fresher" than 
>> the variable that a CMakeList inherits from it's parent environment, 
>> and then to use the "fresher" value. The third solution is to have an 
>> explicit "refresh from cache" command so that the default shadowing 
>> behavior can be overridden.
>>
>> The first is easy, but perhaps limiting. The second is hard and will 
>> undoubtedly lead to other unexpected quirks. The third is perhaps 
>> workable, but bizarre.
>>
>> So I guess that just saying that different "sibling" CMakeLists 
>> should not try to get and set the same cache variable is reasonable 
>> -- if there is either (A) the clear understanding that these 
>> CMakeLists should never need to communicate or (B) a different or 
>> better method for such communication.
>>
>> Any thoughts?
>>
>> Thanks,
>> Zach
>>
>> On Apr 14, 2004, at 5:33 AM, William A. Hoffman wrote:
>>
>>> Perhaps if you were to describe what you are trying to accomplish, 
>>> there is
>>> another solution.
>>>
>>> -Bill
>>>
>>>
>>> At 12:06 AM 4/14/2004, Zachary Pincus wrote:
>>>> Hello,
>>>>
>>>> I've run into a strange problem with the cache and SUBDIRS.
>>>>
>>>> Here's the setup: I have a variable that I want to add to from 
>>>> various different CMakeLists in subdirectories, called from a 
>>>> SUBDIRS() command.
>>>>
>>>> This works fine:
>>>>
>>>> --------------
>>>> Top CMakeList
>>>> --------------
>>>> SUBDIRS(foo bar)
>>>>
>>>> --------------
>>>> Foo CMakeList
>>>> --------------
>>>> SET(VAR "${VAR} foo" CACHE INTERNAL "add foo")
>>>>
>>>> --------------
>>>> Bar CMakeList
>>>> --------------
>>>> SET(VAR "${VAR} bar" CACHE INTERNAL "add bar")
>>>>
>>>>
>>>> Now, as you would expect, after this all runs, the cache contains 
>>>> VAR=" foo bar"
>>>>
>>>> However, if we change the top level CMakeList to look like this:
>>>> --------------
>>>> Top CMakeList
>>>> --------------
>>>> SET(VAR "top" CACHE INTERNAL "add top")
>>>> SUBDIRS(foo bar)
>>>>
>>>> then instead of VAR="top foo bar" as you would expect, we just get 
>>>> "top bar"
>>>>
>>>> It looks to me like *if* there is no variable set in the top-level 
>>>> CMakeList, the CMakeLists called from the SUBDIRS command can load 
>>>> cached variables. However, if such a variable has already been set 
>>>> in the top-level CMakeList, this prevents the subdir-CMakeLists 
>>>> from actively reading from the cache each time. When "child" 
>>>> CMakeList sets the cached variable thinking it is appending to it, 
>>>> it actually overwrites the variable because the CMakeList never 
>>>> read in the latest version (cached by a "sibling" CMakeList) 
>>>> because the version of the variable inherited from the parent 
>>>> "shadows" this.
>>>>
>>>> SO: Is there a way to force a CMakeList to refresh the cache? Is 
>>>> this behavior a bug?
>>>>
>>>> Zach Pincus
>>>>
>>>> Department of Biochemistry and Program in Biomedical Informatics
>>>> Stanford University School of Medicine
>>>>
>>>> _______________________________________________
>>>> Cmake mailing list
>>>> Cmake at www.cmake.org
>>>> http://www.cmake.org/mailman/listinfo/cmake
>>>
>>> _______________________________________________
>>> Cmake mailing list
>>> Cmake at www.cmake.org
>>> http://www.cmake.org/mailman/listinfo/cmake
>
> _______________________________________________
> Cmake mailing list
> Cmake at www.cmake.org
> http://www.cmake.org/mailman/listinfo/cmake
>