On 7. Jul, 2010, at 9:32 , Michael Hertling wrote: > On 07/03/2010 01:03 AM, Chris Hillery wrote: >> There's a slightly nicer work-around: Change project A's CMakeLists to set >> PROJB_OPENCV_LINK as a cache variable, ie, SET(PROJB_OPENCV_LINK NO CACHE >> BOOLEAN "doc"). I've tested it locally and it works the way you want it to. >> >> It seems that CMake divides the world of variables into two classes: cache >> variables and non-cache variables. Somewhat unfortunately, the same >> function, SET(), is used to specify values for both kinds, and cache >> variables "hide" any non-cache variables with the same name. The upshot is >> that the same SET() command will do different things depending on what's >> currently in the cache. >> >> Further confusion here comes from the fact that when a variable is declared >> as a cache variable (using either option() or set(...CACHE...) ), any >> current value that the non-cache variable with the same name has is >> discarded. So the first time you run cmake, PROJB_OPENCV_LINK isn't a cache >> variable until it gets to processing projb's CMakeLists.txt, hence the >> non-cache value you provided gets dropped. The second time, it's already a >> cache variable, so project A's CMakeLists actually sets the cache variable, >> and therefore projb's CMakeLists sees it as you expect. >> >> It's definitely confusing, but I'm not totally sure what the right solution >> is. It probably would have been cleaner if CMake made the distinction clear >> between cache and non-cache variables, but it's far too late to change that >> now. Maybe it would be possible to change it such that a cache variable >> declaration (option() or set(...CACHE...) ) would allow a current non-cache >> variable of the same name to override the declaration's default value, in >> the same way that -D on the command-line does. > > IMO, things aren't sooo bad. ;-) > > W.r.t. the value of a variable, CMake knows scopes and the cache. A new > scope is entered by ADD_SUBDIRECTORY() or a function's invocation. When > referring to a variable's value by the "${}" operator you get the value > from the current scope. At the start of a CMake run, the variables are > initialized with the values from the cache, provided the latter exists > and is appropriately populated. The SET() command - that is the actual > source of confusion along with OPTION() - basically has four flavours: > > (1) SET(VAR "xyz") sets the value of VAR in the current scope to "xyz", > i.e. "${VAR}" yields "xyz" until the value of VAR is changed anew. > (2) SET(VAR "xyz" PARENT_SCOPE) sets the value of VAR in the parent's > scope to "xyz", but doesn't affect the current scope or the cache. > (3) SET(VAR "xyz" CACHE STRING "..." FORCE) sets VAR's value in the > current scope and in the cache to "xyz" regardless if there's > already a cached value or VAR is defined in the current scope. > (4) SET(VAR "xyz" CACHE STRING "...") sets VAR's value in the cache > to "xyz" unless there's already a cached value for VAR, and the > latter's value in the current scope is set from the cache if > (a) the SET() writes to the cache, or > (b) VAR is undefined in the current scope, or > (c) the type of VAR in the cache is UNINITIALIZED. > > While (4a,b) are quite reasonable, (4c) is somewhat strange as it > yields different results for apparently equivalent invocations: > > CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR) > PROJECT(VARS NONE) > MESSAGE("VAR{1,2}[CACHE]: ${VAR1},${VAR2}") > SET(VAR1 "abc") > SET(VAR2 "abc") > MESSAGE("VAR{1,2}[LOCAL]: ${VAR1},${VAR2}") > UNSET(VAR2) > SET(VAR1 "xyz" CACHE STRING "") > SET(VAR2 "xyz" CACHE STRING "") > MESSAGE("VAR{1,2}[FINAL]: ${VAR1},${VAR2}") > > Cmaking from a clean build directory yields, as expected, (4a): > > VAR{1,2}[CACHE]: , > VAR{1,2}[LOCAL]: abc,abc > VAR{1,2}[FINAL]: xyz,xyz > > Afterwards, "cmake -DVAR1:STRING=pqr -DVAR2:STRING=pqr ." yields: > > VAR{1,2}[CACHE]: pqr,pqr > VAR{1,2}[LOCAL]: abc,abc > VAR{1,2}[FINAL]: abc,pqr > > So, VAR1 is finally not set from the cache, but VAR2 is as it's > undefined in the current scope at that moment; this proves (4b). > > Now, "cmake -DVAR1=pqr -DVAR2=pqr ." reveals (4c): > > VAR{1,2}[CACHE]: pqr,pqr > VAR{1,2}[LOCAL]: abc,abc > VAR{1,2}[FINAL]: pqr,pqr > > The parameter "-DVAR1=pqr", i.e. without a type, supplies the cache > with "VAR1:UNINITIALIZED=pqr" for VAR1, and the subsequent command > SET(VAR1 "xyz" CACHE STRING "") changes VAR1's type to STRING, but > does not touch the cached value; though, the latter is written to > VAR1 in the current scope. Here, I'm in doubt if this behaviour is > really intended. > > To summarize: If none of (4a-c) holds, i.e. an already cached value > for VAR with a type other than UNINITIALIZED and VAR defined in the > current scope, SET(VAR "xyz" CACHE STRING "...") just does nothing. > > It's that (4a-c) which causes the confusion in regard to a variable's > value in the cache and the current scope, and as OPTION(VAR "..." ON) > is, AFAIK, quite the same as SET(VAR ON CACHE BOOL "..."), the above- > mentioned considerations apply accordingly. So, the rule of thumb is > to differentiate cleanly between variables to be used with the cache > and variables to be used as usual, or in other words: If one wants a > variable to be set to a cached value one shouldn't use it afore, i.e. > saying SET(VAR "xyz" CACHE STRING "...") with VAR being undefined at > that moment behaves as desired: If there's already a cached value it > gets written to VAR, otherwise "xyz" is written to VAR and the cache > and, thus, serves as a fallback value. In short: Go the (4b) way. ;) > > Regards, > > Michael > > P.S.: There has been several discussions of this issue, and it > has even been considered to introduce a related policy: > > <http://www.mail-archive.com/cmake@cmake.org/msg20930.html> > <http://www.mail-archive.com/cmake@cmake.org/msg21394.html> > <http://public.kitware.com/Bug/view.php?id=9008> - ongoing!
The short rule from all this is: *NEVER* call SET(VAR "xyz" CACHE ...) *AFTER* you called SET(VAR "abc"). Calling SET(VAR "abc") after SET(VAR "xyz" CACHE ...) on the other hand is just fine. Michael (the other) _______________________________________________ Powered by www.kitware.com Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Follow this link to subscribe/unsubscribe: http://www.cmake.org/mailman/listinfo/cmake