CMake if commands are interesting in the sense that variable names can be used directly. In most other languages you have to explicitly dereference the variable to get the value out. I think when you use a string that is the same name as a variable you are getting problems.<br>
<br><span style="font-family: courier new,monospace;"> if(variable STREQUAL string)</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> if(string STREQUAL string)</span><br style="font-family: courier new,monospace;">
<br>According to the docs, only the RHS should have a possibility of being dereferenced, however emperical evidence suggests otherwise.<br><br><span style="font-family: courier new,monospace;">set(var "stuff")</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">set(stuff ON)</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">if(var STREQUAL "stuff")</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> message("var STREQUAL stuff")</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">else()</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> message("NOT var STREQUAL stuff")</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">endif()</span><br style="font-family: courier new,monospace;">
<br>var STREQUAL stuff should return true. var should get dereferenced to "stuff" and that should match "stuff" on the LHS.<br><br>This isn't the case if stuff is defined. Uncommenting out 'set(stuff ON)' makes the if statement behave properly, because stuff can't be dereferenced (it's a string and not a variable).<br>
<br>So in your code when you compare opt to "fine", the behavior changes based on whether you have defined fine as a variable or not.<br><br>In your other post, you said it worked if you used MATCHES instead of STREQUAL. I just verified that MATCHES isn't dependent on whether the LHS string is a variable name or not.<br>
<br>I think this is a bug with STREQUAL, so I filed one. <a href="http://public.kitware.com/Bug/view.php?id=8823">http://public.kitware.com/Bug/view.php?id=8823</a><br><br>James<br><br><div class="gmail_quote">On Tue, Mar 31, 2009 at 1:31 AM, Marcel Loose <span dir="ltr"><<a href="mailto:loose@astron.nl">loose@astron.nl</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Hi James,<br>
<br>
Thanks for your reply. I'm going to comment on your remarks inline. But<br>
first, let me explain what I wanted to accomplish.<br>
<br>
My intention is to keep a list of valid CMake options so that I can<br>
iterate over it. It would have been nice if CMake offered another way of<br>
doing this, but I haven't found one. So, that's the reason for having<br>
the foreach() loop; the variable names being identical to options is in<br>
this case intentional!<br>
<div class="im"><br>
On Mon, 2009-03-30 at 11:55 -0600, James Bigler wrote:<br>
> There may indeed be a bug (at least in the documentation).<br>
><br>
> In CMake 'if' statements are a little different than you might think.<br>
> From the documentation of 'if' (cmake --help-command if):<br>
><br>
> if(variable STREQUAL string)<br>
> if(string STREQUAL string)<br>
><br>
> Now with your code you had:<br>
><br>
> foreach(opt ${options})<br>
> message(STATUS "opt = ${opt}")<br>
> if(${opt} STREQUAL fine)<br>
> ...<br>
> endforeach()<br>
><br>
> Now what the expression states is 'if (${opt} STREQUAL fine)' or if<br>
> (fine STRQUAL fine). ${opt} gets replaced by its value and you<br>
> compare 'fine' with 'fine'. It might have appeared to work had you<br>
> used opt instead of ${opt}, but you wouldn't have been able to turn<br>
> the option(fine) on and off. The if statement would have always been<br>
> false.<br>
</div>I agree with the first part of your paragraph, but you've lost me in the<br>
second part. The string should match, that's what I expect, because I<br>
compare the contents of opt to the string "fine". I don't see why I<br>
should have written 'if(opt STREQUAL fine)', because that would IMO have<br>
compared the string "opt" to the string "fine". I also don't see the<br>
connection of the string "fine" with the option fine (since an option is<br>
nothing more than a cached variable of type bool).<br>
<div class="im"><br>
> Things get tricky when the right side of the STREQUAL is a string that<br>
> matches the name of a variable:<br>
><br>
> set(var "stuff")<br>
> set(stuff ON)<br>
> if(var STREQUAL "stuff")<br>
> message("var STREQUAL stuff")<br>
> else()<br>
> message("NOT var STREQUAL stuff")<br>
> endif()<br>
><br>
> According to the docs, I would expect this to return "var STREQUAL<br>
> ON", but it instead returns "NOT var STREQUAL ON", meaning that it<br>
> dereferenced the value of stuff in the if statement rather than<br>
> treating it as a string literal. This is inconsistent with the<br>
> documentation that indicates that right side operator is a string and<br>
> not a variable.<br>
</div>Well, I would expect it to return "var" STREQUAL "ON" which evaluates to<br>
false, and hence the else branch is followed. Are you assuming that var<br>
would be converted to bool, and the string "stuff" to the contents of<br>
the variable "stuff"? I don't think that's how it's supposed to work.<br>
To access the contents of a variable, you need to enclose it in ${}. So,<br>
had you written ${var} STREQUAL ${stuff}, it would translate IMO to<br>
"stuff" STREQUAL "ON" (which also evaluates to false BTW).<br>
<div class="im"><br>
> To get what you want in your code, you need the following:<br>
><br>
> option(fine_on "Fine" OFF)<br>
> option(good_on "Good" ON)<br>
> option(bad_on "Bad" OFF) # This isn't actually used<br>
> foreach(opt ${options})<br>
> message(STATUS "opt = ${opt}")\<br>
> # Only accept opt == fine when fine_on is true<br>
> if(fine_on AND opt STREQUAL "fine")<br>
> message(STATUS "This is fine")<br>
> # Only accept opt == good when good_on is true<br>
> elseif(good_on AND opt STREQUAL "good")<br>
> message(STATUS "This is good")<br>
> # Everything else is bad<br>
> else()<br>
> message(ERROR " This is bad!")<br>
> endif()<br>
> endforeach(opt ${options})<br>
</div>This will probably work, but that's not what I wanted (see above).<br>
However, here you're doing something completely different: you're<br>
creating a boolean expression consisting of a bool on the LHS of AND and<br>
a string comparison (which evaluates to a bool) on the RHS of AND.<br>
<br>
I still think it's a bug in the code, not in the documentation.<br>
<br>
Best regards,<br>
<font color="#888888">Marcel Loose.<br>
</font><div><div></div><div class="h5"><br>
<br>
> James<br>
><br>
> On Mon, Mar 30, 2009 at 4:28 AM, Marcel Loose <<a href="mailto:loose@astron.nl">loose@astron.nl</a>> wrote:<br>
> > Hi all,<br>
> ><br>
> > I am running cmake version 2.6-patch 2.<br>
> > I stumbled over the following, and I think it is a bug.<br>
> ><br>
> > If I run cmake on this CMakeLists.txt:<br>
> ><br>
> > cmake_minimum_required(VERSION 2.6)<br>
> > set(options<br>
> > fine<br>
> > good<br>
> > bad)<br>
> > #option(fine "Fine" OFF)<br>
> > #option(good "Good" OFF)<br>
> > option(bad "Bad" OFF)<br>
> > foreach(opt ${options})<br>
> > message(STATUS "opt = ${opt}")<br>
> > if(${opt} STREQUAL fine)<br>
> > message(STATUS "This is fine")<br>
> > elseif(${opt} STREQUAL good)<br>
> > message(STATUS "This is good")<br>
> > else(${opt} STREQUAL fine)<br>
> > message(FATAL_ERROR "This is bad!")<br>
> > endif(${opt} STREQUAL fine)<br>
> > endforeach(opt ${options})<br>
> ><br>
> > I get the following output:<br>
> > ...<br>
> > -- val = fine<br>
> > -- fine<br>
> > -- val = good<br>
> > -- good<br>
> > -- val = bad<br>
> > CMake Error at CMakeLists.txt:14 (message):<br>
> > bad<br>
> > ...<br>
> ><br>
> > which is to be expected.<br>
> ><br>
> > However, when I uncomment the line option(fine...), I get the<br>
> following<br>
> > output:<br>
> > ...<br>
> > -- opt = fine<br>
> > -- This is fine<br>
> > -- opt = good<br>
> > -- This is good<br>
> > -- opt = bad<br>
> > -- This is fine<br>
> > -- Configuring done<br>
> > ...<br>
> ><br>
> > which is clearly wrong! Uncommenting the line option(good...) yields<br>
> > almost the same output, but now the elseif branch is followed.<br>
> ><br>
> > Is this a bug, or am I overlooking something?<br>
> ><br>
> > Best regards,<br>
> > Marcel Loose.<br>
> ><br>
> ><br>
> ><br>
> > _______________________________________________<br>
> > Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
> ><br>
> > Visit other Kitware open-source projects at<br>
> <a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
> ><br>
> > Please keep messages on-topic and check the CMake FAQ at:<br>
> <a href="http://www.cmake.org/Wiki/CMake_FAQ" target="_blank">http://www.cmake.org/Wiki/CMake_FAQ</a><br>
> ><br>
> > Follow this link to subscribe/unsubscribe:<br>
> > <a href="http://www.cmake.org/mailman/listinfo/cmake" target="_blank">http://www.cmake.org/mailman/listinfo/cmake</a><br>
> ><br>
><br>
> _______________________________________________<br>
> Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
><br>
> Visit other Kitware open-source projects at <a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
><br>
> Please keep messages on-topic and check the CMake FAQ at: <a href="http://www.cmake.org/Wiki/CMake_FAQ" target="_blank">http://www.cmake.org/Wiki/CMake_FAQ</a><br>
><br>
> Follow this link to subscribe/unsubscribe:<br>
> <a href="http://www.cmake.org/mailman/listinfo/cmake" target="_blank">http://www.cmake.org/mailman/listinfo/cmake</a><br>
<br>
</div></div></blockquote></div><br>