NAME

SOOT - Use ROOT from Perl

SYNOPSIS

use SOOT ':all';
# more to follow

DESCRIPTION

SOOT is a Perl extension for using the ROOT library. It is very similar to the Ruby-ROOT or PyROOT extensions for their respective languages. Specifically, SOOT was implemented after the model of Ruby-ROOT.

Please note that SOOT is to be considered highly experimental at this point. It uses a very dynamic approach to wrapping a very large and quickly evolving library. Due to the dynamic nature (using the CInt introspection), SOOT is able to handle most of the ROOT classes without explicitly wrapping them. Some things are expected to not work because not enough information about the API can be obtained automatically. Let me know what you need and what is giving you problems and we'll work out a solution.

In order to install and use SOOT, you need a configured ROOT library. In particular, it is necessary that the root-config tool be executable and findable via your PATH environment variable. Alternatively, you may set the ROOTSYS environment variable. Please refer to the ROOT manual for details.

Exports

By default, using SOOT does not export anything into your namespace. You may choose to import the various ROOT-related global variables and/or constants into your namespace either by explicitly listing them as arguments to use SOOT or by importing the :globals, :constants, or :all tags:

use SOOT ':all';
# you now have $gApplication, $gSystem, kWhite etc

use SOOT qw($gApplication $gSystem);
# you now have only $gApplication and $gSystem
# you always have $SOOT::gApplication, etc!

use SOOT qw(kRed kDotted);
my $graph = TGraph->new(3);
$graph->SetLineColor(kRed);
$graph->SetLineStyle(kDotted);

The list of currently supported globals is:

$gApplication $gSystem $gRandom $gROOT
$gDirectory   $gStyle  $gPad    $gBenchmark
$gEnv
$gHistImagePalette $gWebImagePalette

The list of currently exported functions:

Load(className, className2,...)
UpdateClasses()

JUMP-START FOR C++-ROOT USERS

This section outlines the differences between using ROOT from C++ or from Perl via SOOT. If in doubt, the two should behave the same, but there are a few subtle differences that a user must be aware of and these should be documented here. If not, it's a bug.

Note about terminology: When referring to a ROOT object, the underlying C++, TObject-derived object is meant. If the document mentions SOOT objects, that is the Perl-level wrapper object.

Memory Management

ROOT has a fairly complex idea of object ownership which is documented in its own section of the Users Manual. SOOT tries to implement a relatively simple and consistent memory management:

Any object that was created with a constructor is SOOT's responsibility to clean up. All other objects are, by default, not freed by SOOT. That means for objects created with new(), the memory of the underlying ROOT object will be freed when the last Perl-side reference to it goes out of scope. SOOT implements its own reference counting "garbage collection" in that you can create copies of SOOT objects that refer to the same underlying ROOT object and there will be double-freed memory. Examples:

sub test {
  my $graph = TGraph->new(2, [0., 1.], [3., 5.]);
  SCOPE: {
    my $axis = $graph->GetXaxis();
    my $otheraxis = $graph->GetXaxis();
    # $axis and $otheraxis are really the same TObject underneath
  }
  # $axis and $otheraxis cease to exist, but don't free their TAxis
  # objects because that would create a segmentation fault.
}
test();
# $graph won't exist here due to my's lexical scoping.
# $graph will free the memory of the underlying TGraph*!
# This also frees the TAxis and other sub-structures of the graph.

Sometimes, this behaviour is not what you want. You can usually work around any problems by keeping references to objects around so that they're not freed earlier than you would like. Alternatively, you can manually mark objects as being owned by ROOT or SOOT:

# doesn't work because $cv goes out of scope
sub draw_histogram {
  my $hist = shift;
  my $cv = TCanvas->new("cv", "Awesome plot");
  # style histogram and canvas here...
  $hist->Draw();
}
my $histogram = ...
draw_histogram($histogram);
# $cv out of scope!

# Workaround 1: Pass around references.
sub draw_histogram2 {
  my $hist = shift;
  my $cv = TCanvas->new("cv", "Awesome plot");
  $hist->Draw();
  return $cv;
}
my $histogram = ...
my $canvas = draw_histogram($histogram);

# Workaround 2: Mark canvas object as global
sub draw_histogram3 {
  my $hist = shift;
  my $cv = TCanvas->new("cv", "Awesome plot")->keep;
  $hist->Draw();
}
my $histogram = ...
draw_histogram($histogram);
# $cv is gone, but the TCanvas is held by ROOT.
# If necessary, you can get it again via $gROOT:
my $same_cv = $gROOT->FindObject('cv')->as('TCanvas');
# ...
# Later, you can manually delete an object:
$same_cv->delete; # deletes the UNDERLYING ROOT object, too!

