diff --git a/.gitignore b/.gitignore index 7dcbabc83..dd49e2a49 100644 --- a/.gitignore +++ b/.gitignore @@ -18,5 +18,6 @@ libraries/zenon_modulo *.install *.gv *.png +*.dot .DS_Store *.map diff --git a/tools/depgraph/README.md b/tools/depgraph/README.md new file mode 100644 index 000000000..b8dfddcf8 --- /dev/null +++ b/tools/depgraph/README.md @@ -0,0 +1,22 @@ +This is a temporary shell script generating the ocaml dependency graph. + +-- How it works ? + +1. it gets the dependencies with ``ocamldep ... | grep ...`` +2. it generates the \*.mli from the \*.ml and gets the constants and functions with ``ocamlc.opt -i ... | grep -e "^val"`` +3. it gets the constants and functions in the dependency by greping the sources +4. it generates the dot files with one colour by module dependency + +-- How to use it ? + +1. choose a set of interesting modules : change the interesting_modules variable +2. remove the interesting ``open Module`` in sources so that functions are explicitly called by ``Module.function a b c``. If you don't do it, you will get the graph with the modules (the nodes) and their dependencies (the edges) but you will miss the called functions (label on the edges) +3. the script has to be used after building lambdapi with dune (as it uses the the src/core/.core.objs/byte/\*.cmi files) +4. just call the script : ``./depgraph.sh`` + +-- Why it sucks ? + +1. it's really a build-system (dune) job to generate such things +2. it should be written in ocaml (and using the graphviz library) +3. it doesn't work correctly with submodules +4. it's grep-ing the source instead of using the compiler libs to get the list of defined symbols diff --git a/tools/depgraph/depgraph.sh b/tools/depgraph/depgraph.sh new file mode 100755 index 000000000..49f0f0ed1 --- /dev/null +++ b/tools/depgraph/depgraph.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# shellcheck disable=SC2086 + +set -eu -o pipefail + +# UPPERCASE THE FIRST LETTER OF A WORD +function uppercasefirst () +{ + word=$1 + first=${word:0:1} + firstupper=${first^^} + wordwithoutfirst=${word:1} + echo "${firstupper}${wordwithoutfirst}" +} + +errordirectory="error : non-existing directory" +workingdir=$(pwd) +scriptdir=$(dirname "${BASH_SOURCE[0]}") +lambdapidir=$(cd ${scriptdir}/../.. || { echo $errordirectory ; exit 1; } ; pwd) +graph=graph +graphdot=$workingdir/$graph.dot +graphpng=$workingdir/$graph.png + +# CHOOSE THE INTERESTING_MODULES MODULES +concat_modules="$@" +if [ -z "$concat_modules" ] ; then + interesting_modules=( compile handle infer proof sr tactics typing unif ) +else + interesting_modules=( $@ ) +fi + +# cd $lambdapidir/src/core +# interesting_modules=( ) +# for mlfile in $(ls *.ml) ; do +# if [ $mlfile != parser.ml ] ; then #remove module with ppx/preprocessor extension +# mlfilenoml=$(basename ${mlfile} .ml) +# interesting_modules+=( "$mlfilenoml" ) +# fi +# done + +# COLORSCHEME +backgroundcolor="#252525" +paired12=( "#a6cee3" "#1f78b4" "#b2df8a" "#33a02c" "#fb9a99" "#e31a1c" "#fdbf6f" "#ff7f00" "#cab2d6" "#6a3d9a" "#ffff99" "#b15928" ) +# brbg11 minus the darkest one +brbg11=( "#8c510a" "#bf812d" "#dfc27d" "#f6e8c3" "#f5f5f5" "#c7eae5" "#80cdc1" "#35978f" "#01665e" "#003c30" ) +# piyg11 minus the darkest one +piyg11=( "#762a83" "#9970ab" "#c2a5cf" "#e7d4e8" "#f7f7f7" "#d9f0d3" "#a6dba0" "#5aae61" "#1b7837" "#00441b" ) +colorscheme=( "${paired12[@]}" "${piyg11[@]}" "${brbg11[@]}" "${paired12[@]}" "${piyg11[@]}" "${brbg11[@]}" "${paired12[@]}" "${piyg11[@]}" "${brbg11[@]}" ) + +# GENERATE THE GRAPH TEXT FILE +rm -f $graphdot +echo "digraph g {" > $graphdot +echo "graph [bgcolor=\"$backgroundcolor\"];" >> $graphdot + +icolor=0 +for mldependency in "${interesting_modules[@]}" ; do + mldependencycolor=${colorscheme[$icolor]} + mldependencywithupper=$(uppercasefirst $mldependency) + echo "$mldependencywithupper [style=filled,fillcolor=\"$mldependencycolor\"];" >> $graphdot + for mlfile in "${interesting_modules[@]}" ; do + mlfilewithupper=$(uppercasefirst $mlfile) + if [ $mlfile != $mldependency ] ; then + cd $lambdapidir || { echo $errordirectory ; exit 1; } + mlfiledependsonmldependency=$(ocamldep -modules src/core/${mlfile}.ml | grep $mldependencywithupper) || true + if [ -n "$mlfiledependsonmldependency" ] ; then + cd $lambdapidir/_build/default || { echo $errordirectory ; exit 1; } + mldependencyfunctions=$(ocamlc -i -I src/core/.core.objs/byte -open Core src/core/${mldependency}.ml 2>&1 | grep -e "^val" | grep -v "type t =" | awk '{print $2}' ) || true + cd $lambdapidir || { echo $errordirectory ; exit 1; } + mldependencyfunctioninmlfile=( ) + for function in ${mldependencyfunctions[*]} ; do + present=$(grep $mldependencywithupper.$function src/core/$mlfile.ml) || true + if [ -n "$present" ] ; then + mldependencyfunctioninmlfile+=( "$function\n" ) + fi + done + echo " $mlfilewithupper -> $mldependencywithupper [color=\"$mldependencycolor\",fillcolor=\"$mldependencycolor\",fontcolor=\"$mldependencycolor\",label="\"${mldependencyfunctioninmlfile[*]}\""];" >> $graphdot + fi + fi + done + icolor=$((icolor+1)) +done +echo "}" >> $graphdot + +# GENERATE THE GRAPH +cd $workingdir || { echo $errordirectory ; exit 1; } +dot $graphdot -Tpng -o $graphpng