1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-09 12:36:08 +02:00

Merge branch 'cw/git-std-lib' into seen

Split libgit.a out to a separate git-std-lib tor easier reuse.

* cw/git-std-lib:
  SQUASH??? get rid of apparent debugging crufts
  test-stdlib: show that git-std-lib is independent
  git-std-lib: introduce Git Standard Library
  pager: include stdint.h because uintmax_t is used
This commit is contained in:
Junio C Hamano 2024-04-26 09:28:36 -07:00
commit 08af859678
11 changed files with 571 additions and 13 deletions

View File

@ -110,6 +110,7 @@ TECH_DOCS += SubmittingPatches
TECH_DOCS += ToolsForGit
TECH_DOCS += technical/bitmap-format
TECH_DOCS += technical/bundle-uri
TECH_DOCS += technical/git-std-lib
TECH_DOCS += technical/hash-function-transition
TECH_DOCS += technical/long-running-process-protocol
TECH_DOCS += technical/multi-pack-index

View File

@ -0,0 +1,170 @@
= Git Standard Library
The Git Standard Library intends to serve as the foundational library
and root dependency that other libraries in Git will be built off of.
That is to say, suppose we have libraries X and Y; a user that wants to
use X and Y would need to include X, Y, and this Git Standard Library.
This does not mean that the Git Standard Library will be the only
possible root dependency in the future, but rather the most significant
and widely used one. Git itself is also built off of the Git Standard
Library.
== Dependency graph in libified Git
Before the introduction of the Git Standard Library, all objects defined
in the Git library are compiled and archived into a singular file,
libgit.a, which is then linked against by common-main.o with other
external dependencies and turned into the Git executable. In other
words, the Git executable has dependencies on libgit.a and a couple of
external libraries. The libfication of Git slightly alters this build
flow by separating out libgit.a into libgit.a and git-std-lib.a.
With our current method of building Git, we can imagine the dependency
graph as such:
Git
/\
/ \
/ \
libgit.a ext deps
We want to separate out potential libraries from libgit.a and have
libgit.a depend on them, which would possibly look like:
Git
/\
/ \
/ \
libgit.a ext deps
/\
/ \
/ \
object-store.a (other lib)
| /
| /
| /
| /
| /
| /
| /
git-std-lib.a
Instead of containing all objects in Git, libgit.a would contain objects
that are not built by libraries it links against. Consequently, if
someone wanted a custom build of Git with a custom implementation of the
object store, they would only have to swap out object-store.a rather
than do a hard fork of Git.
== Rationale behind Git Standard Library
The rationale behind the selected object files in the Git Standard
Library is the result of two observations within the Git
codebase:
1. every file includes git-compat-util.h which defines functions
in a couple of different files
2. wrapper.c + usage.c have difficult-to-separate circular
dependencies with each other and other files.
=== Ubiquity of git-compat-util.h and circular dependencies
Every file in the Git codebase includes git-compat-util.h. It serves as
"a compatibility aid that isolates the knowledge of platform specific
inclusion order and what feature macros to define before including which
system header" (Junio[1]). Since every file includes git-compat-util.h,
and git-compat-util.h includes wrapper.h and usage.h, it would make
sense for wrapper.c and usage.c to be a part of the root library. They
have difficult to separate circular dependencies with each other so it
would impractical for them to be independent libraries. Wrapper.c has
dependencies on parse.c, abspath.c, strbuf.c, which in turn also have
dependencies on usage.c and wrapper.c - more circular dependencies.
=== Tradeoff between swappability and refactoring
From the above dependency graph, we can see that git-std-lib.a could be
many smaller libraries rather than a singular library. So why choose a
singular library when multiple libraries can be individually easier to
swap and are more modular? A singular library requires less work to
separate out circular dependencies within itself so it becomes a
tradeoff question between work and reward. While there may be a point in
the future where a file like usage.c would want its own library so that
someone can have custom die() or error(), the work required to refactor
out the circular dependencies in some files would be enormous due to
their ubiquity so therefore I believe it is not worth the tradeoff
currently. Additionally, we can in the future choose to do this refactor
and change the API for the library if there becomes enough of a reason
to do so (remember we are avoiding promising stability of the interfaces
of those libraries).
=== Reuse of compatibility functions in git-compat-util.h
Most functions defined in git-compat-util.h are implemented in compat/
and have dependencies limited to strbuf.h and wrapper.h so they can be
easily included in git-std-lib.a, which as a root dependency means that
higher level libraries do not have to worry about compatibility files in
compat/. The rest of the functions defined in git-compat-util.h are
implemented in top level files and are hidden behind
an #ifdef if their implementation is not in git-std-lib.a.
=== Rationale summary
The Git Standard Library allows us to get the libification ball rolling
with other libraries in Git. By not spending many more months attempting
to refactor difficult circular dependencies and instead spending that
time getting to a state where we can test out swapping a library out
such as config or object store, we can prove the viability of Git
libification on a much faster time scale. Additionally the code cleanups
that have happened so far have been minor and beneficial for the
codebase. It is probable that making large movements would negatively
affect code clarity.
== Git Standard Library boundary
While I have described above some useful heuristics for identifying
potential candidates for git-std-lib.a, a standard library should not
have a shaky definition for what belongs in it.
- Low-level files (aka operates only on other primitive types) that are
used everywhere within the codebase (wrapper.c, usage.c, strbuf.c)
- Dependencies that are low-level and widely used
(abspath.c, date.c, hex-ll.c, parse.c, utf8.c)
- low-level git/* files with functions defined in git-compat-util.h
(ctype.c)
- compat/*
There are other files that might fit this definition, but that does not
mean it should belong in git-std-lib.a. Those files should start as
their own separate library since any file added to git-std-lib.a loses
its flexibility of being easily swappable.
Wrapper.c and usage.c have dependencies on pager and trace2 that are
possible to remove at the cost of sacrificing the ability for standard Git
to be able to trace functions in those files and other files in git-std-lib.a.
In order for git-std-lib.a to compile with those dependencies, stubbed out
versions of those files are implemented and swapped in during compilation time
(see STUB_LIB_OBJS in the Makefile).
== Files inside of Git Standard Library
The set of files in git-std-lib.a can be found in STD_LIB_OBJS and COMPAT_OBJS
in the Makefile.
When these files are compiled together with the files in STUB_LIB_OBJS (or
user-provided files that provide the same functions), they form a complete
library.
== Pitfalls
There are a small amount of files under compat/* that have dependencies
not inside of git-std-lib.a. While those functions are not called on
Linux, other OSes might call those problematic functions. I don't see
this as a major problem, just moreso an observation that libification in
general may also require some minor compatibility work in the future.
== Testing
Unit tests should catch any breakages caused by changes to files in
git-std-lib.a (i.e. introduction of a out of scope dependency) and new
functions introduced to git-std-lib.a will require unit tests written
for them.
[1] https://lore.kernel.org/git/xmqqwn17sydw.fsf@gitster.g/

View File

@ -672,6 +672,8 @@ FUZZ_PROGRAMS =
GIT_OBJS =
LIB_OBJS =
SCALAR_OBJS =
STD_LIB_OBJS =
STUB_LIB_OBJS =
OBJECTS =
OTHER_PROGRAMS =
PROGRAM_OBJS =
@ -859,8 +861,6 @@ TEST_BUILTINS_OBJS += test-xml-encode.o
TEST_PROGRAMS_NEED_X += test-fake-ssh
TEST_PROGRAMS_NEED_X += test-tool
TEST_PROGRAMS = $(patsubst %,t/helper/%$X,$(TEST_PROGRAMS_NEED_X))
# List built-in command $C whose implementation cmd_$C() is not in
# builtin/$C.o but is linked in as part of some other command.
BUILT_INS += $(patsubst builtin/%.o,git-%$X,$(BUILTIN_OBJS))
@ -912,6 +912,8 @@ TEST_SHELL_PATH = $(SHELL_PATH)
LIB_FILE = libgit.a
XDIFF_LIB = xdiff/lib.a
STD_LIB_FILE = git-std-lib.a
STUB_LIB_FILE = git-stub-lib.a
REFTABLE_LIB = reftable/libreftable.a
REFTABLE_TEST_LIB = reftable/libreftable_test.a
@ -951,7 +953,6 @@ COCCI_SOURCES = $(filter-out $(THIRD_PARTY_SOURCES),$(FOUND_C_SOURCES))
LIB_H = $(FOUND_H_SOURCES)
LIB_OBJS += abspath.o
LIB_OBJS += add-interactive.o
LIB_OBJS += add-patch.o
LIB_OBJS += advice.o
@ -993,8 +994,6 @@ LIB_OBJS += convert.o
LIB_OBJS += copy.o
LIB_OBJS += credential.o
LIB_OBJS += csum-file.o
LIB_OBJS += ctype.o
LIB_OBJS += date.o
LIB_OBJS += decorate.o
LIB_OBJS += delta-islands.o
LIB_OBJS += diagnose.o
@ -1035,7 +1034,6 @@ LIB_OBJS += hash-lookup.o
LIB_OBJS += hashmap.o
LIB_OBJS += help.o
LIB_OBJS += hex.o
LIB_OBJS += hex-ll.o
LIB_OBJS += hook.o
LIB_OBJS += ident.o
LIB_OBJS += json-writer.o
@ -1089,7 +1087,6 @@ LIB_OBJS += pack-write.o
LIB_OBJS += packfile.o
LIB_OBJS += pager.o
LIB_OBJS += parallel-checkout.o
LIB_OBJS += parse.o
LIB_OBJS += parse-options-cb.o
LIB_OBJS += parse-options.o
LIB_OBJS += patch-delta.o
@ -1144,7 +1141,6 @@ LIB_OBJS += sparse-index.o
LIB_OBJS += split-index.o
LIB_OBJS += stable-qsort.o
LIB_OBJS += statinfo.o
LIB_OBJS += strbuf.o
LIB_OBJS += streaming.o
LIB_OBJS += string-list.o
LIB_OBJS += strmap.o
@ -1181,21 +1177,32 @@ LIB_OBJS += unpack-trees.o
LIB_OBJS += upload-pack.o
LIB_OBJS += url.o
LIB_OBJS += urlmatch.o
LIB_OBJS += usage.o
LIB_OBJS += userdiff.o
LIB_OBJS += utf8.o
LIB_OBJS += varint.o
LIB_OBJS += version.o
LIB_OBJS += versioncmp.o
LIB_OBJS += walker.o
LIB_OBJS += wildmatch.o
LIB_OBJS += worktree.o
LIB_OBJS += wrapper.o
LIB_OBJS += write-or-die.o
LIB_OBJS += ws.o
LIB_OBJS += wt-status.o
LIB_OBJS += xdiff-interface.o
STD_LIB_OBJS += abspath.o
STD_LIB_OBJS += ctype.o
STD_LIB_OBJS += date.o
STD_LIB_OBJS += hex-ll.o
STD_LIB_OBJS += parse.o
STD_LIB_OBJS += strbuf.o
STD_LIB_OBJS += usage.o
STD_LIB_OBJS += utf8.o
STD_LIB_OBJS += wrapper.o
STUB_LIB_OBJS += stubs/trace2.o
STUB_LIB_OBJS += stubs/pager.o
STUB_LIB_OBJS += stubs/misc.o
BUILTIN_OBJS += builtin/add.o
BUILTIN_OBJS += builtin/am.o
BUILTIN_OBJS += builtin/annotate.o
@ -1344,7 +1351,7 @@ UNIT_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
# xdiff and reftable libs may in turn depend on what is in libgit.a
GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE)
GITLIBS = common-main.o $(STD_LIB_FILE) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE)
EXTLIBS =
GIT_USER_AGENT = git/$(GIT_VERSION)
@ -2682,6 +2689,15 @@ REFTABLE_TEST_OBJS += reftable/stack_test.o
REFTABLE_TEST_OBJS += reftable/test_framework.o
REFTABLE_TEST_OBJS += reftable/tree_test.o
ifndef NO_POSIX_GOODIES
TEST_PROGRAMS_NEED_X += test-stdlib
MY_VAR = not_else
else
MY_VAR = else
endif
TEST_PROGRAMS = $(patsubst %,t/helper/%$X,$(TEST_PROGRAMS_NEED_X))
TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
.PHONY: test-objs
@ -2706,6 +2722,8 @@ OBJECTS += $(XDIFF_OBJS)
OBJECTS += $(FUZZ_OBJS)
OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS)
OBJECTS += $(UNIT_TEST_OBJS)
OBJECTS += $(STD_LIB_OBJS)
OBJECTS += $(STUB_LIB_OBJS)
ifndef NO_CURL
OBJECTS += http.o http-walker.o remote-curl.o
@ -3208,6 +3226,10 @@ endif
test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X))
t/helper/test-stdlib$X: t/helper/test-stdlib.o GIT-LDFLAGS $(STD_LIB_FILE) $(STUB_LIB_FILE) $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$< $(STD_LIB_FILE) $(STUB_LIB_FILE) $(EXTLIBS)
all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS)
bin-wrappers/%: wrap-for-bin.sh
@ -3637,6 +3659,7 @@ ifneq ($(INCLUDE_DLLS_IN_ARTIFACTS),)
OTHER_PROGRAMS += $(shell echo *.dll t/helper/*.dll t/unit-tests/bin/*.dll)
endif
# Added an info for debugging
artifacts-tar:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) \
GIT-BUILD-OPTIONS $(TEST_PROGRAMS) $(test_bindir_programs) \
$(UNIT_TEST_PROGS) $(MOFILES)
@ -3699,7 +3722,7 @@ clean: profile-clean coverage-clean cocciclean
$(RM) git.res
$(RM) $(OBJECTS)
$(RM) headless-git.o
$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB)
$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB) $(STD_LIB_FILE) $(STUB_LIB_FILE)
$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS)
$(RM) $(TEST_PROGRAMS)
$(RM) $(FUZZ_PROGRAMS)
@ -3891,3 +3914,18 @@ $(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o $(UNIT_TEST_DIR)/
build-unit-tests: $(UNIT_TEST_PROGS)
unit-tests: $(UNIT_TEST_PROGS) t/helper/test-tool$X
$(MAKE) -C t/ unit-tests
### Libified Git rules
# git-std-lib.a
# Programs other than git should compile this with
# make NO_GETTEXT=YesPlease git-std-lib.a
# and link against git-stub-lib.a (if the default no-op functionality is fine)
# or a custom .a file with the same interface as git-stub-lib.a (if custom
# functionality is needed) as well.
$(STD_LIB_FILE): $(STD_LIB_OBJS) $(COMPAT_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
# git-stub-lib.a
$(STUB_LIB_FILE): $(STUB_LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^

View File

@ -1,6 +1,8 @@
#ifndef PAGER_H
#define PAGER_H
#include <stdint.h>
struct child_process;
const char *git_pager(int stdout_is_tty);

View File

@ -1,6 +1,8 @@
#ifndef STRBUF_H
#define STRBUF_H
#include "git-compat-util.h"
/*
* NOTE FOR STRBUF DEVELOPERS
*

34
stubs/misc.c Normal file
View File

@ -0,0 +1,34 @@
#include <assert.h>
#include <stdlib.h>
#ifndef NO_GETTEXT
/*
* NEEDSWORK: This is enough to link our unit tests against
* git-std-lib.a built with gettext support. We don't really support
* programs other than git using git-std-lib.a with gettext support
* yet. To do that we need to start using dgettext() rather than
* gettext() in our code.
*/
#include "gettext.h"
int git_gettext_enabled = 0;
#endif
int common_exit(const char *file, int line, int code);
int common_exit(const char *file, int line, int code)
{
exit(code);
}
#if !defined(__MINGW32__) && !defined(_MSC_VER)
int lstat_cache_aware_rmdir(const char *path);
int lstat_cache_aware_rmdir(const char *path)
{
/*
* This function should not be called by programs linked
* against git-stub-lib.a
*/
assert(0);
}
#endif

