@safe
D bindings for libgit2.
This is an incomplete binding, meaning we polish it as we use it. Right now, you
may use the binding directly if you're fine with writing non-safe functions or
breaking dip1000
. Note that the functions themselves are marked as @safe
;
it's just that some function parameters are simply un-obtainable in an @safe
context (e.g. cannot take address of local variable or a pointer to a pointer).
By polishing, we modify the function signatures and add attributes according to
the rules outlined in the Making It Ergonomic section
so that they can be used smoothly in Safe-D.
This shouldn't be required. When updating the bindings to new versions, consult
Updating Bindings section. If you really need to generate
the bindings, build the libgit2 subproject using CMake, install it to a local
directory, use clang
(NOT gcc
!) to preprocess the header file git2.h
to
git2.i
, and lastly run dstep
on
it.
cmake -DBUILD_TESTS=OFF -B build -S .
make -C build
DESTDIR="$PWD/install" make -C build install
clang -E -I$PWD/install/usr/local/include $PWD/install/usr/local/include/git2.h -o ../../source/git2/git2.i
dstep ../../source/git2/git2.i -o ../../source/git2/bindings.d
Thankfully the maintainers of libgit2 have been doing a tremendous job of keeping their changelog detailed. In addition, libgit2 rarely makes huge changes in its public API. Therefore, once we have the initial generated bindings, we can simply update the bindings by hand according to either the changelog or the diffs between tags generated by GitHub.
When hand-authoring these new functions/structs, you may consult the existing generated bindings as a reference.
If the new API is a completely new header file, you can use dstep
to process
that single header file (without preprocessing) after performing the build and
install steps specified in the Generating Bindings
section.
Currently, there's a Perl script that performs the "safeification" of the bindings according to the rules below.
- At the very least, all pointer parameters should have the
scope
attribute except forconst(char)*
-type parameters, where we're expected to pass a string usingsomeString.toStringz()
. If you're only adding ascope
attribute, you may just edit it in thebindings.d
file. - If a parameter is passed to be assigned (e.g.
git_clone
,git_remote_lookup
), use thescope out
attribute instead. You can usually infer this through the API documentation or the paramter (e.g. anout**
). If you're only replacing a pointer-to-pointer with ascope out
pointer parameter, you may just edit it in thebindings.d
file. - All pointer parameters should be replaced with
scope ref
as much as possible. This primarily applies to structs that have a declared body (such as all structs with the formgit_x_options
). If you're only replacing a pointer withscope ref
, you may just edit it in thebindings.d
file. However, note for exceptions as outlined in the rule below.- The
git_x_options
structs are particularly forgiving in that there are two identical functions for initializing them (git_x_init_options
andgit_x_options_init
). In this case, we choose to exempt thegit_x_init_options
functions from rule (3) and only apply rule (3) on thegit_x_options_init
functions).
- The
- Some structs, particularly structs who do not have a declared body and are
assigned through a pointer-to-pointer or a ref to a pointer (such as
git_repository
andgit_remote
), cannot be passed asref
since they must be declared as a pointer. In these cases, ignore rule (3) and follow rule (1). - Anything with
ref
/out
disallows passing lvalues to it, therefore rule (3) will break any function that intends you to passnull
to indicate an optional parameter. When this happens, copy the edited function into theextra.d
file and follow rule (1) for that parameter. For the edited function in theextra.d
file, you may add a=null
default value to that parameter if desired. For reference, search for the definition of the twogit_clone
functions.
On the ABI level, the signature of the functions are not changed. This is
only for the purpose of satisfying the compiler and adhereing to Safe-D.
(If you're wondering why we can't use the in
attribute, this is because
with --preview=in
, in
is not allowed in extern(C)
functions)