Why does CMake syntax have redundant parentheses everywhere? - syntax

CMake's ifs go like this:
if (condition)
...
else if (...)
...
else (...)
...
endif (...)
With else if (...) the (...) tests for a separate condition.
Why else (...) and not just else? Why endif (...) and not endif?
Cmake's functions go like this:
function(funcname ...)
...
endfunction(funcname ...)
Why endfunction(funcname ...) and not simply endfunction?
I can omit the contents of the redundant parenthesis where they appear, like so: endif (). What's the purpose of this construct?

I believe the initial intention was that, by repeating at each clause (for example, else statement) the initial expression (for example, the one at the if statement) it would make more clear which statement was actually closed, and the parser could verify and warn nothing wrong was going on.
However, it turned out that you would have expression like:
if (VARIABLE matches "something")
[...] #This is executed when above condition is true
else (VARIABLE matches "something") #Looks very much like an elseif...
[...] #This is executed when above condition is false!
endif (VARIABLE matches "something")
Which turned out to be confusing. I am speaking about my every day experience, e.g. I write something and somebody else come to ask me "What does this does?"
So, now CMake allows also to put empty parenthesis, the above can be rewritten as:
if (VARIABLE matches "something")
[...] #This is executed when above condition is true
else ()
[...] #This is executed when above condition is false
endif ()
Which can be considered clearer. The grammar above can still be used.
To completely answer to your question, the parenthesis stay also with empty arguments because conceptually else and endif in CMake are macros like if, and therefore they are invoked with this grammar, a little bit (but not at all exactly) as functions.
Basically the same explanation is available in CMake FAQs: Isn't the "Expression" in the "ELSE (Expression)" confusing?.
To add a little bit of history, in CMake 2.4 repeating the expression was obligatory, and still in CMake 2.6, at least according to the documentation. The documentation was ambiguous on else, but adamant on endif:
Note that the same expression must be given to if, and endif.
The first try to remove this constraint was introduced already with CMake 2.4.3 (year 2006), where it was possible to deactivate it by writing:
set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
This constraint became fully optional with CMake 2.8
Note that the expression in the else and endif clause is optional.

Related

BASH/SH/ .. AutoConf: Wrapping string comparison