6
stubs/pager.c Normal file
View File

@ -0,0 +1,6 @@
#include "pager.h"
int pager_in_use(void)
{
return 0;
}

27
stubs/trace2.c Normal file
View File

@ -0,0 +1,27 @@
#include "git-compat-util.h"
#include "trace2.h"
struct child_process { int stub; };
struct repository { int stub; };
struct json_writer { int stub; };
void trace2_region_enter_fl(const char *file, int line, const char *category,
const char *label, const struct repository *repo, ...) { }
void trace2_region_leave_fl(const char *file, int line, const char *category,
const char *label, const struct repository *repo, ...) { }
void trace2_data_string_fl(const char *file, int line, const char *category,
const struct repository *repo, const char *key,
const char *value) { }
void trace2_cmd_ancestry_fl(const char *file, int line, const char **parent_names) { }
void trace2_cmd_error_va_fl(const char *file, int line, const char *fmt,
va_list ap) { }
void trace2_cmd_name_fl(const char *file, int line, const char *name) { }
void trace2_thread_start_fl(const char *file, int line,
const char *thread_base_name) { }
void trace2_thread_exit_fl(const char *file, int line) { }
void trace2_data_intmax_fl(const char *file, int line, const char *category,
const struct repository *repo, const char *key,
intmax_t value) { }
int trace2_is_enabled(void) { return 0; }
void trace2_counter_add(enum trace2_counter_id cid, uint64_t value) { }
void trace2_collect_process_info(enum trace2_process_info_reason reason) { }

