Boost logo

Boost :

From: Douglas Gregor (gregod_at_[hidden])
Date: 2002-08-07 10:46:08

On Tuesday 06 August 2002 09:57 pm, Beman Dawes wrote:
> With the Filesystem Library, it would be easy to replace the whole pile of
> junk with a single C++ program.
> But we need to figure out a better way of reporting dependencies too. Look
> at any entry in the current table which includes boost/config.hpp, which in
> turn expands into eight other headers.
> --Beman

I made some unsuccessful attempts at a better way to report dependencies.
Maybe this will give someone else a brilliant idea on how to report them :)

My first thought was to use graphviz to create a header dependency DAG.
Unfortunately, this approach results in big graphs, and we really can't go
putting the headers for every dependency in each graph. Here's the dependency
graph for boost/function.hpp:

My second attempt was to use a JavaScript tree component to let the user
interactively explore dependencies. Click on the '+' near any top-level
header to see the subheaders, etc. Unfortunately, browsers don't like to
handle this really large trees and tend to be very, very slow about it.
Perhaps we could do this but at the library level? e.g., each library would
have a 'depend.html' that lets you explore the dependencies starting at that
library's user-level headers. Then the tree would work well. Here's a big,
slow tree for all top-level headers (with thanks to Morten for the component,
of course):

Just for completeness, I generated the dependency table in the same style as
the current table. It uses some heuristics to try to figure out what is a
user-level header and what isn't (so we don't need to maintain a "user-level
header" list by hand), and tries not to repeat information within the
dependencies for a header. It's still big, though, because Boost is big:

The Perl code used to generate the dependency information follows. The code to
actually generate each of the formats is beyond trivial, but I can
post/commit it if anyone is interested.


#!/usr/bin/perl -w
use English;

sub find_dependencies {
  my $file = shift @_;
  my $line;
  open (FILE, "<$file") or die("Cannot open file $file");
  while ($line = <FILE>) {
    my $header = "";
    if ($line =~ /\s*\#\s*include\s*</) {
      if ($POSTMATCH =~ />/) {
        $header = $PREMATCH;
    elsif ($line =~ /\s*\#\s*include\s*\"/) {
      if ($POSTMATCH =~ /\"/) {
        $header = $PREMATCH;

    if ($header ne "") {
      if (exists $dependencies{$file}) {
        if ($dependencies{$file} =~ /$header/) {
        else {
          $dependencies{$file} .= ":$header";
      else {
        $dependencies{$file} = $header;
  close FILE or die ("Cannot close file $file");

sub scan_directory;

sub scan_directory {
  my $directory = shift @_;

  # Emit dependencies for all files in this directory
  opendir FILES, "$directory";
  my @files = grep /.*\.hpp$/, readdir FILES;
  closedir FILES;
  my $file;
  foreach $file (@files) {
    find_dependencies "$directory/$file";

  # Recurse into subdirectories
  opendir DIRS, "$directory";
  my @subdirs = readdir DIRS;
  closedir DIRS;
  my $subdir;
  foreach $subdir (@subdirs) {
    if ($subdir ne "." && $subdir ne ".." && $subdir ne "CVS" &&
        -d "$directory/$subdir") {
      scan_directory "$directory/$subdir";

sub is_top_level_header {
  my $header = shift @_;

  # Nothing with "detail" in it can be a top-level header
  if ($header =~ /detail/) {
    return 0;

  # Nothing with depth > 2 can be a top-level header
  if ($header =~ /\/.*\/.*\//) {
    return 0;

  # Nothing if it is in a directory boost/foo and there exists a file
  # boost/foo.hpp
  $_ = $header;
  if ($_ =~ /\//) {
    my $dir = $PREMATCH;
    if (exists $dependencies{"boost/$dir.hpp"}) {
      return 0;

  return 1;

scan_directory "boost";

Boost list run by bdawes at, gregod at, cpdaniel at, john at