Subject: Re: Splitting common-main

From: Junio C Hamano <[email-masked]>
Date: Fri, 14 Jul 2023 17:34:59 -0700

Josh Steadmon <[email-masked]> writes:

> Sorry, I don't think I'm understanding your proposal here properly,
> please let me know where I'm going wrong: isn't this functionally
> equivalent to my patch, just with different filenames? Now main() would
> live in main.c (vs. my common-main.c), while check_bug_if_BUG() and
> common_exit() would live in common-main.c (now a misnomer, vs. my
> common-exit.c). I'm not following how that changes anything so I'm
> pretty sure I've misunderstood.

Sorry, the old discussion has expired out of my brain, and asking
what I had in mind back then is too late.

Your common-main.c has stuff _other than_ main(), and the remaining
main() has tons of Git specific stuff.  It may be one way to split,
but I did not find a reason to convince myself that it was a good
split.

What I was wondering as a straw-man alternative was to have main.c
that has only this and nothing else:

    $ cat >main.c <<\EOF
    #include "git-compat-util.h" /* or whatever defines git_main() */
    int main(int ac, char **av)
    {
	return git_main(ac, av);
    }
    EOF

Then in common-main.c, rename main() to git_main().

I was not saying such a split would be superiour compared to how you
moved only some stuff out of common-main.c to a separate file.  I
had trouble equally with your split and with the above strawman,
because I did not (and do not) quite see how one would evaluate the
result (go back to the message you are responding to for details).

> The issue I was trying to solve (whether for a unit-test framework or
> for the fuzzing engine) is that we don't have direct control over their
> main(), and so we can't rename it to avoid conflicts with our main().

Sure.  And if we by default use a very thin main() that calls
git_main(), it would be very easy for them to replace that main.o
file with their own implementation of main(); as long as they
eventually call git_main(), they can borrow what we do in ours.

> I guess there may be some linker magic we could do to avoid the conflict
> and have (our) main() call (their, renamed) main()?

We can throw a main.o that has the implementation of our default
"main" function into "libgit.a".

Then, when we link our "git" program (either built-in programs that
are reachable from git.o, or standalone programs like remote-curl.o
that have their own cmd_main()), we list our object files (but we do
not have to list main.o) and tuck libgit.a at the end of the linker
command line.  As the start-up runtime code needs to find symbol
"main", and the linker sees no object files listed has "main", the
linker goes in and finds main.o stored in libgit.a (which has "main"
defined) and that will end up being linked.

If on the other hand when we link somebody else's program that has
its own "main()", we list the object files that make up the program,
including the one that has their "main()", before "libgit.a" and
the linker does not bother trying to find "main" in libgit.a:main.o
so the resulting binary will use their main().

Is that what you are looking for?