Skip to content

Commit 3f8f2ab

Browse files
steadmongitster
authored andcommitted
common-main: split init and exit code into new files
Currently, object files in libgit.a reference common_exit(), which is contained in common-main.o. However, common-main.o also includes main(), which references cmd_main() in git.o, which in turn depends on all the builtin/*.o objects. We would like to allow external users to link libgit.a without needing to include so many extra objects. Enable this by splitting common_exit() and check_bug_if_BUG() into a new file common-exit.c, and add common-exit.o to LIB_OBJS so that these are included in libgit.a. This split has previously been proposed ([1], [2]) to support fuzz tests and unit tests by avoiding conflicting definitions for main(). However, both of those issues were resolved by other methods of avoiding symbol conflicts. Now we are trying to make libgit.a more self-contained, so hopefully we can revisit this approach. Additionally, move the initialization code out of main() into a new init_git() function in its own file. Include this in libgit.a as well, so that external users can share our setup code without calling our main(). [1] https://lore.kernel.org/git/Yp+wjCPhqieTku3X@google.com/ [2] https://lore.kernel.org/git/20230517-unit-tests-v2-v2-1-21b5b60f4b32@google.com/ Signed-off-by: Josh Steadmon <steadmon@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 757161e commit 3f8f2ab

File tree

6 files changed

+101
-81
lines changed

6 files changed

+101
-81
lines changed

Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,8 @@ LIB_OBJS += combine-diff.o
981981
LIB_OBJS += commit-graph.o
982982
LIB_OBJS += commit-reach.o
983983
LIB_OBJS += commit.o
984+
LIB_OBJS += common-exit.o
985+
LIB_OBJS += common-init.o
984986
LIB_OBJS += compat/nonblock.o
985987
LIB_OBJS += compat/obstack.o
986988
LIB_OBJS += compat/terminal.o

common-exit.c

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include "git-compat-util.h"
2+
#include "trace2.h"
3+
4+
static void check_bug_if_BUG(void)
5+
{
6+
if (!bug_called_must_BUG)
7+
return;
8+
BUG("on exit(): had bug() call(s) in this process without explicit BUG_if_bug()");
9+
}
10+
11+
/* We wrap exit() to call common_exit() in git-compat-util.h */
12+
int common_exit(const char *file, int line, int code)
13+
{
14+
/*
15+
* For non-POSIX systems: Take the lowest 8 bits of the "code"
16+
* to e.g. turn -1 into 255. On a POSIX system this is
17+
* redundant, see exit(3) and wait(2), but as it doesn't harm
18+
* anything there we don't need to guard this with an "ifdef".
19+
*/
20+
code &= 0xff;
21+
22+
check_bug_if_BUG();
23+
trace2_cmd_exit_fl(file, line, code);
24+
25+
return code;
26+
}

common-init.c

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#define USE_THE_REPOSITORY_VARIABLE
2+
3+
#include "git-compat-util.h"
4+
#include "common-init.h"
5+
#include "exec-cmd.h"
6+
#include "gettext.h"
7+
#include "attr.h"
8+
#include "repository.h"
9+
#include "setup.h"
10+
#include "strbuf.h"
11+
#include "trace2.h"
12+
13+
/*
14+
* Many parts of Git have subprograms communicate via pipe, expect the
15+
* upstream of a pipe to die with SIGPIPE when the downstream of a
16+
* pipe does not need to read all that is written. Some third-party
17+
* programs that ignore or block SIGPIPE for their own reason forget
18+
* to restore SIGPIPE handling to the default before spawning Git and
19+
* break this carefully orchestrated machinery.
20+
*
21+
* Restore the way SIGPIPE is handled to default, which is what we
22+
* expect.
23+
*/
24+
static void restore_sigpipe_to_default(void)
25+
{
26+
sigset_t unblock;
27+
28+
sigemptyset(&unblock);
29+
sigaddset(&unblock, SIGPIPE);
30+
sigprocmask(SIG_UNBLOCK, &unblock, NULL);
31+
signal(SIGPIPE, SIG_DFL);
32+
}
33+
34+
void init_git(const char **argv)
35+
{
36+
struct strbuf tmp = STRBUF_INIT;
37+
38+
trace2_initialize_clock();
39+
40+
/*
41+
* Always open file descriptors 0/1/2 to avoid clobbering files
42+
* in die(). It also avoids messing up when the pipes are dup'ed
43+
* onto stdin/stdout/stderr in the child processes we spawn.
44+
*/
45+
sanitize_stdfds();
46+
restore_sigpipe_to_default();
47+
48+
git_resolve_executable_dir(argv[0]);
49+
50+
setlocale(LC_CTYPE, "");
51+
git_setup_gettext();
52+
53+
initialize_repository(the_repository);
54+
55+
attr_start();
56+
57+
trace2_initialize();
58+
trace2_cmd_start(argv);
59+
trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);
60+
61+
if (!strbuf_getcwd(&tmp))
62+
tmp_original_cwd = strbuf_detach(&tmp, NULL);
63+
}