The above examples introduce three methods for manual memory management that are useful enough to highlight them again: keep() marks a SOOT object as a global, that is, ROOT will hold on to the underlying TObject even if all SOOT references to it have been garbage collected. keep() will return the same SOOT object it was called on, for convenience.

In order to gain access to a ROOT object that is no longer accessible via SOOT, you can use the usual FindObject('name') method of the TROOT class via the $gROOT (or $SOOT::gROOT) global. This highlights an important detail about the ROOT wrapper: FindObject returns a generic TObject*. In C++, you would cast it into a TCanvas*:

TCanvas* same_cv = (TCanvas*)gROOT->FindObject('cv');

In the context of SOOT, explicit casting is done with the as('Typename') method:

my $same_cv = $gROOT->FindObject('cv')->as('TCanvas');

as('Typename') returns a copy of the SOOT object it is called on with a new type. Finally, the delete() method forcefully deletes a ROOT object and all of its SOOT wrappers. It is possible to use this to crash the program, so beware and use it sparingly.

Object Behaviour

Some operations are overloaded for all SOOT objects. Currently, you can use the == comparison to check whether two SOOT objects refer to the same ROOT object:

my $graph1 = TGraph->new(2, [1., 2.], [3., 4.]);
my $graph2 = TGraph->new(1, [4.], [8.2]);
my $g1_copy = $graph1; # actually a shallow copy...

say '$graph1 and $g1_copy are the same'
  if $graph1 == $g1_copy;

say '$graph1 and $graph2 are the same'
  if $graph1 == $graph2;

This will print:

$graph1 and $g1_copy are the same

Availability of ROOT Classes

By default, SOOT loads most of the available ROOT classes and wraps them for use in Perl. If some class is not available, you may try to load it as follows:

SOOT::Load( qw(TSomeClass TAnotherClassILike) );

Load will automatically try to load the specified classes' base classes as well. In future, it might be extended to inspect the class members and load any other ROOT classes that are part of its interface.

If you want to use classes from a shared library that is not loaded by default, everything should work if you do the following:

$gSystem->Load('libGeom.so');
$gSystem->Load('libGeomBuilder.so');
SOOT::UpdateClasses(); # Bind ALL new classes

Alternatively you may bind only what you need:

$gSystem->Load('libGeom.so');
$gSystem->Load('libGeomBuilder.so');
SOOT::Load('TGeoMaterial'); # or whatever

Updating all classes may be a relatively slow operation. A third approach is using the special TSystem::LoadNUpddate method which is not part of the normal ROOT interface:

$gSystem->Load('libGeom.so');
$gSystem->LoadNUpdate('libGeomBuilder.so');

LoadNUpdate() will bind any new classes if the library was loaded successfully and wasn't loaded before.

FUNCTIONS

Load

Loads one or more ROOT classes and their base classes into Perl. Virtually all ROOT classes should be loaded out of the box. This function is only necessary if you load additional shared libraries.

UpdateClasses

After loading non-standard shared libraries that provide ROOT-based classes, it may be necessary to update the Perl-bindings for those classes. You may either use Load() if you know which exact classes you want to bind, or you may call SOOT::UpdateClasses() to check the whole ROOT class table for classes that were previously not available to Perl.

INSTALLATION

Eventually, SOOT might be shipped with ROOT. Until that happens, you need to do the following: Set your ROOT paths as usual. Make sure the root-config program is available and executable via the PATH.

Then build SOOT like any other CPAN module. To install a release from CPAN, type:

sudo cpan SOOT

To do so manually, do:

tar -xzf SOOT-0.XX.tar.gz
cd SOOT-0.XX
perl Makefile.PL
make
make test
(sudo make install)

Without installing, you may run the SOOT examples from the SOOT directory where you just typed make as follows:

perl -Mblib examples/Hist/hstack.pl

The -Mblib indicates that perl should preferably load modules from the blib (read: build-library) directory of the current directory which contains the uninstalled SOOT library.

NOTE: At this point, SOOT requires a copy of ROOT that has been configured with the --enable-explicitlink option, which -- sadly -- isn't the default.

SEE ALSO

http://root.cern.ch

SOOT::API exposes some of the underlying SOOT-internals.

SOOT::Struct allows for run-time creation/compilation of ROOT/C-level structs. Structs created this way are available from Perl.

SOOT::App implements a root.exe/CInt-like front-end using Devel::REPL. It is not part of SOOT and is available separately from CPAN.

ACKNOWLEDGMENTS

Eric Wilhelm and David Golden put up with my stupid questions about Module::Build and always stayed civil and helpful. Thanks for that!

AUTHOR

Steffen Mueller, <smueller@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2010 by Steffen Mueller

SOOT, the Perl-ROOT wrapper, is free software; you can redistribute it and/or modify it under the same terms as ROOT itself, that is, the GNU Lesser General Public License. A copy of the full license text is available from the distribution as the LICENSE file.