--- /dev/null
+++ b/bin/mlbdeps
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+
+set -e
+
+SED=${SED:-sed}
+
+name=$(basename "$0")
+
+function normalize_path () {
+    local path="$1"
+    local opath=""
+    while [ "$opath" != "$path" ]; do
+        opath="$path"
+        path="$(echo "$path" | ${SED} -e 's;^\./;;')"
+    done
+    local opath=""
+    while [ "$opath" != "$path" ]; do
+        opath="$path"
+        path="$(echo "$path" | ${SED} -e 's;/\./;/;')"
+    done
+    opath=""
+    while [ "$opath" != "$path" ]; do
+        opath="$path"
+        path="$(echo "$path" | ${SED} -e 's;[^/][^/]*/\.\./;;')"
+    done
+    path="$(echo "$path" | ${SED} -e 's;^\./;;')"
+    echo "$path"
+}
+
+declare -a seen
+
+function doit() {
+    local mlb="$1"
+    for s in "${seen[@]}"; do
+        if [ "$mlb" == "$s" ]; then
+            return 0
+        fi
+    done
+    seen+=("$mlb");
+    echo "$mlb"
+    if [ -e "$mlb" ]; then
+        local dir="$(dirname $mlb)"
+        for f in $(cat "$mlb" | ${SED} -n -e 's/^[ ]*\([^ ]*\.\(sml\|sig\|fun\|mlb\)\).*/\1/p'); do
+            case "$f" in
+                /*) ;;
+                \$\(*\)*) ;;
+                *) f="$(normalize_path "$dir"/"$f")" ;;
+            esac
+            case "$f" in
+                *.mlb) doit "$f";;
+                *) echo "$f";;
+            esac
+        done
+    fi
+}
+
+doit "$(normalize_path "$1")"
