Tuesday, 26 February 2008

KRename Video

Peter Upfold from fosswire.com has posted a great video on how to use KRename.

I think this video is great to show how KRename (or any other application) is working. I love the way he made the video: easy to understand and very well commented! Great work Peter!

You can find his article including the links to the video here. The video is available as flash for viewing online or as OGG for download.

Thursday, 21 February 2008

Visualize dependencies of binaries and libraries on Linux

Update2: pfee made some more fixes. The script parses now the dependcies tree correctly using readelf and ldd so that only direct dependencies apear in the graph. The updated version can also be found at dependencies.sh



Update: Thanks to the feedback from pfee, I made some fixes to the script. The script is now also available for direct download dependencies.sh



Sometimes it is useful to know the library dependencies of an application or a library on Linux (or Unix). Especially OpenSource applications depend on lot's of libraries which in turn depend on other libraries again. So it is not always quite clear which dependencies your software has.



Imagine you want to package up your software for a customer and need to know on which libraries your software depends. Usually you know which libraries were used during development, but what are the dependencies of these libraries? You have to package all dependencies so that the customer can use and/or install your software.



I created a bash-script which uses ldd to find the dependencies of a binary on Linux and Graphviz to create a dependency graph out of this information. Benedikt Hauptmann had the idea to show dependencies as a graph - so I cannot take credits for that. Using this script I created the depency graph of TFORMer, the report generator we are developing at TEC-IT. The result is a nice graph showing all the dependencies a user has to have installed before using TFORMer.





Another beautiful graph is the one of PoDoFo. See below the graph of PoDoFo.





The dependencies of Firefox are way more complex than the examples shown above...





If you want to create a graph of your favorite application or library your self, get the script from here. I pulished the simple source code below. Graphviz is the only requirement. Usage is very simple, just pass an application or library as first parameter and the output image as second argument. The script will always create a PNG image:


./dependencies.sh /usr/bin/emacs emacs.png
./dependencies.sh /usr/local/lib/libpodofo.so \
podofo.png



The code of the script is as follows: (Warning: the style sheet cuts of some lines, so better download the script from dependencies.sh)




#!/bin/bash

# This is the maximum depth to which dependencies are resolved
MAXDEPTH=14

# analyze a given file on its
# dependecies using ldd and write
# the results to a given temporary file
#
# Usage: analyze [OUTPUTFILE] [INPUTFILE]
function analyze
{
local OUT=$1
local IN=$2
local NAME=$(basename $IN)

for i in $LIST
do
if [ "$i" == "$NAME" ];
then
# This file was already parsed
return
fi
done
# Put the file in the list of all files
LIST="$LIST $NAME"

DEPTH=$[$DEPTH + 1]
if [ $DEPTH -ge $MAXDEPTH ];
then
echo "MAXDEPTH of $MAXDEPTH reached at file $IN."
echo "Continuing with next file..."
return
fi

echo "Parsing file: $IN"

$READELF $IN &> $READELFTMPFILE
ELFRET=$?

if [ $ELFRET != 0 ];
then
echo "ERROR: ELF reader returned error code $RET"
echo "ERROR:"
cat $TMPFILE
echo "Aborting..."
rm $TMPFILE
rm $READELFTMPFILE
rm $LDDTMPFILE
exit 1
fi

DEPENDENCIES=$(cat $READELFTMPFILE | grep NEEDED | awk '{if (substr($NF,1,1) == "[") print substr($NF, 2, length($NF) - 2); else print $NF}')

for DEP in $DEPENDENCIES;
do
if [ -n "$DEP" ];
then

ldd $IN &> $LDDTMPFILE
LDDRET=$?

if [ $LDDRET != 0 ];
then
echo "ERROR: ldd returned error code $RET"
echo "ERROR:"
cat $TMPFILE
echo "Aborting..."
rm $TMPFILE
rm $READELFTMPFILE
rm $LDDTMPFILE
exit 1
fi

DEPPATH=$(grep $DEP $LDDTMPFILE | awk '{print $3}')
if [ -n "$DEPPATH" ];
then
echo -e " \"$NAME\" -> \"$DEP\";" >> $OUT
analyze $OUT $DEPPATH
fi
fi
done

DEPTH=$[$DEPTH - 1]
}

########################################
# main #
########################################

if [ $# != 2 ];
then
echo "Usage:"
echo " $0 [filename] [outputimage]"
echo ""
echo "This tools analyses a shared library or an executable"
echo "and generates a dependency graph as an image."
echo ""
echo "GraphViz must be installed for this tool to work."
echo ""
exit 1
fi

DEPTH=0
INPUT=$1
OUTPUT=$2
TMPFILE=$(mktemp -t)
LDDTMPFILE=$(mktemp -t)
READELFTMPFILE=$(mktemp -t)
LIST=""

if [ ! -e $INPUT ];
then
echo "ERROR: File not found: $INPUT"
echo "Aborting..."
exit 2
fi

# Use either readelf or dump
# Linux has readelf, Solaris has dump
READELF=$(type readelf 2> /dev/null)
if [ $? != 0 ]; then
READELF=$(type dump 2> /dev/null)
if [ $? != 0 ]; then
echo Unable to find ELF reader
exit 1
fi
READELF="dump -Lv"
else
READELF="readelf -d"
fi



echo "Analyzing dependencies of: $INPUT"
echo "Creating output as: $OUTPUT"
echo ""

echo "digraph DependencyTree {" > $TMPFILE
echo " \"$(basename $INPUT)\" [shape=box];" >> $TMPFILE
analyze $TMPFILE "$INPUT"
echo "}" >> $TMPFILE

#cat $TMPFILE # output generated dotfile for debugging purposses
dot -Tpng $TMPFILE -o$OUTPUT

rm $LDDTMPFILE
rm $TMPFILE

exit 0