[CMake] CMake with Lua Experiment

E. Wing ewmailing at gmail.com
Tue Nov 27 22:13:16 EST 2007


I think you are misinterpreting some things about the Lua syntax.

The heart and soul of Lua is the 'table'. It is *the* data structure
in Lua. A table is an hash or associative array. But in Lua, a table
can also be an array. There are some very interesting optimizations
under the hood that make sure both array and hash usage are extremely
fast (demonstrated by real world use and benchmarks).

So when you say 'list', think of a table in Lua.

Your example gets into some syntactic sugar:
cm_add_library{"simpleLib", "STATIC", "simpleLib.cxx", "simpleCLib.c",
"simpleWe.cpp"}

This is actually just syntactic sugar for a function call without the
parenthesis that takes one table parameter that is inlined using the
table constructor syntax:

First add back the parenthesis for the function call:

cm_add_library( {"simpleLib", "STATIC", "simpleLib.cxx", "simpleCLib.c",
"simpleWe.cpp"} )

Then, pull out the inline:
my_table = {"simpleLib", "STATIC", "simpleLib.cxx",
"simpleCLib.c","simpleWe.cpp"}
cm_add_library(my_table)

These are all equivalent.


As you discovered Lua supports varargs. Lua is also dynamic so you can
check the types of the arguments passed in. This would allow you to
group things in different ways, allowing people the control of
deciding what is more natural.

So we can compare to our original call:
sources = {"simpleLib.cxx", "simpleCLib.c", "simpleWe.cpp"}
cm_add_library( "simpleLib", "STATIC", sources)

This is passing two string parameters, and a table containing the
sources. I think it is more natural to have a separate list/table for
sources, rather than combining it into one giant table as above. But
it is certainly possible to handle both cases.

We could also inline the thing like:
cm_add_library( "simpleLib", "STATIC", {"simpleLib.cxx",
"simpleCLib.c", "simpleWe.cpp"})
which is identical to the above.

Or we could exploit the varargs capability and not even use a table
and just list things one by one:
cm_add_library( "simpleLib", "STATIC", "simpleLib.cxx",
"simpleCLib.c", "simpleWe.cpp")

This is actually what unpack(sources) was doing. Unpack was basically
flattening/unpacking the table and passing each element in the table
as a separate parameter. Lua's varargs ability automatically kicks in
and unrolls the thing. As I said,  the use of unpack() was
unnecessary.


Lua can also do other some interesting things besides tables. Like
most other languages, you could also invoke a function call.

-- Return a table containing the sources
function GetSources()
	return { "simpleLib", "STATIC", "simpleLib.cxx", "simpleCLib.c",
"simpleWe.cpp" }
end
cm_add_library( "simpleLib", "STATIC", GetSources())


Lua supports multiple return arguments too so one could return all the
elements instead:
-- Instead of returning 1 table, return 3 strings
function GetSources()
	return "simpleLib", "STATIC", "simpleLib.cxx", "simpleCLib.c", "simpleWe.cpp"
end
cm_add_library( "simpleLib", "STATIC", GetSources())


You can also inline functions and make them anonymous:
cm_add_library( "simpleLib", "STATIC", function () return "simpleLib",
"STATIC", "simpleLib.cxx", "simpleCLib.c", "simpleWe.cpp" end )

(Quick note, for demonstration purposes, here we are actually passing
the function reference, not invoking unlike the previous examples.
cm_add_library could then detect the type is a function and invoke it
for us. To invoke it, add () right after 'end'.)

You can also use function pointers/objects/closures.

function GetSources()
	return "simpleLib", "STATIC", "simpleLib.cxx", "simpleCLib.c", "simpleWe.cpp"
end
my_function = GetSources
cm_add_library( "simpleLib", "STATIC", my_function)

(Again, I am not invoking the function, and it could be invoked by
cm_add_library. Do my_function() to invoke.)

Obviously, you might have different criteria to decide what
my_function actually represents. (Maybe Windows and Linux have
different sources.)



Closures can get very interesting because you can inject the
appearance of state into your function calls. This would probably only
be used by people in very specific circumstances. One random thought
is maybe you have some file generation stuff going on in your build
system, and with every call of my_function, you need to increment a
unique number suffix to the a file. (See newCounter example at
http://www.lua.org/pil/6.1.html).



> That paradigm is crippled with respect to FOREACH and LIST style processing.

I'm not completely sure what you are after here, but Lua also has a
for/foreach construct for tables so you can use that too. And it is
potentially very powerful because you can write your own iterator
functions/criteria.


An additional thought is to export global constants (variables), so we
can basically create keywords. So instead of:
cm_add_library( "simpleLib", "STATIC", sources)
we could drop the quotes around STATIC:
cm_add_library( "simpleLib", STATIC, sources)
(We also might consider namespacing the keywords: CM.STATIC.)

> 3.6. Why is SCons written for Python version 1.5.2?

That's an interesting and legitimate point. With Lua, though, the
issues are a little different. If CMake adopts Lua, then it should be
embedded with CMake (especially since it is not standard with Windows
and Mac). Because you embed Lua, the CMake authors have complete say
on which version is used and is not influenced by what the most
popular Linux distro has installed and is available to the masses. So
CMake has final discretion over which version is used.

As for the Lua community, I wouldn't expect abandonment if you froze
on Lua 5 while a hypothetical Lua 6 was very mature. However, you may
hear lots of requests to upgrade if there was a new killer language
feature that made things easier. But as merely a scripting API to
CMake, I wouldn't expect there to be many language features that are
invented that most users would care about. More likely I think, the
CMake authors will see something new in the Lua-C API that makes
things easier and they might want to upgrade. And I would say to most
outsiders, seeing Lua 5 used instead of Lua 6 is still a much less
significant deal than users having to worry about learning CMake
script and also dealing with their own version changes (1.8 vs 2.0 vs
2.2 vs 2.4 etc).


More information about the CMake mailing list