[Insight-developers] CMake/Cable (EVERYONE PLEASE READ)

Brad King brad.king@kitware.com
Tue, 20 Mar 2001 16:26:53 -0500 (EST)


Hello, all:

One of the problems we have all been having with testing our code is
that not all the code in a template class is necessarily compiled by
our test programs.  Consider the following example:

--------------------------------------------------
template <typename TElement>
class MyVector
{
public:
  typedef TElement ElementType;

  void MyMethod0() {}
  void MyMethod1() { callingNonexistentFunction(); }
};

int main()
{
  MyVector<int> mv; // Implicit instantiation of MyVector<int>
  mv.MyMethod0();   // Only the methods that are called will
                    // be compiled.
  return 0;
}
--------------------------------------------------

This program will compile without error because MyMethod1() is never
instantiated, and therefore its code is not compiled.  However, if
someone else uses MyVector, and tries to call MyMethod1(), they will
get a compiler error even though their own code is perfectly valid.

If, however, there were an explicit instantiation of MyVector<int>,
then MyMethod1() would be compiled, even if it is not called.  An
explicit instantiation would look like "template class MyVector<int>;"
and would produce a compiler error immediately on MyMethod1().

Eventually, we would also like to be able to build explicit
instantiations of ITK classes into the libraries to reduce code bloat.
Writing out dozens of combinations of template arguments to create
these instantiations is time consuming and hard to maintain.  The new
tool "CABLE" I have added to Insight solves this problem, and an
extension to CMake makes it easy to use as part of the build process.

Near the end of last week I checked in changes to Code/CMakeLists.txt,
Code/Common/CMakeLists.txt, and Code/BasicFilters/CMakeLists.txt that
introduce automatic generation of explicit instantiations of template
classes into the Common and BasicFilters libraries.  Now that I have
confirmed that the builds with the instantiations are working on all
of the dashboard's platforms, it is time to announce this so that
everyone can use the new CMake / CABLE features.

--------------------------------------------------

Here is a short tutorial of how to use the CMake-Cable-Command
features.  First off, all control is done in the CMakeLists.txt files
through CMake commands.  All Cable commands in CMake begin with
"CABLE_" to distinguish them from the rest of CMake's commands.

The idea here is to define sets of types that can be used as template
arguments and then use these sets to automatically instantiate various
combinations of template classes.

A set is defined with the CABLE_DEFINE_SET command.  For example

CABLE_DEFINE_SET (BasicType int float long "unsigned short")

defines a set called "BasicType" with members "int", "float", "long",
and "unsigned short".  This set can be referenced in certain other
CMake CABLE_ commands by its name with a '$' in front.  Now
we define a set of specializations of the above "MyVector" class
with each of these basic types.

CABLE_DEFINE_SET (MyVectorType "MyVector<$BasicType>")

This defines a set called "MyVectorType" with the following members:
MyVector<int>
MyVector<float>
MyVector<long>
MyVector<unsigned short>

Now, say we want to actually tell CMake to put explicit instantiations
of MyVector into the library being built.  Assume that we have fixed
the code in MyMethod1() so that it will compile.  Here, I assume that
we defined "MyVector" in the files myVector.h and myVector.txx CMake
will automatically find the file extensions when the source is
specified below.  Now, we add this code to CMakeLists.txt:

# Define the name of the package in which we wish to put the
# instantiations.  This controls the file name with the generated
# code, and must come before any CABLE_INSTANTIATE_CLASS commands.
CABLE_PACKAGE(MyVectors)

# We must tell CMake where to find the source to our template class,
# since it cannot be listed in the regular SOURCE_FILES command.
CABLE_SOURCE_FILES(myVector)

# Create explicit instantiations of the class.
CABLE_INSTANTIATE_CLASS($MyVectorType
                        "MyVector<double>")

This will create a package called "MyVectors" with the following
explicit instantiations:
MyVector<int>
MyVector<float>
MyVector<long>
MyVector<unsigned short>
MyVector<double>

This package will automatcially be compiled and linked into the
library specified in this CMakeLists file.

The above tutorial is just a quick overview of some of the most
basic features in Cable and the CMake extension controlling it.
Code already checked in to the Code/CMakeLists.txt,
Code/Common/CMakeLists.txt, and Code/BasicFilters/CMakeLists.txt
demonstrates much more of the functionality.  To help you read it,
here is a quick description of some of the features it uses:

In a CABLE_DEFINE_SET command, the keyword "SOURCE_FILES" can be used
after the list of set elements.  Any argument after this keyword will
be interpreted as a source file specification.  Any place that
references the set will automatically include the sources specified.

When referencing a set with a '$', the set name is terminated when
a character other than A-Z, a-z, 0-9, '_', or ':' is encountered.
This prevents one from using the members of a set to construct
an identifier.  Alternatively, $(setname) will use all the characters
between the parentheses as the set name.  This allows one to write
something like:

CABLE_DEFINE_SET(digits 0 1 2 3 4 5 6 7 8 9)
CABLE_DEFINE_SET(zeroTo99 "$(digits)$digits")

The set "zeroTo99" will contain "00" "01" "02" ... "97" "98" "99".

--------------------------------------------------

I would like everyone to read the example code already provided in the
CMakeLists files like Code/Common/CMakeLists.txt and add code
to create one instantiation of each of your own template classes.
Feel free to email the list with questions, and I will answer them.
The commands are very flexible and may take some "getting-used-to"
to use them.

We would like to get an explicit instantiation of every template class
in all of Insight so that we are sure all code is compiled for the
dashboard.  These instantiations will be linked into the libraries
where they are defined, and can be used in any test program.  For now,
however, we would like to stick to instantiations using the
ScalarType, PixelType, Dimension, PointType, VectorType, ImageType,
and MeshType sets already defined in Code/CMakeLists.txt.  This means
that filters should only be instantiated as
"MyFilter<$ImageType,$ImageType>" (assuming that MyFilter is templated
over TInputImage, TOutputImage).  However, feel free to define other
sets to shorten your code (look at the "iaFunc" example already
present).

Good luck, and thank you for taking the time to read this,
-Brad


P.S.  In case anyone is wondering what "CABLE" means, it is a
recursive acronym:

CABLE Automates Bindings for Language Extension

Eventually this will become the Tcl/Python/etc wrapping tool.