# from Dr.Ruud # on Friday 19 January 2007 09:36 am: >I am not currently using par, but I want to create a utility that >generates a hash with a "use"-tree, starting at any module. >Especially for detecting circles. >The scandeps.pl seems like a nice start. If anybody knows a better way >to generate such a tree, please reply.
Well, I've been playing with Devel::TraceDeps as a fork of chromatic's Devel::TraceUse which puts a hook in @INC to grab all of the require calls. This is similar to Module::ScanDeps::DataFeed, which is what scandeps.pl is doing for the 'compile' and 'execute' steps. The difference is that my approach tries to catch *all* of the require calls by deleting the %INC entry as soon as it is created where M::SD::DF only examines the final (aggregate of all dependencies) %INC, so it has less information about 'who wants what.' However, I noticed that perl is somewhat tricky about how it handles circular dependency. The @INC hook won't see another 'use foo' if foo.pm says 'use bar' and bar.pm says 'use foo'. My guess is that it defers the compile until after all of the requires have returned filehandles. So, at least with my current (pseudo-recursive: flag the current and call require($module) to send perl looking through the rest of @INC) implementation, I can't see the 'use foo' in bar.pm if starting at foo.pm With some debugging info, you see this: $ perl -MDevel::TraceDeps -e 'use foo' want foo.pm want bar.pm want baz.pm done baz.pm done bar.pm done foo.pm (bar.pm does "use baz", and baz.pm has a "require foo") Though I might very well have a bug in the code atm. Thus, to actually construct a correct dependency tree, you have to take one pass just to determine the aggregate list of dependencies, then take each of those as an entry point. Unfortunately, if I can't tie %INC (*), I'm not sure even that will work in some circular cases. Maybe the compiling approach will ever be sure to hit all of the deps, thus some static scanning, PPI, or opcode examination may be necessary. http://scratchcomputing.com/svn/Devel-TraceDeps/trunk * subrefs in @INC return a filehandle, after which perl sets an entry in %INC. Because I depend on ! exists($INC{foo.pm}) to re-trigger the require(), I'm sort of stuck right now because if I don't set it, perl sets it to the subref which is the @INC hook. I can use a DB hook, INIT block and other such stuff, but I have to think there's a gap in those approaches somewhere. One thing that I've noticed is that no dep-finder system currently has any sort of caching mechanism. We should probably checksum the file and store the known dependencies somewhere (that is, once we get it right.) --Eric -- But you can never get 3n from n, ever, and if you think you can, please email me the stock ticker of your company so I can short it. --Joel Spolsky --------------------------------------------------- http://scratchcomputing.com ---------------------------------------------------
