Apply documentation suggestions from code review

Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
This commit is contained in:
Yorick 2023-08-28 16:20:46 +02:00 committed by José Luis Lafuente
parent 3b41830a96
commit 40f5d48d3c
No known key found for this signature in database
GPG key ID: 8A3455EBE455489A
8 changed files with 65 additions and 44 deletions

View file

@ -1,11 +1,27 @@
# Getting started # Getting started
There are two ways to interface with nix: embedding it, or as a plugin. Embedding means you link one of the nix libraries in your program and use it from there, while being a plugin means you make a library that gets loaded by the nix evaluator, specified through a configuration option. These C bindings are **experimental** at the moment, which means they can still change any time or get removed again, but the plan is to provide a stable external C API to the Nix language and the Nix store.
The language library allows evaluating Nix expressions and interacting with Nix language values.
The Nix store API is still rudimentary, and only allows initialising and connecting to a store for the Nix language evaluator to interact with.
Currently there are two ways to interface with the Nix language evaluator programmatically:
1. Embedding the evaluator
2. Writing language plug-ins
Embedding means you link the Nix C libraries in your program and use them from there.
Adding a plug-in means you make a library that gets loaded by the Nix language evaluator, specified through a configuration option.
Many of the components and mechanisms involved are not yet documented, therefore please refer to the [Nix source code](https://github.com/NixOS/nix/) for details.
Additions to in-code documentation and the reference manual are highly appreciated.
The following examples, for simplicity, don't include error handling.
See the [Handling errors](@ref errors) section for more information.
# Embedding the Nix Evaluator # Embedding the Nix Evaluator
These examples don't include error handling. In this example we programmatically start the Nix language evaluator with a dummy store (that has no store paths and cannot be written to), and evaluate the Nix expression `builtins.nixVersion`.
See the [Handling errors](@ref errors) section for more information.
**main.c:** **main.c:**
```C ```C
@ -18,7 +34,7 @@ int main() {
nix_libexpr_init(NULL); nix_libexpr_init(NULL);
Store* store = nix_store_open(NULL, "dummy://", NULL); Store* store = nix_store_open(NULL, "dummy://", NULL);
State* state = nix_state_create(NULL, NULL, store); // empty nix path State* state = nix_state_create(NULL, NULL, store); // empty search path (NIX_PATH)
Value *value = nix_alloc_value(NULL, state); Value *value = nix_alloc_value(NULL, state);
nix_expr_eval_from_string(NULL, state, "builtins.nixVersion", ".", value); nix_expr_eval_from_string(NULL, state, "builtins.nixVersion", ".", value);
@ -40,7 +56,9 @@ nix version 1.2.3
``` ```
# Writing a Nix Plugin # Writing a Nix language plug-in
In this example we add a custom primitive operation (*primop*) to `builtins`.
It will increment the argument if it is an integer and return `null` otherwise.
**plugin.c:** **plugin.c:**
```C ```C
@ -59,7 +77,7 @@ void increment(State* state, int pos, Value** args, Value* v) {
void nix_plugin_entry() { void nix_plugin_entry() {
const char* args[] = {"n", NULL}; const char* args[] = {"n", NULL};
PrimOp *p = nix_alloc_primop(NULL, increment, 1, "increment", args, "Example nix plugin function: increments an int"); PrimOp *p = nix_alloc_primop(NULL, increment, 1, "increment", args, "Example custom built-in function: increments an integer");
nix_register_primop(NULL, p); nix_register_primop(NULL, p);
nix_gc_decref(NULL, p); nix_gc_decref(NULL, p);
} }

View file

@ -18,7 +18,7 @@ PROJECT_NUMBER = @PACKAGE_VERSION@
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short. # quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "Nix, the purely functional package manager; stable external interfaces" PROJECT_BRIEF = "Nix, the purely functional package manager: C API (experimental)"
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES. # The default value is: YES.

View file

@ -3,7 +3,7 @@ libdir=@libdir@
includedir=@includedir@ includedir=@includedir@
Name: Nix Name: Nix
Description: Nix Package Manager - C API Description: Nix Language Evaluator - C API
Version: @PACKAGE_VERSION@ Version: @PACKAGE_VERSION@
Requires: nix-store-c Requires: nix-store-c
Libs: -L${libdir} -lnixexprc Libs: -L${libdir} -lnixexprc

View file

@ -1,7 +1,7 @@
#ifndef NIX_API_EXPR_H #ifndef NIX_API_EXPR_H
#define NIX_API_EXPR_H #define NIX_API_EXPR_H
/** @defgroup libexpr libexpr /** @defgroup libexpr libexpr
* @brief Bindings to the Nix evaluator * @brief Bindings to the Nix language evaluator
* *
* Example (without error handling): * Example (without error handling):
* @code{.c} * @code{.c}
@ -38,17 +38,18 @@ extern "C" {
// Type definitions // Type definitions
/** /**
* @brief Represents a nix evaluator state. * @brief Represents a state of the Nix language evaluator.
* *
* Multiple can be created for multi-threaded * Multiple states can be created for multi-threaded
* operation. * operation.
* @struct State * @struct State
* @see nix_state_create
*/ */
typedef struct State State; // nix::EvalState typedef struct State State; // nix::EvalState
/** /**
* @brief Represents a nix value. * @brief Represents a value in the Nix language.
* *
* Owned by the GC. * Owned by the garbage collector.
* @struct Value * @struct Value
* @see value_manip * @see value_manip
*/ */
@ -56,7 +57,7 @@ typedef void Value; // nix::Value
// Function prototypes // Function prototypes
/** /**
* @brief Initializes the Nix expression evaluator. * @brief Initialize the Nix language evaluator.
* *
* This function should be called before creating a State. * This function should be called before creating a State.
* This function can be called multiple times. * This function can be called multiple times.
@ -73,6 +74,7 @@ nix_err nix_libexpr_init(nix_c_context *context);
* @param[in] state The state of the evaluation. * @param[in] state The state of the evaluation.
* @param[in] expr The Nix expression to parse. * @param[in] expr The Nix expression to parse.
* @param[in] path The file path to associate with the expression. * @param[in] path The file path to associate with the expression.
* This is required for expressions that contain relative paths (such as `./.`) that are resolved relative to the given directory.
* @param[out] value The result of the evaluation. You should allocate this * @param[out] value The result of the evaluation. You should allocate this
* yourself. * yourself.
* @return NIX_OK if the evaluation was successful, an error code otherwise. * @return NIX_OK if the evaluation was successful, an error code otherwise.
@ -109,7 +111,7 @@ nix_err nix_value_call(nix_c_context *context, State *state, Value *fn,
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] state The state of the evaluation. * @param[in] state The state of the evaluation.
* @param[in,out] value The Nix value to force. * @param[in,out] value The Nix value to force.
* @post values is not of type NIX_TYPE_THUNK * @post value is not of type NIX_TYPE_THUNK
* @return NIX_OK if the force operation was successful, an error code * @return NIX_OK if the force operation was successful, an error code
* otherwise. * otherwise.
*/ */
@ -133,10 +135,10 @@ nix_err nix_value_force_deep(nix_c_context *context, State *state,
Value *value); Value *value);
/** /**
* @brief Creates a new Nix state. * @brief Create a new Nix language evaluator state.
* *
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] searchPath The NIX_PATH. * @param[in] searchPath Array of strings corresponding to entries in NIX_PATH.
* @param[in] store The Nix store to use. * @param[in] store The Nix store to use.
* @return A new Nix state or NULL on failure. * @return A new Nix state or NULL on failure.
*/ */
@ -155,28 +157,28 @@ void nix_state_free(State *state);
/** @addtogroup GC /** @addtogroup GC
* @brief Reference counting and garbage collector operations * @brief Reference counting and garbage collector operations
* *
* Nix's evaluator uses a garbage collector. To ease C interop, we implement * The Nix language evaluator uses a garbage collector. To ease C interop, we implement
* a reference counting scheme, where objects will be deallocated * a reference counting scheme, where objects will be deallocated
* when there are no references from the Nix side, and the reference count kept * when there are no references from the Nix side, and the reference count kept
* by the C API reaches `0`. * by the C API reaches `0`.
* *
* Functions returning a garbage-collected object will automatically increase * Functions returning a garbage-collected object will automatically increase
* the refcount for you. You should make sure to call `nix_gc_decref` when * the refcount for you. You should make sure to call `nix_gc_decref` when
* you're done. * you're done with a value returned by the evaluator.
* @{ * @{
*/ */
/** /**
* @brief Increase the GC refcount. * @brief Increment the garbage collector reference counter for the given object.
* *
* The nix C api keeps alive objects by refcounting. * The Nix language evaluator C API keeps track of alive objects by reference counting.
* When you're done with a refcounted pointer, call nix_gc_decref. * When you're done with a refcounted pointer, call nix_gc_decref().
* *
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] object The object to keep alive * @param[in] object The object to keep alive
*/ */
nix_err nix_gc_incref(nix_c_context *context, const void *object); nix_err nix_gc_incref(nix_c_context *context, const void *object);
/** /**
* @brief Decrease the GC refcount * @brief Decrement the garbage collector reference counter for the given object
* *
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] object The object to stop referencing * @param[in] object The object to stop referencing
@ -193,7 +195,7 @@ void nix_gc_now();
/** /**
* @brief Register a callback that gets called when the object is garbage * @brief Register a callback that gets called when the object is garbage
* collected. * collected.
* @note objects can only have a single finalizer. This function overwrites * @note Objects can only have a single finalizer. This function overwrites existing values
* silently. * silently.
* @param[in] obj the object to watch * @param[in] obj the object to watch
* @param[in] cd the data to pass to the finalizer * @param[in] cd the data to pass to the finalizer

View file

@ -22,7 +22,7 @@ extern "C" {
// cffi start // cffi start
/** /**
* @brief Represents a string owned by nix. * @brief Represents a string owned by the Nix language evaluator.
* @see nix_set_owned_string * @see nix_set_owned_string
*/ */
typedef struct nix_string_return nix_string_return; typedef struct nix_string_return nix_string_return;

View file

@ -73,9 +73,10 @@ typedef struct ExternalValue ExternalValue;
*/ */
typedef void (*PrimOpFun)(State *state, int pos, Value **args, Value *v); typedef void (*PrimOpFun)(State *state, int pos, Value **args, Value *v);
/** @brief Allocate a primop /** @brief Allocate a PrimOp
* *
* Owned by the GC. Use nix_gc_decref when you're done with the pointer * Owned by the garbage collector.
* Use nix_gc_decref() when you're done with the returned PrimOp.
* *
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] fun callback * @param[in] fun callback
@ -89,12 +90,12 @@ typedef void (*PrimOpFun)(State *state, int pos, Value **args, Value *v);
PrimOp *nix_alloc_primop(nix_c_context *context, PrimOpFun fun, int arity, PrimOp *nix_alloc_primop(nix_c_context *context, PrimOpFun fun, int arity,
const char *name, const char **args, const char *doc); const char *name, const char **args, const char *doc);
/** @brief add a primop to builtins /** @brief add a primop to the `builtins` attribute set
* *
* Only applies to new States. * Only applies to States created after this call.
* *
* Moves your primop into the global * Moves your PrimOp into the global evaluator
* registry, meaning your input primOp is no longer usable * registry, meaning your input PrimOp pointer is no longer usable
* (but still possibly subject to garbage collection). * (but still possibly subject to garbage collection).
* *
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
@ -108,7 +109,7 @@ nix_err nix_register_primop(nix_c_context *context, PrimOp *primOp);
/** @brief Allocate a Nix value /** @brief Allocate a Nix value
* *
* Owned by the GC. Use nix_gc_decref when you're done with the pointer * Owned by the GC. Use nix_gc_decref() when you're done with the pointer
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] state nix evaluator state * @param[in] state nix evaluator state
* @return value, or null in case of errors * @return value, or null in case of errors
@ -116,7 +117,7 @@ nix_err nix_register_primop(nix_c_context *context, PrimOp *primOp);
*/ */
Value *nix_alloc_value(nix_c_context *context, State *state); Value *nix_alloc_value(nix_c_context *context, State *state);
/** @addtogroup value_manip Manipulating values /** @addtogroup value_manip Manipulating values
* @brief Functions to inspect and change nix Value's * @brief Functions to inspect and change Nix language values, represented by Value.
* @{ * @{
*/ */
/** @name Getters /** @name Getters
@ -128,7 +129,7 @@ Value *nix_alloc_value(nix_c_context *context, State *state);
* @return type of nix value * @return type of nix value
*/ */
ValueType nix_get_type(nix_c_context *context, const Value *value); ValueType nix_get_type(nix_c_context *context, const Value *value);
/** @brief Get type name of value /** @brief Get type name of value as defined in the evaluator
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] value Nix value to inspect * @param[in] value Nix value to inspect
* @return type name, owned string * @return type name, owned string

View file

@ -3,7 +3,7 @@ libdir=@libdir@
includedir=@includedir@ includedir=@includedir@
Name: Nix Name: Nix
Description: Nix Package Manager - C API Description: Nix Store - C API
Version: @PACKAGE_VERSION@ Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lnixstorec -lnixutilc Libs: -L${libdir} -lnixstorec -lnixutilc
Cflags: -I${includedir}/nix Cflags: -I${includedir}/nix

View file

@ -19,9 +19,9 @@ extern "C" {
#endif #endif
// cffi start // cffi start
/** @brief reference to a nix store */ /** @brief Reference to a Nix store */
typedef struct Store Store; typedef struct Store Store;
/** @brief nix store path */ /** @brief Nix store path */
typedef struct StorePath StorePath; typedef struct StorePath StorePath;
/** /**
@ -79,9 +79,9 @@ nix_err nix_store_get_uri(nix_c_context *context, Store *store, char *dest,
// returns: owned StorePath* // returns: owned StorePath*
/** /**
* @brief parse a nix store path into a StorePath * @brief Parse a Nix store path into a StorePath
* *
* Don't forget to free this path using nix_store_path_free * @note Don't forget to free this path using nix_store_path_free()!
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] store nix store reference * @param[in] store nix store reference
* @param[in] path Path string to parse, copied * @param[in] path Path string to parse, copied
@ -90,7 +90,7 @@ nix_err nix_store_get_uri(nix_c_context *context, Store *store, char *dest,
StorePath *nix_store_parse_path(nix_c_context *context, Store *store, StorePath *nix_store_parse_path(nix_c_context *context, Store *store,
const char *path); const char *path);
/** @brief Deallocate a nix StorePath /** @brief Deallocate a StorePath
* *
* Does not fail. * Does not fail.
* @param[in] p the path to free * @param[in] p the path to free
@ -98,9 +98,9 @@ StorePath *nix_store_parse_path(nix_c_context *context, Store *store,
void nix_store_path_free(StorePath *p); void nix_store_path_free(StorePath *p);
/** /**
* @brief check if a storepath is valid (exists in the store) * @brief Check if a StorePath is valid (i.e. that corresponding store object and its closure of references exists in the store)
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] store nix store reference * @param[in] store Nix Store reference
* @param[in] path Path to check * @param[in] path Path to check
* @return true or false, error info in context * @return true or false, error info in context
*/ */
@ -109,12 +109,12 @@ bool nix_store_is_valid_path(nix_c_context *context, Store *store,
// nix_err nix_store_ensure(Store*, const char*); // nix_err nix_store_ensure(Store*, const char*);
// nix_err nix_store_build_paths(Store*); // nix_err nix_store_build_paths(Store*);
/** /**
* @brief Build a nix store path * @brief Realise a Nix store path
* *
* Blocking, calls cb once for each built output * Blocking, calls cb once for each built output
* *
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] store nix store reference * @param[in] store Nix Store reference
* @param[in] path Path to build * @param[in] path Path to build
* @param[in] userdata data to pass to every callback invocation * @param[in] userdata data to pass to every callback invocation
* @param[in] cb called for every built output * @param[in] cb called for every built output