Contribution Guidelines
=======================

This library began as a personal project, and is primarily still maintained as
such.  The following list of guidelines is not necessarily exhaustive, and,
ultimately, any contribution is subject to the maintainer's discretion. That
being said, contributions are welcome, and most recent new features have been
added by users who need them!

Coding Style
------------

 - Go code must be formatted using the official `gofmt` tool.

 - C code should adhere to the portions of Google's C++ style guide that
   apply to C.

 - If at all possible, any Go or C code should have at most 80 character lines.
   (This may not be enforced very strictly.)

 - Purely stylistic changes are unlikely to be accepted. Instead, the
   maintainer or other contributers may make small stylistic adjustments to
   surrounding code as part of other contributions.

 - Attempt to mimic the existing style of the surrounding code.


Documentation
-------------

 - All Go types, public-facing functions, and nontrivial internal functions
   must include a comment on their intended usage, to be parsed by godoc.

 - As per the google C++ style guide, all C functions must be documented with a
   comment as well.  If a C function is defined in a header file, the comment
   should appear with the definition in the header. If it's a static function
   in a `.c` file, the comment should appear with the function definition.


Tests
-----

 - All new features and bugfixes must include a basic unit test (in
   `onnxruntime_test.go`) to serve as a sanity check.

 - If a test is for a platform-dependent or execution-provider-dependent
   feature, the test must be skipped if run on an unsupported system.

 - No tests should panic.  Always check errors and fail rather than allowing
   tests to panic.

 - Every change must ensure that `go test -v -bench=.` passes.

 - Every test failure should be accompanied by a message containing the reason,
   either using `t.Logf()`, `t.Errorf()`, or `t.Fatalf()`.


Adding New Files
----------------

 - Apart from testing data, try not to add new source files.

 - Do not add third-party code or headers.  The only exceptions for now are
   `onnxruntime_c_api.h` and `onnxruntime_ep_c_api.h`.

 - No C++ at all. Developing Go-to-C wrappers is annoying enough as it is.

 - Do not add any new `onnxruntime` shared libraries under `test_data`. I know
   there are additional platforms that would be nice to include (such as
   `x86_64` Linux), but I do not want this project turning into an unofficial
   distribution channel for onnxruntime libraries.  It also clogs up the git
   repo with large files, and increases the size of the history every time
   these files are updated.  The libraries that are included were only intended
   to allow a majority of users to run `go test -v -bench=.` without further
   setup or modification. Currently: amd64 Windows, arm64 Linux (I wish I
   hadn't included this!), and arm64 osx. All other users must set the
   `ONNXRUNTIME_SHARED_LIBRARY_PATH` environment variable to a valid path
   to the correct `onnxruntime` shared library file prior to running tests.

 - If you need to add a .onnx file for a test, place both the .onnx file
   _and_ the script used to generate it into `test_data/`.

 - Keep any testing .onnx files as small as possible.

 - Without a good reason (i.e., implementing an entire class of APIs such as
   training), avoid adding new Go files---just add to `onnxruntime_go.go`.


Dependencies
------------

 - Avoid Go or C dependencies outside of the language's standard libraries.
   This package currently does not depend on any third-party Go modules, and
   it would be great to keep it this way.

 - Python scripts within `test_data/` can use whatever dependencies they need,
   because end users should not be required to run the python files, and the
   `.onnx` file they produce should already be included.


C-Specific Stuff
----------------

 - Minimize Go management of C-allocated memory as much as possible. For
   example, see the `convertORTString` function on `onnxruntime_go.go`, which
   copies a C-allocated string into a garbage-collected go `string`.

 - If you need to use a `OrtAllocator` in onnxruntime's C API, always use the
   default `OrtAllocator` returned by
   `ort_api->GetAllocatorWithDefaultOptions()`.

 - ONNXRuntime APIs requiring file paths typically use `ORTCHAR_T*`
   strings. On Linux/OSX/etc, these should be UTF-8, but on Windows they will
   be wide-character strings. (Our tricks with `#include` to make them look
   like `char*` to C code even on Windows, but the DLL still expects a
   `wchar_t*`.)  The important takeaway: when passing `ORTCHAR_T*`
   values to the onnxruntime C API, use the `createOrtCharString(...)`
   function. It converts a Go string to a C string, but unlike `C.CString`, it
   will do UTF8 to UTF16 conversion on Windows. (On Linux, it simply wraps
   `C.CString`.)


A Few Notes on Organization
---------------------------

 - The `onnxruntime` C API uses a struct containing function pointers. Cgo
   can't directly invoke functions via pointers, so `onnxruntime_wrapper.c`
   (along with the associated header file) are used to provide top-level C
   functions that call the function pointers within the `OrtApi` struct.

 - Linux and OSX use `dlopen` to load the onnxruntime shared library, but this
   isn't possible on Windows, which instead can use the `syscall.LoadLibrary()`
   function from Go's standard library. This different behavior is locked
   behind build constraints in `setup_env.go` and `setup_env_windows.go`,
   respectively.

