Best way for an executable to depend on another executable target?

suppose you have a SwiftPM project that contains two executable targets, tool-a, and tool-b. the tool-a binary should be able to launch an instance of tool-b as a child process, and wait for its result. but this is challenging because tool-a does not know where to find the tool-b binary.

i could think of a few possible solutions, but none stuck out to me as a clear winner.

  1. push problem onto users. you could force the user of tool-a to specify the path (.build/release/tool-b, /usr/bin/tool-b, etc.) explicitly.

  2. subsume tool-b into tool-a. tool-a could provide an adapter interface for escaping command line arguments and forwarding them to the backing implementation for tool-b. tool-a could then spawn another instance of itself and pass the child process the intended arguments through its own argument escaping format. because we spawned a new context, the exit logic that already exists in tool-b will Just Work.

  3. fork tool-a into a parent and child process. you could do something similar to #2, except fork the current process instead of spawning a new context. this avoids the problem of passing arguments to tool-b, but replaces it with the problem of getting its exit status. this doesn’t fit neatly into static typing patterns, so you need to (conditionally!) import the low-level _exit function wherever you fork a process, and call the Never-returning C function.

what is the best way for an executable to depend on another tool written in Swift?