List of used functions from a given library

Hello
I have a library Foo which depends on another library Bar. How do I get the list of Bar functions that Foo really uses?

(I’m ok to count all functions that are present in the source code of Foo, even if parts of that source code are never called.)
Of course I can just grep Bar.* but the problem is to detect open Bar

if you’re willing to build the library, nm foo.a | grep Bar might be useful?

2 Likes

If you compile your file with the flag -dtypedtree, you will get a (large) dump where all identifiers are resolved with their full path. With the right grep/sed invocations you should be able to turn it into some readable output which should contain all occurrences of functions from a given module, even in presence of open statements or shadowing.

1 Like

with more opens than I’d like:

open Printf
open Event
open Thread

let () =
  let chan = new_channel () in
  let rec printer () =
    printf "going\n%!";
    let msg = sync (receive chan) in
    printf "gone?\n%!";
    printf "printed: %s\n%!" msg;
    delay 2.0;
    printer ()
  in
  ignore (create printer ());
  for i = 1 to 10 do
    printf "sending\n%!";
    let msg = sprintf "msg %d" i in
    ignore (poll (send chan msg));
    delay 0.5
  done

compiled with -annot and checked:

$ ocamlfind ocamlc -package unix,threads -linkpkg -annot example.ml
$ $ grep -Eo '(Thread|Event|Printf)\.\S+' example.annot |sort -u
Event.channel
Event.event
Event.new_channel
Event.poll
Event.receive
Event.send
Event.sync
Printf.printf
Printf.sprintf
Thread.create
Thread.delay
Thread.t
2 Likes

that’s a good idea thanks;
however I don’t really understand the output, some functions are listed which don’t exist in Bar. I suspect it’s because they are from submodules like Bar.X.f but are listed as Bar.f

@vlaviron and @jrfondren both your techniques seem to work well, thanks !

with -annot I need to check that the preceeding line contains ident( in order to filter out types and only keep values.

with -dtypedtree I just need to check that the line starts with Texp_ident (which is slightly easier since I need only grep one line)

[PS: another example that this forum is so useful!
(I must admit I asked GPT first but it didn’t give me anything usable even after 45min of trying to put it on the right track :wink: )]

Perhaps the machinery behind merlin project wide occurrences can help too ?

1 Like

another good idea, thanks.
I couldn’t make it work though: I tried ‘merlin-project-occurrences’ in emacs by selecting an occurence of Bar but I get the error

progn: Wrong type argument: integer-or-marker-p, nil

Here’s an example of that: ciao-lwt/lib/migrate_utils/ocaml_index_utils.mli at main · tarides/ciao-lwt · GitHub

The index files are built using dune build @ocaml-index.

2 Likes

I’ve personally used LexiFi’s dead_code_analyzer to do exactly this last year.

You just need to have one binary that fully uses Foo and you’ll get the list of functions that Foo really uses from Bar.

Make sure you’re using a sufficiently recent version (see #33) and be aware that some categories of OCaml values are not tracked yet (see #19).

1 Like