On Monday 12 July 2010, Michael Hertling wrote: > On 07/07/2010 09:44 AM, Michael Wild wrote: > > 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"). > > Yes, this is the usually recommended procedure to avoid such problems > with the peculiarities of SET(), but it is also counterintuitive, IMO, > that SET(VAR "abc") has an impact on a later SET(VAR "xyz" CACHE ...). > > > Calling SET(VAR "abc") after SET(VAR "xyz" CACHE ...) on the other hand > > is just fine. > > Personally, I'd prefer to strictly distinguish between "cached" and > "scoped" variables, i.e. when saying SET(VAR "xyz" CACHE ...), don't > say SET(VAR "abc") and vice versa, or in other words: SET(VAR "xyz") > means not being interested in a cached value of VAR at all - now and > later and for the entire project - and SET(VAR "xyz" CACHE ...) means > not to "misuse" VAR in the current scope as a writable local variable. > > If I understand correctly, the whole issue boils down to the fact that > a SET(<var> <val> CACHE <type> <doc>) sometimes writes to the current > scope and sometimes it doesn't, and changing this to make SET() always > write to the current scope would affect SET()'s backward compatibility, > cf. 9a77f65. > > With this in mind, there are two spontaneous suggestions for my part: > > (1) Introduce a new option to SET(), say "FROM_CACHE", so the command > SET(VAR "xyz" FROM_CACHE) unconditionally transfers VAR's cached > value to the current scope; the "xyz" could serve as a fallback > value if VAR is not yet cached, or VAR becomes unset in that case > as with SET(VAR) and "xyz" is simply ignored. Maybe, "FROM_CACHE" > can be provided for the likewise concerned OPTION() command, too. > (2) Introduce a new dereference operator, say "@{}", similar to the > well-known "${}" but working on the cache instead of the current > scope. So, SET(VAR @{VAR}) also unconditionally transfers VAR's > cached value to the current scope, and possibly, it's sufficient > to restrict "@{}" to the SET() command's realm. Though, OPTION() > wouldn't benefit in any way. > > However, the documentation of SET() and OPTION() should be improved > with respect to SET(<var> <val> CACHE <type> <doc>) and the related > possibility of <var> not receiving a new value in some cases, and > besides, is there a reason for "cmake -DXYZ:STRING=xyz .." and > "cmake -DXYZ=xyz .." to behave differently?
IIRC they both end up in the cache, but the one without "STRING" as type UNINITIALIZED. Or do you mean something else ? Alex _______________________________________________ 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