common-init.h

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef COMMON_INIT_H
2+
#define COMMON_INIT_H
3+
4+
void init_git(const char **argv);
5+
6+
#endif /* COMMON_INIT_H */

common-main.c

+2-81
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,13 @@
1-
#define USE_THE_REPOSITORY_VARIABLE
2-
31
#include "git-compat-util.h"
4-
#include "exec-cmd.h"
5-
#include "gettext.h"
6-
#include "attr.h"
7-
#include "repository.h"
8-
#include "setup.h"
9-
#include "strbuf.h"
10-
#include "trace2.h"
11-
12-
/*
13-
* Many parts of Git have subprograms communicate via pipe, expect the
14-
* upstream of a pipe to die with SIGPIPE when the downstream of a
15-
* pipe does not need to read all that is written. Some third-party
16-
* programs that ignore or block SIGPIPE for their own reason forget
17-
* to restore SIGPIPE handling to the default before spawning Git and
18-
* break this carefully orchestrated machinery.
19-
*
20-
* Restore the way SIGPIPE is handled to default, which is what we
21-
* expect.
22-
*/
23-
static void restore_sigpipe_to_default(void)
24-
{
25-
sigset_t unblock;
26-
27-
sigemptyset(&unblock);
28-
sigaddset(&unblock, SIGPIPE);
29-
sigprocmask(SIG_UNBLOCK, &unblock, NULL);
30-
signal(SIGPIPE, SIG_DFL);
31-
}
2+
#include "common-init.h"
323

334
int main(int argc, const char **argv)
345
{
356
int result;
36-
struct strbuf tmp = STRBUF_INIT;
37-
38-
trace2_initialize_clock();
39-
40-
/*
41-
* Always open file descriptors 0/1/2 to avoid clobbering files
42-
* in die(). It also avoids messing up when the pipes are dup'ed
43-
* onto stdin/stdout/stderr in the child processes we spawn.
44-
*/
45-
sanitize_stdfds();
46-
restore_sigpipe_to_default();
47-
48-
git_resolve_executable_dir(argv[0]);
49-
50-
setlocale(LC_CTYPE, "");
51-
git_setup_gettext();
52-
53-
initialize_repository(the_repository);
54-
55-
attr_start();
56-
57-
trace2_initialize();
58-
trace2_cmd_start(argv);
59-
trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);
60-
61-
if (!strbuf_getcwd(&tmp))
62-
tmp_original_cwd = strbuf_detach(&tmp, NULL);
637

8+
init_git(argv);
649
result = cmd_main(argc, argv);
6510

6611
/* Not exit(3), but a wrapper calling our common_exit() */
6712
exit(result);
6813
}
69-
70-
static void check_bug_if_BUG(void)
71-
{
72-
if (!bug_called_must_BUG)
73-
return;
74-
BUG("on exit(): had bug() call(s) in this process without explicit BUG_if_bug()");
75-
}
76-
77-
/* We wrap exit() to call common_exit() in git-compat-util.h */
78-
int common_exit(const char *file, int line, int code)
79-
{
80-
/*
81-
* For non-POSIX systems: Take the lowest 8 bits of the "code"
82-
* to e.g. turn -1 into 255. On a POSIX system this is
83-
* redundant, see exit(3) and wait(2), but as it doesn't harm
84-
* anything there we don't need to guard this with an "ifdef".
85-
*/
86-
code &= 0xff;
87-
88-
check_bug_if_BUG();
89-
trace2_cmd_exit_fl(file, line, code);
90-
91-
return code;
92-
}

meson.build

+2
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ libgit_sources = [
245245
'commit-graph.c',
246246
'commit-reach.c',
247247
'commit.c',
248+
'common-exit.c',
249+
'common-init.c',
248250
'compat/nonblock.c',
249251
'compat/obstack.c',
250252
'compat/terminal.c',

0 commit comments

Comments
 (0)