Provided by: makepp_184.108.40.206-2_all
makeppgraph -- Graphical analysis of the dependency graph
?: -?, A: -A, --args-file, --arguments-file, B: -b, --because, --build-reasons, C: &cwd, D: -D, -d, --dependencies, &dir, --dot, --down, --downwards, G: -g, --graphviz, H: -h, --help, &home, --html, I: -I, -i, --include, --include-dir, --includes, L: -l, --log, --log-file, M: -M, -m, &makepp, $MAKEPPGRAPHFLAGS, --merge, --module, O: -o, --output, P: -p, --plain, R: -r, --rename, S: -s, --separate-directions, &suf, T: -t, --text, U: -u, --up, --upwards, &usr, V: -V, --version makeppgraph [ option ... ] [ pattern ... ] mppg [ option ... ] [ pattern ... ] They say "A picture is worth a thousand words". So let's draw your dependency or include graph from various viewpoints. Check out the gallery <http://makepp.sourceforge.net/gallery/> to get some ideas of what you can do. Each node represents a source file or a target, colored according to file name patterns. A file's node is rectangular. A phony target's node is oval. Each solid edge represents a direct dependency. Alternately or additionally you can display include relationships as dotted lines. For a more detailed but not so pretty textual view see makepplog. But beware, even for a small build the complexity can be staggering! This is because with .o files and system includes you easily have twice as many nodes as source files. But that is nothing -- the number of edges often far exceeds that of nodes, due to multiple include statements. A crossing-free layout is usually impossible. In real projects the complexity becomes insane. Techniques like template based source file generation, preprocessors (e.g. embedded SQL, interface definition languages, Qt library) or publishing of files to central directories (e.g. to have only one "-I" or "-L" option) make the graph explode. Even if edges are just one pixel wide, you end up with broad black stripes of criss-crossing edges. Once you realize what really goes on, if you're lucky, you may be able to find a way of simplifying your build setup. But before you get there, you must drastically reduce the amount of information you display. To that end there are various selection, renaming and merging possibilities in "makeppgraph". When you fail to strike a balance between reducing the graph so far that it becomes sensibly displayable, while still showing what you want to see, you may fall back to a textual graph.
If you give no patterns, makeppgraph will start operating with all the nodes it can extract from makepp's log. When given one or more patterns (using "?", "*", "**" and/or "[...]"), it will match those in the file system and operate on any that also occur in the log. For these it will by default select "upwards", i.e. all targets that depend on and/or include any of them and "downwards", i.e. all targets and/or sources, which any of them depends on and/or includes. (The directions are metaphorical, because the graph is best displayed from left "top" to right "bottom" due to the width of the nodes.) -A filename --args-file=filename --arguments-file=filename Read the file and parse it as possibly quoted whitespace- and/or newline-separated options. -b --because --build-reasons If a node was rebuilt because of a dependency, then that edge is shown in red. Alas makepp applies optimizations to detect when a target needs rebuilding, such that it often can't say which file triggered the rebuild. If the node was rebuilt for a reason not attributed to another file, then the node's border is red. With uDraw(Graph) a double border is used instead, as it doesn't support border color. -D --dependencies Draw a graph of the dependency relationship determined by makepp. This is the default unless "-i, --includes" is also given. -d --down --downwards This option is only meaningful if you provide one or more patterns. It will then only select the targets and/or sources which the matched files depend on, or which they include. -g --graphviz --dot Produce a Graphviz .dot file, instead of the default uDraw(Graph) .udg file. -h --html Produce a browser .html file, instead of the default uDraw(Graph) .udg file. -? --help Print out a brief summary of the options. -I directory --include=directory --include-dir=directory Add directory to Perl load path @INC. -i --includes Instead of dependencies (or with "-D, --dependencies" additionally to them) draw a graph of include relationships. This will only have been logged as far as it needed to be analyzed. To get the full picture you need a fresh full build. -l filename --log=filename --log-file=filename The filename is to where makepp wrote its log. It may also be a directory, in which a file called .makepp/log or log will be searched. To read from stdin, you must give - as a filename. When this option is not given, it defaults to the current directory. This option can be given multiple times, e.g. for merging all the logs from "--traditional-recursive-make". But the dependencies you hid from makepp through the evil recursion paradigm can't of course show up here. -M module[=arg,...] --module=module[=arg,...] Load module and import any functions it exports. -m perlcode --merge=perlcode Perform perlcode for every target and its dependencies. See merging for details about this option. -o filename --output=filename Write the output to this file. -p --plain Don't use attributes like colors or dotted lines. This is especially useful for uncluttering "-t, --text" output. In that format bidirectional edges will be lost unless you combine this with "-s, --separate-directions". -r perlcode --rename=perlcode Perform perlcode for every target and its dependencies. See renaming for details about this option. -s --separate-directions Draw two separate arrows, instead of each double ended arrow, to make them easier to spot. -t --text Produce a human readable .txt file, instead of the default uDraw(Graph) .udg file. -u --up --upwards This option is only meaningful if you provide one or more patterns. It will then only select the targets which depend on and/or include the matched files. -V --version Print out the version number.
The techniques in this chapter are usually essential to get a reasonably sized graph. As they are formulated as Perl code, knowing the language is helpful. But you should be able to achieve quite a lot with the examples here or in the gallery <http://makepp.sourceforge.net/gallery/>. Renaming This is the first name rewriting that occurs, if the "-r, --rename" option is given. For every name encountered, perlcode gets called. It gets a filename in $_, and it may modify it. This is often needed, because makepp logs fully qualified file names, so one node can easily be half a screen wide. For one thing, you can rewrite names to "undef" or the empty string. This will eliminate the node from the graph. Note that eliminating a node in this first stage will break a chain of dependency if this node was in the middle. You can also rewrite various names to the same string, coercing them all into the same node, which accumulates the combined dependencies and dependents. On the other hand you can just rename names to (usually) shorter names, so as to reduce the width of nodes, which can be far to wide with absolute filenames. There are a few predefined functions in package "Mpp::Rewrite", in which your code also runs, you can use for this. These return true if they did something so you can combine them as in: --rename='cwd( 1 ) || &home || &usr' &cwd cwd number cwd number, name[, separator] Removes the current working directory from the beginning of path. With a number, also replaces parent directories that many levels up with the right number of ../ directories, where applicable. In this case you can give an alternate name, like a piled up ':' instead of '..' and additionally an alternate separator like '' instead of '/'. In the first case you might get :/:/a/b, in the second an even shorter ::a/b instead of ../../a/b. Passing a number is useful if you draw in stuff from neighbouring trees. Or you have a src directory, where most of the action is, so you call makeppgraph there, but want to see the relation to your other directories too. If you give no "--rename" option, &cwd is the default. Should you want no renaming, you can give some perlcode like "--rename=1" that does nothing. &dir This one is a great reducer of graph complexity. It reduces every file to its directory. That amounts to the question: "Files from which directory depend on files from which other directory?" Note that while the dependency graph is always acyclic (else makepp wouldn't know where to start building), that is not true of this reduced view. E.g. if dir1/a depends on dir2/b and dir2/a on dir1/b that will display as a mutual dependency between dir1 and dir2. Since a cyclic graph has no obvious starting point, the layout may be odd. Unlike the other functions in this section, this is not exclusive with the others. So you may not want to logically combine it: --rename='&dir; &cwd || &home' &home Replaces your home directory with ~/. &makepp Replaces the makepp installation directory with |m|. &suf suf number This one is also a great reducer of graph complexity. It reduces every file that has a suffix to an asterisk and that suffix. So you can see which kinds of files depend on which other kinds. With an argument of 0 it leaves the first character of the directory, provided it is one of "/", "~" or "|" (as put in by &home or &usr if you called those first). With a positive argument, it leaves that many directory levels at the beginning. With a negative argument, it removes that many directory levels at the end. So for /a/b/c/d/e/x.y you get: &suf *.y suf 0 /*.y suf 1 /a/*.y suf 2 /a/b/*.y suf -1 /a/b/c/d/*.y suf -2 /a/b/c/*.y For a relative a/b/c/d/e/x.y you get: &suf *.y suf 0 *.y suf 1 a/*.y suf -1 a/b/c/d/*.y &usr Under /, /usr, /usr/local, /usr/X11, /usr/X11R6, /usr/X11R7 or /opt, for any of the directories bin, etc, include, lib or share, the initials of these words are concatenated between bars. E.g. /usr/local/bin/foobar becomes |ulb|foobar or /usr/include/net/if.h becomes |ui|net/if.h. Note that `l' stands for `local' when between two letters and for `lib' as the last letter. Merging This is the second name rewriting that occurs, if the "-m, --merge" option is given. This API is still under development! Currently the target is passed in $_ and the dependency as an argument. If perlcode returns a value, that value replaces both the target and the dependency, merging them into one node. A few predefined functions can help you: c2o For any C/C++ source and the resulting .o file, merge them into one node, by adding to the source path a suffix of ">o" like some/where/foo.cc>o, even if the .o file is in another directory. exe For any .o file and the resulting executable of the same notdir basename without a suffix or with .exe, merge them into one node, by adding an asterisk to the .o file. This will not currently work together with c2o. x2 For any pair of files with the same name, usually a header or library published to a central directory, merge them into one node, by adding *2 to the dependency.
Makeppgraph looks at the following environment variable: $MAKEPPGRAPHFLAGS Any flags in this environment variable are interpreted as command line options before any explicit options. Quotes are interpreted like in makefiles.
Daniel Pfeiffer (firstname.lastname@example.org)