1
t/helper/.gitignore vendored
View File

@ -1,2 +1,3 @@
/test-tool
/test-fake-ssh
/test-stdlib

266
t/helper/test-stdlib.c Normal file
View File

@ -0,0 +1,266 @@
#include "git-compat-util.h"
#include "abspath.h"
#include "hex-ll.h"
#include "parse.h"
#include "strbuf.h"
#include "string-list.h"
/*
* Calls all functions from git-std-lib
* Some inline/trivial functions are skipped
*
* NEEDSWORK: The purpose of this file is to show that an executable can be
* built with git-std-lib.a and git-stub-lib.a, and then executed. If there
* is another executable that demonstrates this (for example, a unit test that
* takes the form of an executable compiled with git-std-lib.a and git-stub-
* lib.a), this file can be removed.
*/
static void abspath_funcs(void) {
struct strbuf sb = STRBUF_INIT;
fprintf(stderr, "calling abspath functions\n");
is_directory("foo");
strbuf_realpath(&sb, "foo", 0);
strbuf_realpath_forgiving(&sb, "foo", 0);
real_pathdup("foo", 0);
absolute_path("foo");
absolute_pathdup("foo");
prefix_filename("foo/", "bar");
prefix_filename_except_for_dash("foo/", "bar");
is_absolute_path("foo");
strbuf_add_absolute_path(&sb, "foo");
strbuf_add_real_path(&sb, "foo");
}
static void hex_ll_funcs(void) {
unsigned char c;
fprintf(stderr, "calling hex-ll functions\n");
hexval('c');
hex2chr("A1");
hex_to_bytes(&c, "A1", 1);
}
static void parse_funcs(void) {
intmax_t foo;
ssize_t foo1 = -1;
unsigned long foo2;
int foo3;
int64_t foo4;
fprintf(stderr, "calling parse functions\n");
git_parse_signed("42", &foo, maximum_signed_value_of_type(int));
git_parse_ssize_t("42", &foo1);
git_parse_ulong("42", &foo2);
git_parse_int("42", &foo3);
git_parse_int64("42", &foo4);
git_parse_maybe_bool("foo");
git_parse_maybe_bool_text("foo");
git_env_bool("foo", 1);
git_env_ulong("foo", 1);
}
static int allow_unencoded_fn(char ch) {
return 0;
}
static void strbuf_funcs(void) {
struct strbuf *sb = xmalloc(sizeof(*sb));
struct strbuf *sb2 = xmalloc(sizeof(*sb2));
struct strbuf sb3 = STRBUF_INIT;
struct string_list list = STRING_LIST_INIT_NODUP;
int fd = open("/dev/null", O_RDONLY);
fprintf(stderr, "calling strbuf functions\n");
fprintf(stderr, "at line %d\n", __LINE__);
starts_with("foo", "bar");
fprintf(stderr, "at line %d\n", __LINE__);
istarts_with("foo", "bar");
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_init(sb, 0);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_init(sb2, 0);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_release(sb);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_attach(sb, strbuf_detach(sb, NULL), 0, 0);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_swap(sb, sb2);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_setlen(sb, 0);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_trim(sb);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_trim_trailing_dir_sep(sb);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_trim_trailing_newline(sb);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_reencode(sb, "foo", "bar");
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_tolower(sb);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_add_separated_string_list(sb, " ", &list);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_list_free(strbuf_split_buf("foo bar", 8, ' ', -1));
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_cmp(sb, sb2);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_addch(sb, 1);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_splice(sb, 0, 1, "foo", 3);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_insert(sb, 0, "foo", 3);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_insertf(sb, 0, "%s", "foo");
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_remove(sb, 0, 1);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_add(sb, "foo", 3);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_addbuf(sb, sb2);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_join_argv(sb, 0, NULL, ' ');
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_addchars(sb, 1, 1);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_addstr(sb, "foo");
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_add_commented_lines(sb, "foo", 3, "#");
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_commented_addf(sb, "#", "%s", "foo");
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_addbuf_percentquote(sb, &sb3);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_add_percentencode(sb, "foo", STRBUF_ENCODE_SLASH);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_fread(sb, 0, stdin);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_read(sb, fd, 0);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_read_once(sb, fd, 0);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_write(sb, stderr);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_readlink(sb, "/dev/null", 0);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_getcwd(sb);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_getwholeline(sb, stderr, '\n');
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_appendwholeline(sb, stderr, '\n');
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_getline(sb, stderr);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_getline_lf(sb, stderr);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_getline_nul(sb, stderr);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_getwholeline_fd(sb, fd, '\n');
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_read_file(sb, "/dev/null", 0);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_add_lines(sb, "foo", "bar", 0);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_addstr_xml_quoted(sb, "foo");
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_addstr_urlencode(sb, "foo", allow_unencoded_fn);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_humanise_bytes(sb, 42);
fprintf(stderr, "at line %d\n", __LINE__);
strbuf_humanise_rate(sb, 42);
fprintf(stderr, "at line %d\n", __LINE__);
printf_ln("%s", sb->buf);
fprintf(stderr, "at line %d\n", __LINE__);
fprintf_ln(stderr, "%s", sb->buf);
fprintf(stderr, "at line %d\n", __LINE__);
xstrdup_tolower("foo");
fprintf(stderr, "at line %d\n", __LINE__);
xstrdup_toupper("foo");
fprintf(stderr, "at line %d\n", __LINE__);
xstrfmt("%s", "foo");
fprintf(stderr, "at line %d\n", __LINE__);
}
static void error_builtin(const char *err, va_list params) {}
static void warn_builtin(const char *err, va_list params) {}
static void usage_funcs(void) {
fprintf(stderr, "calling usage functions\n");
error("foo");
error_errno("foo");
die_message("foo");
die_message_errno("foo");
warning("foo");
warning_errno("foo");
get_die_message_routine();
set_error_routine(error_builtin);
get_error_routine();
set_warn_routine(warn_builtin);
get_warn_routine();
}
static void wrapper_funcs(void) {
int tmp;
void *ptr = xmalloc(1);
int fd = open("/dev/null", O_RDONLY);
struct strbuf sb = STRBUF_INIT;
int mode = 0444;
char host[PATH_MAX], path[PATH_MAX], path1[PATH_MAX];
xsnprintf(path, sizeof(path), "out-XXXXXX");
xsnprintf(path1, sizeof(path1), "out-XXXXXX");
fprintf(stderr, "calling wrapper functions\n");
xstrdup("foo");
xmalloc(1);
xmallocz(1);
xmallocz_gently(1);
xmemdupz("foo", 3);
xstrndup("foo", 3);
xrealloc(ptr, 2);
xcalloc(1, 1);
xsetenv("foo", "bar", 0);
xopen("/dev/null", O_RDONLY);
xread(fd, &sb, 1);
xwrite(fd, &sb, 1);
xpread(fd, &sb, 1, 0);
xdup(fd);
xfopen("/dev/null", "r");
xfdopen(fd, "r");
tmp = xmkstemp(path);
close(tmp);
unlink(path);
tmp = xmkstemp_mode(path1, mode);
close(tmp);
unlink(path1);
xgetcwd();
fopen_for_writing(path);
fopen_or_warn(path, "r");
xstrncmpz("foo", "bar", 3);
xgethostname(host, 3);
tmp = git_mkstemps_mode(path, 1, mode);
close(tmp);
unlink(path);
tmp = git_mkstemp_mode(path, mode);
close(tmp);
unlink(path);
read_in_full(fd, &sb, 1);
write_in_full(fd, &sb, 1);
pread_in_full(fd, &sb, 1, 0);
}
int main(int argc, const char **argv) {
abspath_funcs();
hex_ll_funcs();
parse_funcs();
strbuf_funcs();
usage_funcs();
wrapper_funcs();
fprintf(stderr, "all git-std-lib functions finished calling\n");
return 0;
}

11
t/t0082-std-lib.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
test_description='Test git-std-lib compilation'
. ./test-lib.sh
test_expect_success !WINDOWS 'stdlib-test compiles and runs' '
test-stdlib
'
test_done