I'm working with a large C++ project that presently produces 66 different binaries. Each entrypoint contains its own global variables and main() function, though there's a lot of common code that's provided through a shared library.
For ease of distribution, I would like to distribute a single statically-linked binary, like you'd get from a Go or Rust project. Instead of invoking:
./ProgramFoo
./ProgramBar
I'd like to have a single combined binary that "execs" itself into one of those tools behind the scenes based on argv parameters, sort of like how busybox works:
./CombinedProgram ProgramFoo
./CombinedProgram ProgramBar
Look, I get that there's a "right" way to do this — refactor all 66 source files. Replace all global state with class singletons. Replace all the main() functions with entrypoint functions that could be dispatched from a single, unifying main() function. That sounds like a lot of work and a fair amount of disruption to all the other developers on the project. Is there truly no alternative on the compiler/linker level?
(I also don't want to just archive the binaries inside the CombinedProgram, write them to disk, and exec them. Boo. If I wanted a tarball, I'd just use a tarball.)
My understanding of C/C++ binary production is that the compiler will insert a crt0 startup routine that will initialize all my global state and then invoke main() with the appropriate parameters. Could I... perhaps... sneak some code in before that crt0 that peeks at argv and then proceeds down the correct code path?