In order to know how to execute a tool and how to interpret its output,
benchexec
needs a tool-specific Python module
with functions for creating the appropriate command-line arguments for a run etc.
(called "tool info").
BenchExec already provides such ready-to-use modules for some common tools.
If your tool is in that list, you do not need to do anything special.
Simply use the name of the tool-info module (without .py
suffix)
as the value of the tool
attribute of the <benchmark>
tag.
Note that BenchExec needs to be able to find the executable of the tool, of course.
The easiest way to achieve this is to specify the directory of the tool
with the parameter --tool-directory
on the command line.
If this parameter is not given,
BenchExec searches in the directories of the PATH
environment variable
and in the current directory.
Thus one can also execute BenchExec directly inside the directory of the tool,
or adjust PATH
accordingly:
PATH=/path/to/tool/directory:$PATH benchexec ...
To debug problems if BenchExec cannot find your tool, use our test utility described below.
For tools that are not supported out-of-the-box by BenchExec, the tool info needs to be defined. This is typically just a few lines of Python code. If you write such a module, please consider sending us a pull request with it such that we can include it in BenchExec.
Tool-info modules need to define a class named Tool
that inherits from one of the classes in the module benchexec.tools.template
.
For compatibility with older tool-info modules, several such classes exist,
but new tool-info modules should inherit from the latest class,
benchexec.tools.template.BaseTool2
(for updating older tool-info modules, cf. our
migration guide) at the end of this document.
The template
module also contains the full documentation
on how to write such a tool-info module.
In the following we provide a short summary.
You can also look at the other existing tool-info modules to see examples.
A minimal tool info needs to overwrite the functions executable
and name
.
If the tool gives true
/ false
answers or customized errors should be shown,
the method determine_result
needs to be overwritten.
It is recommended to also overwrite the function version
if the tool has a version
that can be automatically extracted.
A Python doc string (example)
should be added to the Tool
class with some short description of the tool.
In this doc string there should also be any additional information about the tool-info module,
such as its supported features
or whether it adds or requires certain command-line parameter of the tool.
It is also recommended to overwrite the function project_url
if the tool has a webpage.
Overwrite the functions cmdline
and working_directory
, and environment
to adjust the respective values, e.g., to add the name of a given property file
to the command-line options.
Overwriting the function get_value_from_output
will allow you to add
<column>
tags with custom values to your table-definition files,
and table-generator
will extract the respective values from the output of
your tool using this function.
If a tool-info module encounters a request that it cannot handle
(e.g., because a tool does not support runs without property files,
but no property file was given),
the tool-info module should raise benchexec.tools.template.UnsupportedFeatureException
with an appropriate message for the user.
Note that the tool-info module itself and any commands it starts
will be executed in its own container similar to the actual runs
(except if --no-container
is used).
This means that the tool-info module typically has no network access
and that any changes made to files will not be seen by the actual runs.
The name of the tool-info module needs to be given to benchexec
as the value
of the attribute tool
of the tag <benchmark>
of a benchmark-definition file
(note that runexec
does not use tool infos).
Any of the supplied tool infos can be referenced
with its simple name (file name without .py
suffix).
If you have checked out BenchExec from source and added your tool info
to the benchexec/tools/
directory, also use the simple name.
If you have put your tool info as a module somewhere else on the Python search path,
you must specify the full name of the Python module including its package(s).
Note that tool-info modules that are not in a package are not supported.
In order to allow testing a tool info (either self-written or supplied with BenchExec) and your installation (i.e., whether BenchExec can find your tool), we provide a small utility that uses a given tool info just like it would be done during benchmarking, and prints all the information provided by the tool info, for example which executable is used and in which path it lies, how the command line is constructed etc.
To execute this utility, run
python3 -m benchexec.test_tool_info <TOOL> [--debug] [--tool-output <OUTPUT_FILE>] ...
<TOOL>
is the name of a tool-info module
as it would be given in the tool
attribute of the <benchmark>
tag.
If necessary, change to the appropriate directory or adjust PATH
as described above.
The optional flag --tool-output
activates testing of the function determine_result
that should analyze the tool output.
If specified, this option needs to be given at least one file with example output of the tool.
If the utility runs successfully and its output looks sane (i.e., correct paths, command line, etc.), then BenchExec should also be able to successfully run the tool.
If you have installed BenchExec successfully, the following command
should work and print information about the fake tool dummy
supplied with BenchExec:
python3 -m benchexec.test_tool_info dummy
If container mode is not working on your system,
adjust the directory modes as necessary or add --no-container
.
If you have written your own info for a tool foobar
as a Python module named tools.foobar
(this means you have created a directory tools
with an empty file __init__.py
and a file foobar.py
with the tool info), the following command tests it:
python3 -m benchexec.test_tool_info tools.foobar
This assumes that the package tools
is already in your Python search path,
for example because it is inside the current directory.
If not, you can extend the search path by specifying the parent directory
of the package directory in the PYTHONPATH
environment variable.
It is recommended to upgrade tool-info modules that do not yet inherit from BaseTool2
in order to be able to take advantage of new features like --tool-directory
.
Upgrading should be straight forward in most cases
because the general structure of the APIs defined by BaseTool
and BaseTool2
is the same.
The following assumes familiarity with the API of BaseTool
and explains the differences of BaseTool2
,
it can serve as a step-by-step migration guide.
Everything not mentioned does not need to be changed.
- General remarks: Tool-info modules should not rely on any part of BenchExec
except for what is defined within the
BaseTool2
class and the necessarybenchexec.result.RESULT_*
constants. Everything else is subject to change. In particular,benchexec.util
should no longer be imported. - Class definition: The tool-info module's class now needs to inherit from
benchexec.tools.template.BaseTool2
. - Method
executable
: This method now has one parameter,tool_locator
. Instead of callingbenchexec.util.find_executable()
, calltool_locator.find_executable()
. If the executable is expected in a subdirectory likebin
, pass the executable name on its own and use the parametersubdir
(Example:tool_locator.find_executable("foo", subdir="bin")
instead ofutil.find_executable("foo", "bin/foo")
.) If the executable cannot be found,executable
should raiseToolNotFoundException
now (tool_locator.find_executable()
does that automatically). - Method
cmdline
: Previously it was common to have default values for some parameters, this is no longer recommended.- The parameters
tasks
andpropertyfile
have been replaced with one parametertask
that contains an instance ofBaseTool2.Task
. An exact replacement oftasks
islist(task.input_files_or_identifier)
, though many tool-info modules can usetask.input_files
instead to automatically fail if the current task has no input files. The property file is available astask.property_file
. - Task-definition files can now contain additional arbitrary information
in a key named
options
. Whatever is contained in this key is passed to the methodcmdline
astask.options
, whereas the parameteroptions
continues to contain the parameters defined in the benchmark definition within<option>
tags. - The parameter
rlimits
is now a proper object instead of a dict, cf. documentation ofBaseTool2.ResourceLimits
.
- The parameters
- Method
determine_result
: There is now only a single parameterrun
that contains an instance ofBaseTool2.Run
.- The command line of the run is now available as
run.cmdline
. - The parameter
returncode
was replaced byrun.exit_code.value
, which isNone
instead of0
if the tool was terminated by a signal. - The parameter
returnsignal
was replaced byrun.exit_code.signal
, which isNone
instead of0
if the tool terminated itself. - The parameter
output
was replaced by an instance ofBaseTool2.RunOutput
inrun.output
. This is still a sequence of strings, but without line separators, so callingstrip()
while iterating through it is often no longer necessary and code like"result line" in run.output
works as expected.RunOutput
also has additional utility methods. - The parameter
isTimeout
was replaced byrun.was_timeout
, but more information is now available asrun.was_terminated
andrun.termination_reason
.
- The command line of the run is now available as
- Method
get_value_from_output
: The parameterlines
(list of strings with line separators) was replaced by the parameteroutput
that contains an instance ofBaseTool2.RunOutput
(list of strings without line separators plus utility methods) like fordetermine_result
.