The libigl library is a collection of useful/reusable/sharable C++ functions with very few external dependencies. The library may be used as a "headers only" library or a statically linked library.
This duality is illustrated in the example
examples/example_fun
. When built this example compiles two
binaries, one using the example_fun
routine of the igl
library, either as a headers-only library or linking against the igl
static library.
All classes and functions in the IGL library are written in a way in
which the entire library may be compiled just-in-time,
effectively behaiving as if it were a "headers only" library (like e.g.
Eigen). This is achieved by careful organization of each pair of .h and
.cpp files. To take advantage of this one must only include the path to
igl_lib
directory in one's project's include path and
define the preprocessor macro IGL_HEADER_ONLY
.
Defining IGL_HEADER_ONLY
may be done at the project level,
prescribing that all included igl headers be treated as code that
should be inlined. Consequently all templated functions will be derived
at compile time if need be.
One may also define IGL_HEADER_ONLY
not only on a per-file
basis, but a per-include basis. For example it may be useful for a
project to use the static library for most functionality from IGL, but then
include a certain IGL function as an inlined function. This may be achieved
by surrounding the relevant include with a define and undefine of the
IGL_HEADER_ONLY
macro. Here's an example of the little
widget:
...
#include <igl/some_other_igl_function.h>
#ifndef IGL_HEADER_ONLY
# define IGL_HEADER_ONLY
# define IGL_HEADER_ONLY_WAS_NOT_DEFINED
#endif
#include <igl/igl_function_to_inline.h>
#ifdef IGL_HEADER_ONLY_WAS_NOT_DEFINED
# undef IGL_HEADER_ONLY
#endif
#include <igl/yet_another_igl_function.h>
...
example examples/XXX
also highlights this feature
Special care must be taken by the developers of each function and
class in the IGL library that uses C++ templates. If this function is
intended to be compiled into the statically linked igl library then
function is only compiled for each explicitly specialized
declaration. These should be added at the bottom of the corresponding
.cpp file surrounded by a #ifndef IGL_HEADER_ONLY
.
Of course, a developer may not know ahead of time which specializations should be explicitly included in the igl static lib. One way to find out is to add one explicit specialization for each call in one's own project. This only ever needs to be done once for each template.
The process is somewhat mechanical using a linker with reasonable error output.
Supposed for example we have compiled the igl static lib, including the
cat.h and cat.cpp functions, without any explicit instanciation. Say
using the makefile in the igl_lib
directory:
cd $IGL_LIB
make
Now if we try to compile a project and link against it we may get an error like:
Undefined symbols for architecture x86_64:
"Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::cat<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&)", referenced from:
uniform_sample(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, int, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>&)in Skinning.o
"Eigen::SparseMatrix<double, 0, int> igl::cat<Eigen::SparseMatrix<double, 0, int> >(int, Eigen::SparseMatrix<double, 0, int> const&, Eigen::SparseMatrix<double, 0, int> const&)", referenced from:
covariance_scatter_matrix(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, ArapEnergy, Eigen::SparseMatrix<double, 0, int>&)in arap_dof.o
arap_rhs(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, ArapEnergy, Eigen::SparseMatrix<double, 0, int>&)in arap_dof.o
This looks like a mess, but luckily we don't really need to read it
all. Just copy the first highlighted part in quotes, then append it
to the list of explicit templat specializations at the end of
cat.cpp
after the word
template
and followed by a semi-colon.
Like this:
...
#ifndef IGL_HEADER_ONLY
// Explicit template specialization
template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::cat<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&);
#endif
Then you must recompile the IGL static library.
cd $IGL_LIB
make
And try to compile your project again, potentially repeating this process until no more symbols are undefined.
If you're using make then the following command will reveal each missing symbol on its own line:
make 2>&1 | grep "referenced from" | sed -e "s/, referenced from.*//"
Alternatively you can use the autoexplicit.sh
function
which (for well organized .cpp files in the igl_lib) automatically
create explicit instanciations from your compiler's error messages.
Repeat this process until convergence:
cd /to/your/project
make 2>$IGL_LIB/make.err
cd $IGL_LIB
cat make.err | ./autoexplicit.sh
make clean
make
By design the IGL library has very few external dependencies.
Besides the standard C++ library, there are a few dependencies, without which the main library will not compile or work properly. These are:
Certain functions and classes included the IGL library have external dependencies by construction (e.g. the matlab_interface routines are only useful when matlab is present anyway). These are never compiled by default into the static igl library and are only exposed through compiler options. These are:
Eigen's matrix API often makes it fairly to translate to and from matlab code (Eigen provides a translation table). We have implemented a few additional matlab-esque functions to make the translation even easier. Our own translation table shows a list of common matlab functions and their igl-eigen equivalents.
See also: style guidlines, auto-documentation