I am modifying a configure.ac for use with AutoConf: http://mathpad.wikidot.com/acousto-configure-ac
The script points out that it needs to run on darwin, solaris, cygwin and linux.
I assume this is why it uses an arcane method of comparing strings:
foo="1"
if test "x$foo" != "x0"; then
This double negative makes it difficult to read through the code. Can I clean it up?
How might I implement a string comparison macro:
if STR_EQUAL( $foo, "1" ); then
Or:
if TRUE( $foo ); then
And this is the best way of solving the problem?
EDIT: apparently this script is written in M4 http://www.gnu.org/software/m4/manual/m4.html
For shell portability, you really should be wrapping as much as possible in M4sh macros. There's some special considerations for writing portable shell code in autoconf, and that's why the code looks so arcane.
That being said, there's no restriction on cleaning up confusing code:
foo="1"
AS_IF([test "x$foo" = "x1"], [...])
This page tells why there's leading x in this test statement. In this case you could get away without it, if you want.
Using expr should be portable (and readable) enough:
if expr $foo; then
#do something
fi
If you want to eliminate the output from expr, say: if expr $foo >/dev/null; then
Using test requires some odd constructions to handle ancient shells. If you don't care about those shells, you can use AS_IF and a straightforward test, but if you don't care about portability you probably shouldn't be bothering with autoconf. It is probably slightly cleaner to use AS_CASE, IMO:
AS_CASE($foo,[1], [...], [...default commands (if $foo != `)])

Why Does TCL Give me an Error if I forget to close an open brace '{ ' using a closing brace '}'

Well I do not have much experience with tcl but while i was writing a few test cases today all of a sudden the complier kept saying Missing '}' and i had to go through like atleast 50 to 60 brace pairs to make sure all were right, and after spending about 1.5 hours on this mistake it was really annoyed to find out that i forgot to close my comment with a '}'
so the following is the code in my comment
#test XmlDAOTest-1.15 {Test XmlDAO - method - 'ProcessCDATASectionNode'\
So if you see, i have commented the line and i did not close it with the '}' because comments are not supposed to be compiled and checked for syntax, only after i appended a '}' after the '\' the compiler gave me the result. I am using the following
IDE - Eclipse Indigo Version of Tcl - Tcl/Tk 8.5 with tclOO
Version: Indigo Service Release 2 Tcltest, tDom all included
Build id: 20120216-1857
I want to know if this is a Flaw on the side of the IDE or is it inherent to TCL/Tk and if it is a problem in TCl are there anymore like these that you have encountered.
The '\' at the end of the line is also a continuation marker, so it could be pulling the next line into the comment.
e.g.
#puts "1";\
puts "2";
puts "3";
Will output 3 because the 2nd line is treated as part of the comment.
The issue you are seeing is due to Tcl, not your IDE. That being said, it's not a "problem" with Tcl, just an artifact of how the code is parsed. In Tcl, the has symbol only starts a comment in places where it would be valid to start commands and, as such, comments need be parsed at the same time as the rest of the code. Since the code is not "preprocessed" to remove comments, the quotes and braces need to be balanced.
To give you an example of why the parsing is done this way:
set x #abc
In the above line, the value of x is #abc. If comments were preprocessed, the above would convert to just set x and the rest would disappear.
Along the same lines, and another place many people get bitten by with comments:
switch -exact -- $myvalue {
# this is not a comment
"a value" { do something }
"another value { do something }
}
In the above, #, is, and a are all switch cases; you can also look at it this way (which is the same thing)
switch -exact -- $myvalue {
"#" { this }
"is" { not }
"a" { comment }
"a value" { do something }
"another value" { do something }
}
The reason for this is that the inside of a switch statement, where it's looking for case values, is not a valid place for a command. As such, the # is just a normal character the same as any other.

Modelica conditional printing (for debugging)

In Modelica, is it possible to have an if-condition and a command in one line?
(Of course it is possible to write it in three lines, but I would prefer it in one line.)
Something like:
Boolean verbose;
...
if verbose then Modelica.Utilities.Streams.print("iteration steps " + String(iter), "printlog.txt");
What is wrong with the code you wrote? Only thing I find missing is the end if.
if cond then print(str, file); end if;

Makefile syntax $(A,B,C)?

Consider the following code:
$ANIMAL = COW PIG CHICKEN VAMPIRE
all:
#echo $(ANIMAL, F, >.txt)
I strove to find a section in GNU make manual that mentions the above syntax, but I couldn't find anything related to it. What does it print and how is the syntax structured for the functionality?
Added: When a line starts with "#--" what does it mean?
#-- $(GEN_ENV); ...
To answer your addition: In regular Makefiles (read: POSIX, GNU, ...)
a leading '#' supresses echoing of the command.
a leading '-' says to ignore a non-zero exit status
both can be combined, and repetitions are okay, so #---###-#---echo foo is the same as #-echo foo
This is called "macro modifiers". This is not a GNU make feature. Take a look at this chapter of OPUS make tutorial. The general syntax of these modifiers:
$(name,modifier[,modifier]...)
name is macro expanded, then each modifier is applied in succession to the elements of the expanded value.
Take a look then at the list of modifiers and it becomes clear that it forms a list of file names (truncates paths of each variable in ANIMAL) with .txt added. So, in your case it shoud output:
COW.txt PIG.txt CHICKEN.txt VAMPIRE.txt
PS
I looked through the reference mentioned above and don't think the first line ($ANIMAL = ) is correct since macro definition should start without $.
Based on your comments it seems you are actually using OpusMake, rather than GNU make. You can find more information about it on the Opus Software, Inc. website, and also in this handy reference guide. From those sources you can see that you have an example of a macro employing macro modifiers in its expansion.
Generally speaking $(FOO) is expanded to the unmodified value of the variable FOO, while $(FOO,mod1[,mod2[,...]]]) expands to the value of FOO, modified according to the modifiers you specify. Note that you can string together any number of modifiers, and they will be applied in left-to-right order.
There's a ton of possible modifiers, but your example specifically uses two:
The F modifier, which means "use just the final path component of each pathname in the variable value"
The >str modifier, which means "append the text str to each space-separated word in the value".
Here's a quick example:
FOO=abc/def ghi/jkl
BAR=$(FOO,F)
BAZ=$(FOO,>.txt)
BOO=$(FOO,F,>.txt)
BAR will have the value def jkl (ie, just the filename portion of each path).
BAZ will have the value abc/def.txt ghi/jkl.txt (ie, append .txt to each space-separated word in the value)
BOO will have the value def.txt jkl.txt (ie, first take just the filename portion of each path, then append .txt to each)

trying to find a file/line for: .(eval):289: warning: don't put space before argument parentheses

So, I get this warning when I'm running my tests in ruby/RoR
.(eval):289: warning: don't put space before argument parentheses
I've checked every where (but obvoiusly not) and I can't find the origin of this error.
The above error just pops up inbetween the unit tests ...
Can someone clue me in onto how to find the location of this error?
The file and line number are contained in the backtrace. However, in your case, the warning is inside a string being evaled at runtime. Which means there is no file. (Actually, the eval method does take optional arguments for the file name and line number that should be displayed in a backtrace, but in this case whoever wrote the code in question unfortunately forgot to pass those arguments.)
I fear that you have no other choice than to manually examine every single call to eval in your entire codebase, and that includes Rails, your testing framework, your entire application, your tests, your plugins, your helpers, the ruby standard library, ...
Of course, you should be aware that the problem might not be obvious as in
eval 'foo (bar, baz)'
It could also be something like
def foo(*args)
puts args.join
end
bar = 'Hello'
baz = 'World'
foostr = 'foo' # in one file
barstr = 'bar' # in another file in a different directory
bazstr = 'baz' # in another file in a different directory
argstr = "(#{barstr}, #{bazstr})" # in yet another file
$, = ' ' # in some third-party plugin
str = [foostr, argstr].join # in a fourth file
eval str # somewhere else entirely
eval str, binding, __FILE__, __LINE__ # this is how it *should* be done
Note the difference between the two warning messages: the first one reads exactly like the one you posted, but the second one has the filename instead of (eval) and the line number inside the file instead of the line number inside the eval string.
By the way: the line number 289 in the warning message is the line number inside the evald string! In other words: somewhere in your application there is a string being evald, which is at least 289 lines long! (Actually, it is more likely that this done not in your application but rather in Rails. The Rails router used to be a particularly bad offender, I don't know if this is still the case.)
It sounds to me that there is a rule which forbids a space between a function name and the parentheses enclosing the arguments of the function.
In many languages this would be considered a permissible stylistic variation.
Is the eval mentioned in the warning message, the 'function' being complained about?
Does the number 289 mean anything as a line number?
Could you search your source files for a parenthesis preceded by a space?
Incidentally, the message says warning. What happens if you ignore it?
If it's happening in between the unit tests it might be in a setup or teardown method. Try searching for eval or try reducing the code you are running until the error goes away. Then you'll know where to look (the code you just removed).

Resources