diff --git a/collects/macro-debugger/analysis/private/util.rkt b/collects/macro-debugger/analysis/private/util.rkt index 84a3842..fe0b8ec 100644 --- a/collects/macro-debugger/analysis/private/util.rkt +++ b/collects/macro-debugger/analysis/private/util.rkt @@ -129,6 +129,7 @@ (let-values ([(imports) (module-compiled-imports compiled)] [(var-exports stx-exports) (module-compiled-exports compiled)]) (parameterize ((current-directory (path-only resolved))) + (force-all-mpis imports) (force-all-mpis (cons var-exports stx-exports))) (modinfo imports var-exports stx-exports)))) diff --git a/collects/macro-debugger/analysis/show-dependencies.rkt b/collects/macro-debugger/analysis/show-dependencies.rkt new file mode 100644 index 0000000..cb84713 --- /dev/null +++ b/collects/macro-debugger/analysis/show-dependencies.rkt @@ -0,0 +1,115 @@ +#lang racket/base +(require racket/cmdline + "private/util.rkt") +(provide main) + +(define (get-dependencies-table #:include? include? . ms) + (define visited (make-hash)) ;; resolved-module-path => (listof mpi-list) + (define (loop m ctx) + (let* ([resolved (module-path-index-resolve m)] + [ctx (cons m ctx)] + [already-visited? (hash-ref visited resolved #f)]) + (when (or include? (pair? (cdr ctx))) + ;; hack to not record initial list (unless inter-dependencies) + (hash-set! visited resolved + (cons ctx (hash-ref visited resolved null)))) + (unless already-visited? + (unless (symbol? (resolved-module-path-name resolved)) + (let ([imports (get-module-imports m)]) + (for* ([phase+mods (in-list imports)] + [mod (in-list (cdr phase+mods))]) + (loop mod ctx))))))) + (for ([m (in-list ms)]) + (loop (module-path-index-join m #f) null)) + visited) + +(define (table->dependencies visited) + (let* ([unsorted + (for/list ([(key mpi-lists) (in-hash visited)]) + (list (mpi-list->module-path (car mpi-lists)) + (sort (map mpi-list->module-path + (filter pair? (map cdr mpi-lists))) + module-pathstring A) (symbol->string B))] + [(symbol? A) #t] + [(symbol? B) #f] + [(and (string? A) (string? B)) + (string" + (set! exclusions (cons exclude exclusions))] + [("-b") "Same as --minus racket/base" + (set! exclusions (cons 'racket/base exclusions))] + #:args module-path + (let () + (define (->modpath x) + (cond [(string? x) + (case mode + ((auto) + (if (file-exists? x) + `(file ,x) + (read (open-input-string x)))) + ((file) `(file ,x)) + ((module-path) + (read (open-input-string x))))] + [else x])) + (let* ([table + (apply get-dependencies-table + #:include? #f + (map ->modpath module-path))] + [exclude-table + (apply get-dependencies-table + #:include? #t + (map ->modpath exclusions))]) + (for ([key (in-hash-keys exclude-table)]) + (hash-remove! table key)) + (for ([dep (in-list (table->dependencies table))]) + (let ([mod (car dep)] + [direct-requirers (cadr dep)]) + (printf "~s" mod) + (when context? + (printf " <- ~s" direct-requirers)) + (newline))))))) + +#| + +For example, + + racket -lm macro-debugger/analysis/show-dependencies -- -bc mzscheme + +shows the additional modules used to implement mzscheme beyond those +already needed for the implementation of racket/base. And + + racket -lm macro-debugger/analysis/show-dependencies -- -bc syntax/parse/pre + +shows that syntax/parse/pre has no dependencies on the contract +library. Actually, it shows that it has no *residual* dependencies; +contracts are used in the code that is lazily loaded, but using +syntax/parse/pre does not cause a module's compiled code to depend on +racket/contract/base. + +|#