mirror of
https://github.com/NixOS/nix
synced 2025-07-06 21:41:48 +02:00
Merge remote-tracking branch 'upstream/master' into rm-createdirs
This commit is contained in:
commit
a1bb668ccb
112 changed files with 2290 additions and 893 deletions
|
@ -42,56 +42,56 @@ nix_err nix_libexpr_init(nix_c_context * context)
|
|||
}
|
||||
|
||||
nix_err nix_expr_eval_from_string(
|
||||
nix_c_context * context, EvalState * state, const char * expr, const char * path, Value * value)
|
||||
nix_c_context * context, EvalState * state, const char * expr, const char * path, nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
nix::Expr * parsedExpr = state->state.parseExprFromString(expr, state->state.rootPath(nix::CanonPath(path)));
|
||||
state->state.eval(parsedExpr, *(nix::Value *) value);
|
||||
state->state.forceValue(*(nix::Value *) value, nix::noPos);
|
||||
state->state.eval(parsedExpr, value->value);
|
||||
state->state.forceValue(value->value, nix::noPos);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, Value * arg, Value * value)
|
||||
nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, nix_value * arg, nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
state->state.callFunction(*(nix::Value *) fn, *(nix::Value *) arg, *(nix::Value *) value, nix::noPos);
|
||||
state->state.forceValue(*(nix::Value *) value, nix::noPos);
|
||||
state->state.callFunction(fn->value, arg->value, value->value, nix::noPos);
|
||||
state->state.forceValue(value->value, nix::noPos);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_value_call_multi(nix_c_context * context, EvalState * state, Value * fn, size_t nargs, Value ** args, Value * value)
|
||||
nix_err nix_value_call_multi(nix_c_context * context, EvalState * state, nix_value * fn, size_t nargs, nix_value ** args, nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
state->state.callFunction(*(nix::Value *) fn, nargs, (nix::Value * *)args, *(nix::Value *) value, nix::noPos);
|
||||
state->state.forceValue(*(nix::Value *) value, nix::noPos);
|
||||
state->state.callFunction(fn->value, nargs, (nix::Value * *)args, value->value, nix::noPos);
|
||||
state->state.forceValue(value->value, nix::noPos);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_value_force(nix_c_context * context, EvalState * state, Value * value)
|
||||
nix_err nix_value_force(nix_c_context * context, EvalState * state, nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
state->state.forceValue(*(nix::Value *) value, nix::noPos);
|
||||
state->state.forceValue(value->value, nix::noPos);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, Value * value)
|
||||
nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
state->state.forceValueDeep(*(nix::Value *) value);
|
||||
state->state.forceValueDeep(value->value);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
@ -181,6 +181,15 @@ nix_err nix_gc_decref(nix_c_context * context, const void *)
|
|||
void nix_gc_now() {}
|
||||
#endif
|
||||
|
||||
nix_err nix_value_incref(nix_c_context * context, nix_value *x)
|
||||
{
|
||||
return nix_gc_incref(context, (const void *) x);
|
||||
}
|
||||
nix_err nix_value_decref(nix_c_context * context, nix_value *x)
|
||||
{
|
||||
return nix_gc_decref(context, (const void *) x);
|
||||
}
|
||||
|
||||
void nix_gc_register_finalizer(void * obj, void * cd, void (*finalizer)(void * obj, void * cd))
|
||||
{
|
||||
#ifdef HAVE_BOEHMGC
|
||||
|
|
|
@ -29,14 +29,23 @@ extern "C" {
|
|||
* @see nix_state_create
|
||||
*/
|
||||
typedef struct EvalState EvalState; // nix::EvalState
|
||||
/**
|
||||
* @brief Represents a value in the Nix language.
|
||||
|
||||
/** @brief A Nix language value, or thunk that may evaluate to a value.
|
||||
*
|
||||
* Values are the primary objects manipulated in the Nix language.
|
||||
* They are considered to be immutable from a user's perspective, but the process of evaluating a value changes its
|
||||
* ValueType if it was a thunk. After a value has been evaluated, its ValueType does not change.
|
||||
*
|
||||
* Evaluation in this context refers to the process of evaluating a single value object, also called "forcing" the
|
||||
* value; see `nix_value_force`.
|
||||
*
|
||||
* The evaluator manages its own memory, but your use of the C API must follow the reference counting rules.
|
||||
*
|
||||
* Owned by the garbage collector.
|
||||
* @struct Value
|
||||
* @see value_manip
|
||||
* @see nix_value_incref, nix_value_decref
|
||||
*/
|
||||
typedef void Value; // nix::Value
|
||||
typedef struct nix_value nix_value;
|
||||
[[deprecated("use nix_value instead")]] typedef nix_value Value;
|
||||
|
||||
// Function prototypes
|
||||
/**
|
||||
|
@ -65,7 +74,7 @@ nix_err nix_libexpr_init(nix_c_context * context);
|
|||
* @return NIX_OK if the evaluation was successful, an error code otherwise.
|
||||
*/
|
||||
nix_err nix_expr_eval_from_string(
|
||||
nix_c_context * context, EvalState * state, const char * expr, const char * path, Value * value);
|
||||
nix_c_context * context, EvalState * state, const char * expr, const char * path, nix_value * value);
|
||||
|
||||
/**
|
||||
* @brief Calls a Nix function with an argument.
|
||||
|
@ -79,7 +88,7 @@ nix_err nix_expr_eval_from_string(
|
|||
* @see nix_init_apply() for a similar function that does not performs the call immediately, but stores it as a thunk.
|
||||
* Note the different argument order.
|
||||
*/
|
||||
nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, Value * arg, Value * value);
|
||||
nix_err nix_value_call(nix_c_context * context, EvalState * state, nix_value * fn, nix_value * arg, nix_value * value);
|
||||
|
||||
/**
|
||||
* @brief Calls a Nix function with multiple arguments.
|
||||
|
@ -98,7 +107,7 @@ nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, V
|
|||
* @see NIX_VALUE_CALL For a macro that wraps this function for convenience.
|
||||
*/
|
||||
nix_err nix_value_call_multi(
|
||||
nix_c_context * context, EvalState * state, Value * fn, size_t nargs, Value ** args, Value * value);
|
||||
nix_c_context * context, EvalState * state, nix_value * fn, size_t nargs, nix_value ** args, nix_value * value);
|
||||
|
||||
/**
|
||||
* @brief Calls a Nix function with multiple arguments.
|
||||
|
@ -116,7 +125,7 @@ nix_err nix_value_call_multi(
|
|||
*/
|
||||
#define NIX_VALUE_CALL(context, state, value, fn, ...) \
|
||||
do { \
|
||||
Value * args_array[] = {__VA_ARGS__}; \
|
||||
nix_value * args_array[] = {__VA_ARGS__}; \
|
||||
size_t nargs = sizeof(args_array) / sizeof(args_array[0]); \
|
||||
nix_value_call_multi(context, state, fn, nargs, args_array, value); \
|
||||
} while (0)
|
||||
|
@ -124,12 +133,10 @@ nix_err nix_value_call_multi(
|
|||
/**
|
||||
* @brief Forces the evaluation of a Nix value.
|
||||
*
|
||||
* The Nix interpreter is lazy, and not-yet-evaluated Values can be
|
||||
* The Nix interpreter is lazy, and not-yet-evaluated values can be
|
||||
* of type NIX_TYPE_THUNK instead of their actual value.
|
||||
*
|
||||
* This function converts these Values into their final type.
|
||||
*
|
||||
* @note This function is mainly needed before calling @ref getters, but not for API calls that return a `Value`.
|
||||
* This function mutates such a `nix_value`, so that, if successful, it has its final type.
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] state The state of the evaluation.
|
||||
|
@ -138,7 +145,7 @@ nix_err nix_value_call_multi(
|
|||
* @return NIX_OK if the force operation was successful, an error code
|
||||
* otherwise.
|
||||
*/
|
||||
nix_err nix_value_force(nix_c_context * context, EvalState * state, Value * value);
|
||||
nix_err nix_value_force(nix_c_context * context, EvalState * state, nix_value * value);
|
||||
|
||||
/**
|
||||
* @brief Forces the deep evaluation of a Nix value.
|
||||
|
@ -154,7 +161,7 @@ nix_err nix_value_force(nix_c_context * context, EvalState * state, Value * valu
|
|||
* @return NIX_OK if the deep force operation was successful, an error code
|
||||
* otherwise.
|
||||
*/
|
||||
nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, Value * value);
|
||||
nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_value * value);
|
||||
|
||||
/**
|
||||
* @brief Create a new Nix language evaluator state.
|
||||
|
@ -188,6 +195,11 @@ void nix_state_free(EvalState * state);
|
|||
* you're done with a value returned by the evaluator.
|
||||
* @{
|
||||
*/
|
||||
|
||||
// TODO: Deprecate nix_gc_incref in favor of the type-specific reference counting functions?
|
||||
// e.g. nix_value_incref.
|
||||
// It gives implementors more flexibility, and adds safety, so that generated
|
||||
// bindings can be used without fighting the host type system (where applicable).
|
||||
/**
|
||||
* @brief Increment the garbage collector reference counter for the given object.
|
||||
*
|
||||
|
|
|
@ -20,6 +20,11 @@ struct ListBuilder
|
|||
nix::ListBuilder builder;
|
||||
};
|
||||
|
||||
struct nix_value
|
||||
{
|
||||
nix::Value value;
|
||||
};
|
||||
|
||||
struct nix_string_return
|
||||
{
|
||||
std::string str;
|
||||
|
|
|
@ -21,49 +21,54 @@
|
|||
#endif
|
||||
|
||||
// Internal helper functions to check [in] and [out] `Value *` parameters
|
||||
static const nix::Value & check_value_not_null(const Value * value)
|
||||
static const nix::Value & check_value_not_null(const nix_value * value)
|
||||
{
|
||||
if (!value) {
|
||||
throw std::runtime_error("Value is null");
|
||||
throw std::runtime_error("nix_value is null");
|
||||
}
|
||||
return *((const nix::Value *) value);
|
||||
}
|
||||
|
||||
static nix::Value & check_value_not_null(Value * value)
|
||||
static nix::Value & check_value_not_null(nix_value * value)
|
||||
{
|
||||
if (!value) {
|
||||
throw std::runtime_error("Value is null");
|
||||
throw std::runtime_error("nix_value is null");
|
||||
}
|
||||
return *((nix::Value *) value);
|
||||
return value->value;
|
||||
}
|
||||
|
||||
static const nix::Value & check_value_in(const Value * value)
|
||||
static const nix::Value & check_value_in(const nix_value * value)
|
||||
{
|
||||
auto & v = check_value_not_null(value);
|
||||
if (!v.isValid()) {
|
||||
throw std::runtime_error("Uninitialized Value");
|
||||
throw std::runtime_error("Uninitialized nix_value");
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static nix::Value & check_value_in(Value * value)
|
||||
static nix::Value & check_value_in(nix_value * value)
|
||||
{
|
||||
auto & v = check_value_not_null(value);
|
||||
if (!v.isValid()) {
|
||||
throw std::runtime_error("Uninitialized Value");
|
||||
throw std::runtime_error("Uninitialized nix_value");
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static nix::Value & check_value_out(Value * value)
|
||||
static nix::Value & check_value_out(nix_value * value)
|
||||
{
|
||||
auto & v = check_value_not_null(value);
|
||||
if (v.isValid()) {
|
||||
throw std::runtime_error("Value already initialized. Variables are immutable");
|
||||
throw std::runtime_error("nix_value already initialized. Variables are immutable");
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline nix_value * as_nix_value_ptr(nix::Value * v)
|
||||
{
|
||||
return reinterpret_cast<nix_value *>(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to convert calls from nix into C API.
|
||||
*
|
||||
|
@ -87,7 +92,7 @@ static void nix_c_primop_wrapper(
|
|||
// or maybe something to make blackholes work better; we don't know).
|
||||
nix::Value vTmp;
|
||||
|
||||
f(userdata, &ctx, (EvalState *) &state, (Value **) args, (Value *) &vTmp);
|
||||
f(userdata, &ctx, (EvalState *) &state, (nix_value **) args, (nix_value *) &vTmp);
|
||||
|
||||
if (ctx.last_err_code != NIX_OK) {
|
||||
/* TODO: Throw different errors depending on the error code */
|
||||
|
@ -154,19 +159,19 @@ nix_err nix_register_primop(nix_c_context * context, PrimOp * primOp)
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
Value * nix_alloc_value(nix_c_context * context, EvalState * state)
|
||||
nix_value * nix_alloc_value(nix_c_context * context, EvalState * state)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
Value * res = state->state.allocValue();
|
||||
nix_value * res = as_nix_value_ptr(state->state.allocValue());
|
||||
nix_gc_incref(nullptr, res);
|
||||
return res;
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
ValueType nix_get_type(nix_c_context * context, const Value * value)
|
||||
ValueType nix_get_type(nix_c_context * context, const nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -202,7 +207,7 @@ ValueType nix_get_type(nix_c_context * context, const Value * value)
|
|||
NIXC_CATCH_ERRS_RES(NIX_TYPE_NULL);
|
||||
}
|
||||
|
||||
const char * nix_get_typename(nix_c_context * context, const Value * value)
|
||||
const char * nix_get_typename(nix_c_context * context, const nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -214,7 +219,7 @@ const char * nix_get_typename(nix_c_context * context, const Value * value)
|
|||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
bool nix_get_bool(nix_c_context * context, const Value * value)
|
||||
bool nix_get_bool(nix_c_context * context, const nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -226,7 +231,8 @@ bool nix_get_bool(nix_c_context * context, const Value * value)
|
|||
NIXC_CATCH_ERRS_RES(false);
|
||||
}
|
||||
|
||||
nix_err nix_get_string(nix_c_context * context, const Value * value, nix_get_string_callback callback, void * user_data)
|
||||
nix_err
|
||||
nix_get_string(nix_c_context * context, const nix_value * value, nix_get_string_callback callback, void * user_data)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -238,7 +244,7 @@ nix_err nix_get_string(nix_c_context * context, const Value * value, nix_get_str
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
const char * nix_get_path_string(nix_c_context * context, const Value * value)
|
||||
const char * nix_get_path_string(nix_c_context * context, const nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -257,7 +263,7 @@ const char * nix_get_path_string(nix_c_context * context, const Value * value)
|
|||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
unsigned int nix_get_list_size(nix_c_context * context, const Value * value)
|
||||
unsigned int nix_get_list_size(nix_c_context * context, const nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -269,7 +275,7 @@ unsigned int nix_get_list_size(nix_c_context * context, const Value * value)
|
|||
NIXC_CATCH_ERRS_RES(0);
|
||||
}
|
||||
|
||||
unsigned int nix_get_attrs_size(nix_c_context * context, const Value * value)
|
||||
unsigned int nix_get_attrs_size(nix_c_context * context, const nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -281,7 +287,7 @@ unsigned int nix_get_attrs_size(nix_c_context * context, const Value * value)
|
|||
NIXC_CATCH_ERRS_RES(0);
|
||||
}
|
||||
|
||||
double nix_get_float(nix_c_context * context, const Value * value)
|
||||
double nix_get_float(nix_c_context * context, const nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -293,7 +299,7 @@ double nix_get_float(nix_c_context * context, const Value * value)
|
|||
NIXC_CATCH_ERRS_RES(0.0);
|
||||
}
|
||||
|
||||
int64_t nix_get_int(nix_c_context * context, const Value * value)
|
||||
int64_t nix_get_int(nix_c_context * context, const nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -305,7 +311,7 @@ int64_t nix_get_int(nix_c_context * context, const Value * value)
|
|||
NIXC_CATCH_ERRS_RES(0);
|
||||
}
|
||||
|
||||
ExternalValue * nix_get_external(nix_c_context * context, Value * value)
|
||||
ExternalValue * nix_get_external(nix_c_context * context, nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -317,7 +323,7 @@ ExternalValue * nix_get_external(nix_c_context * context, Value * value)
|
|||
NIXC_CATCH_ERRS_NULL;
|
||||
}
|
||||
|
||||
Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int ix)
|
||||
nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int ix)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -328,12 +334,12 @@ Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalSta
|
|||
nix_gc_incref(nullptr, p);
|
||||
if (p != nullptr)
|
||||
state->state.forceValue(*p, nix::noPos);
|
||||
return (Value *) p;
|
||||
return as_nix_value_ptr(p);
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name)
|
||||
nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -345,7 +351,7 @@ Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalSt
|
|||
if (attr) {
|
||||
nix_gc_incref(nullptr, attr->value);
|
||||
state->state.forceValue(*attr->value, nix::noPos);
|
||||
return attr->value;
|
||||
return as_nix_value_ptr(attr->value);
|
||||
}
|
||||
nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute");
|
||||
return nullptr;
|
||||
|
@ -353,7 +359,7 @@ Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalSt
|
|||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name)
|
||||
bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -369,8 +375,8 @@ bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState
|
|||
NIXC_CATCH_ERRS_RES(false);
|
||||
}
|
||||
|
||||
Value *
|
||||
nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i, const char ** name)
|
||||
nix_value * nix_get_attr_byidx(
|
||||
nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i, const char ** name)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -380,12 +386,13 @@ nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * sta
|
|||
*name = ((const std::string &) (state->state.symbols[a.name])).c_str();
|
||||
nix_gc_incref(nullptr, a.value);
|
||||
state->state.forceValue(*a.value, nix::noPos);
|
||||
return a.value;
|
||||
return as_nix_value_ptr(a.value);
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i)
|
||||
const char *
|
||||
nix_get_attr_name_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -397,7 +404,7 @@ const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * valu
|
|||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
nix_err nix_init_bool(nix_c_context * context, Value * value, bool b)
|
||||
nix_err nix_init_bool(nix_c_context * context, nix_value * value, bool b)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -409,7 +416,7 @@ nix_err nix_init_bool(nix_c_context * context, Value * value, bool b)
|
|||
}
|
||||
|
||||
// todo string context
|
||||
nix_err nix_init_string(nix_c_context * context, Value * value, const char * str)
|
||||
nix_err nix_init_string(nix_c_context * context, nix_value * value, const char * str)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -420,7 +427,7 @@ nix_err nix_init_string(nix_c_context * context, Value * value, const char * str
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_init_path_string(nix_c_context * context, EvalState * s, Value * value, const char * str)
|
||||
nix_err nix_init_path_string(nix_c_context * context, EvalState * s, nix_value * value, const char * str)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -431,7 +438,7 @@ nix_err nix_init_path_string(nix_c_context * context, EvalState * s, Value * val
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_init_float(nix_c_context * context, Value * value, double d)
|
||||
nix_err nix_init_float(nix_c_context * context, nix_value * value, double d)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -442,7 +449,7 @@ nix_err nix_init_float(nix_c_context * context, Value * value, double d)
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_init_int(nix_c_context * context, Value * value, int64_t i)
|
||||
nix_err nix_init_int(nix_c_context * context, nix_value * value, int64_t i)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -453,7 +460,7 @@ nix_err nix_init_int(nix_c_context * context, Value * value, int64_t i)
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_init_null(nix_c_context * context, Value * value)
|
||||
nix_err nix_init_null(nix_c_context * context, nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -464,7 +471,7 @@ nix_err nix_init_null(nix_c_context * context, Value * value)
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_init_apply(nix_c_context * context, Value * value, Value * fn, Value * arg)
|
||||
nix_err nix_init_apply(nix_c_context * context, nix_value * value, nix_value * fn, nix_value * arg)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -477,7 +484,7 @@ nix_err nix_init_apply(nix_c_context * context, Value * value, Value * fn, Value
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_init_external(nix_c_context * context, Value * value, ExternalValue * val)
|
||||
nix_err nix_init_external(nix_c_context * context, nix_value * value, ExternalValue * val)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -504,7 +511,8 @@ ListBuilder * nix_make_list_builder(nix_c_context * context, EvalState * state,
|
|||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
nix_err nix_list_builder_insert(nix_c_context * context, ListBuilder * list_builder, unsigned int index, Value * value)
|
||||
nix_err
|
||||
nix_list_builder_insert(nix_c_context * context, ListBuilder * list_builder, unsigned int index, nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -524,7 +532,7 @@ void nix_list_builder_free(ListBuilder * list_builder)
|
|||
#endif
|
||||
}
|
||||
|
||||
nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, Value * value)
|
||||
nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -535,7 +543,7 @@ nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, Value
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_init_primop(nix_c_context * context, Value * value, PrimOp * p)
|
||||
nix_err nix_init_primop(nix_c_context * context, nix_value * value, PrimOp * p)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -546,7 +554,7 @@ nix_err nix_init_primop(nix_c_context * context, Value * value, PrimOp * p)
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_copy_value(nix_c_context * context, Value * value, const Value * source)
|
||||
nix_err nix_copy_value(nix_c_context * context, nix_value * value, const nix_value * source)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -558,7 +566,7 @@ nix_err nix_copy_value(nix_c_context * context, Value * value, const Value * sou
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_make_attrs(nix_c_context * context, Value * value, BindingsBuilder * b)
|
||||
nix_err nix_make_attrs(nix_c_context * context, nix_value * value, BindingsBuilder * b)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -584,7 +592,7 @@ BindingsBuilder * nix_make_bindings_builder(nix_c_context * context, EvalState *
|
|||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
nix_err nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * bb, const char * name, Value * value)
|
||||
nix_err nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * bb, const char * name, nix_value * value)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -605,7 +613,7 @@ void nix_bindings_builder_free(BindingsBuilder * bb)
|
|||
#endif
|
||||
}
|
||||
|
||||
nix_realised_string * nix_string_realise(nix_c_context * context, EvalState * state, Value * value, bool isIFD)
|
||||
nix_realised_string * nix_string_realise(nix_c_context * context, EvalState * state, nix_value * value, bool isIFD)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
|
|
@ -35,8 +35,11 @@ typedef enum {
|
|||
} ValueType;
|
||||
|
||||
// forward declarations
|
||||
typedef void Value;
|
||||
typedef struct nix_value nix_value;
|
||||
typedef struct EvalState EvalState;
|
||||
|
||||
[[deprecated("use nix_value instead")]] typedef nix_value Value;
|
||||
|
||||
// type defs
|
||||
/** @brief Stores an under-construction set of bindings
|
||||
* @ingroup value_manip
|
||||
|
@ -90,7 +93,8 @@ typedef struct nix_realised_string nix_realised_string;
|
|||
* @param[out] ret return value
|
||||
* @see nix_alloc_primop, nix_init_primop
|
||||
*/
|
||||
typedef void (*PrimOpFun)(void * user_data, nix_c_context * context, EvalState * state, Value ** args, Value * ret);
|
||||
typedef void (*PrimOpFun)(
|
||||
void * user_data, nix_c_context * context, EvalState * state, nix_value ** args, nix_value * ret);
|
||||
|
||||
/** @brief Allocate a PrimOp
|
||||
*
|
||||
|
@ -142,10 +146,29 @@ nix_err nix_register_primop(nix_c_context * context, PrimOp * primOp);
|
|||
* @return value, or null in case of errors
|
||||
*
|
||||
*/
|
||||
Value * nix_alloc_value(nix_c_context * context, EvalState * state);
|
||||
nix_value * nix_alloc_value(nix_c_context * context, EvalState * state);
|
||||
|
||||
/**
|
||||
* @brief Increment the garbage collector reference counter for the given `nix_value`.
|
||||
*
|
||||
* The Nix language evaluator C API keeps track of alive objects by reference counting.
|
||||
* When you're done with a refcounted pointer, call nix_value_decref().
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value The object to keep alive
|
||||
*/
|
||||
nix_err nix_value_incref(nix_c_context * context, nix_value * value);
|
||||
|
||||
/**
|
||||
* @brief Decrement the garbage collector reference counter for the given object
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value The object to stop referencing
|
||||
*/
|
||||
nix_err nix_value_decref(nix_c_context * context, nix_value * value);
|
||||
|
||||
/** @addtogroup value_manip Manipulating values
|
||||
* @brief Functions to inspect and change Nix language values, represented by Value.
|
||||
* @brief Functions to inspect and change Nix language values, represented by nix_value.
|
||||
* @{
|
||||
*/
|
||||
/** @anchor getters
|
||||
|
@ -157,7 +180,7 @@ Value * nix_alloc_value(nix_c_context * context, EvalState * state);
|
|||
* @param[in] value Nix value to inspect
|
||||
* @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 nix_value * value);
|
||||
|
||||
/** @brief Get type name of value as defined in the evaluator
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -165,14 +188,14 @@ ValueType nix_get_type(nix_c_context * context, const Value * value);
|
|||
* @return type name, owned string
|
||||
* @todo way to free the result
|
||||
*/
|
||||
const char * nix_get_typename(nix_c_context * context, const Value * value);
|
||||
const char * nix_get_typename(nix_c_context * context, const nix_value * value);
|
||||
|
||||
/** @brief Get boolean value
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return true or false, error info via context
|
||||
*/
|
||||
bool nix_get_bool(nix_c_context * context, const Value * value);
|
||||
bool nix_get_bool(nix_c_context * context, const nix_value * value);
|
||||
|
||||
/** @brief Get the raw string
|
||||
*
|
||||
|
@ -186,7 +209,7 @@ bool nix_get_bool(nix_c_context * context, const Value * value);
|
|||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err
|
||||
nix_get_string(nix_c_context * context, const Value * value, nix_get_string_callback callback, void * user_data);
|
||||
nix_get_string(nix_c_context * context, const nix_value * value, nix_get_string_callback callback, void * user_data);
|
||||
|
||||
/** @brief Get path as string
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -194,42 +217,42 @@ nix_get_string(nix_c_context * context, const Value * value, nix_get_string_call
|
|||
* @return string
|
||||
* @return NULL in case of error.
|
||||
*/
|
||||
const char * nix_get_path_string(nix_c_context * context, const Value * value);
|
||||
const char * nix_get_path_string(nix_c_context * context, const nix_value * value);
|
||||
|
||||
/** @brief Get the length of a list
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return length of list, error info via context
|
||||
*/
|
||||
unsigned int nix_get_list_size(nix_c_context * context, const Value * value);
|
||||
unsigned int nix_get_list_size(nix_c_context * context, const nix_value * value);
|
||||
|
||||
/** @brief Get the element count of an attrset
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return attrset element count, error info via context
|
||||
*/
|
||||
unsigned int nix_get_attrs_size(nix_c_context * context, const Value * value);
|
||||
unsigned int nix_get_attrs_size(nix_c_context * context, const nix_value * value);
|
||||
|
||||
/** @brief Get float value in 64 bits
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return float contents, error info via context
|
||||
*/
|
||||
double nix_get_float(nix_c_context * context, const Value * value);
|
||||
double nix_get_float(nix_c_context * context, const nix_value * value);
|
||||
|
||||
/** @brief Get int value
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return int contents, error info via context
|
||||
*/
|
||||
int64_t nix_get_int(nix_c_context * context, const Value * value);
|
||||
int64_t nix_get_int(nix_c_context * context, const nix_value * value);
|
||||
|
||||
/** @brief Get external reference
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return reference to external, NULL in case of error
|
||||
*/
|
||||
ExternalValue * nix_get_external(nix_c_context * context, Value *);
|
||||
ExternalValue * nix_get_external(nix_c_context * context, nix_value *);
|
||||
|
||||
/** @brief Get the ix'th element of a list
|
||||
*
|
||||
|
@ -240,7 +263,7 @@ ExternalValue * nix_get_external(nix_c_context * context, Value *);
|
|||
* @param[in] ix list element to get
|
||||
* @return value, NULL in case of errors
|
||||
*/
|
||||
Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int ix);
|
||||
nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int ix);
|
||||
|
||||
/** @brief Get an attr by name
|
||||
*
|
||||
|
@ -251,7 +274,7 @@ Value * nix_get_list_byidx(nix_c_context * context, const Value * value, EvalSta
|
|||
* @param[in] name attribute name
|
||||
* @return value, NULL in case of errors
|
||||
*/
|
||||
Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name);
|
||||
nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name);
|
||||
|
||||
/** @brief Check if an attribute name exists on a value
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -260,7 +283,7 @@ Value * nix_get_attr_byname(nix_c_context * context, const Value * value, EvalSt
|
|||
* @param[in] name attribute name
|
||||
* @return value, error info via context
|
||||
*/
|
||||
bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState * state, const char * name);
|
||||
bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name);
|
||||
|
||||
/** @brief Get an attribute by index in the sorted bindings
|
||||
*
|
||||
|
@ -274,8 +297,8 @@ bool nix_has_attr_byname(nix_c_context * context, const Value * value, EvalState
|
|||
* @param[out] name will store a pointer to the attribute name
|
||||
* @return value, NULL in case of errors
|
||||
*/
|
||||
Value *
|
||||
nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i, const char ** name);
|
||||
nix_value * nix_get_attr_byidx(
|
||||
nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i, const char ** name);
|
||||
|
||||
/** @brief Get an attribute name by index in the sorted bindings
|
||||
*
|
||||
|
@ -288,7 +311,8 @@ nix_get_attr_byidx(nix_c_context * context, const Value * value, EvalState * sta
|
|||
* @param[in] i attribute index
|
||||
* @return name, NULL in case of errors
|
||||
*/
|
||||
const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * value, EvalState * state, unsigned int i);
|
||||
const char *
|
||||
nix_get_attr_name_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i);
|
||||
|
||||
/**@}*/
|
||||
/** @name Initializers
|
||||
|
@ -305,7 +329,7 @@ const char * nix_get_attr_name_byidx(nix_c_context * context, const Value * valu
|
|||
* @param[in] b the boolean value
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_init_bool(nix_c_context * context, Value * value, bool b);
|
||||
nix_err nix_init_bool(nix_c_context * context, nix_value * value, bool b);
|
||||
|
||||
/** @brief Set a string
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -313,7 +337,7 @@ nix_err nix_init_bool(nix_c_context * context, Value * value, bool b);
|
|||
* @param[in] str the string, copied
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_init_string(nix_c_context * context, Value * value, const char * str);
|
||||
nix_err nix_init_string(nix_c_context * context, nix_value * value, const char * str);
|
||||
|
||||
/** @brief Set a path
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -321,7 +345,7 @@ nix_err nix_init_string(nix_c_context * context, Value * value, const char * str
|
|||
* @param[in] str the path string, copied
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_init_path_string(nix_c_context * context, EvalState * s, Value * value, const char * str);
|
||||
nix_err nix_init_path_string(nix_c_context * context, EvalState * s, nix_value * value, const char * str);
|
||||
|
||||
/** @brief Set a float
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -329,7 +353,7 @@ nix_err nix_init_path_string(nix_c_context * context, EvalState * s, Value * val
|
|||
* @param[in] d the float, 64-bits
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_init_float(nix_c_context * context, Value * value, double d);
|
||||
nix_err nix_init_float(nix_c_context * context, nix_value * value, double d);
|
||||
|
||||
/** @brief Set an int
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -338,13 +362,13 @@ nix_err nix_init_float(nix_c_context * context, Value * value, double d);
|
|||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
|
||||
nix_err nix_init_int(nix_c_context * context, Value * value, int64_t i);
|
||||
nix_err nix_init_int(nix_c_context * context, nix_value * value, int64_t i);
|
||||
/** @brief Set null
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_init_null(nix_c_context * context, Value * value);
|
||||
nix_err nix_init_null(nix_c_context * context, nix_value * value);
|
||||
|
||||
/** @brief Set the value to a thunk that will perform a function application when needed.
|
||||
*
|
||||
|
@ -360,7 +384,7 @@ nix_err nix_init_null(nix_c_context * context, Value * value);
|
|||
* @see nix_value_call() for a similar function that performs the call immediately and only stores the return value.
|
||||
* Note the different argument order.
|
||||
*/
|
||||
nix_err nix_init_apply(nix_c_context * context, Value * value, Value * fn, Value * arg);
|
||||
nix_err nix_init_apply(nix_c_context * context, nix_value * value, nix_value * fn, nix_value * arg);
|
||||
|
||||
/** @brief Set an external value
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -368,7 +392,7 @@ nix_err nix_init_apply(nix_c_context * context, Value * value, Value * fn, Value
|
|||
* @param[in] val the external value to set. Will be GC-referenced by the value.
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_init_external(nix_c_context * context, Value * value, ExternalValue * val);
|
||||
nix_err nix_init_external(nix_c_context * context, nix_value * value, ExternalValue * val);
|
||||
|
||||
/** @brief Create a list from a list builder
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -376,7 +400,7 @@ nix_err nix_init_external(nix_c_context * context, Value * value, ExternalValue
|
|||
* @param[out] value Nix value to modify
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, Value * value);
|
||||
nix_err nix_make_list(nix_c_context * context, ListBuilder * list_builder, nix_value * value);
|
||||
|
||||
/** @brief Create a list builder
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -393,7 +417,8 @@ ListBuilder * nix_make_list_builder(nix_c_context * context, EvalState * state,
|
|||
* @param[in] value value to insert
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_list_builder_insert(nix_c_context * context, ListBuilder * list_builder, unsigned int index, Value * value);
|
||||
nix_err
|
||||
nix_list_builder_insert(nix_c_context * context, ListBuilder * list_builder, unsigned int index, nix_value * value);
|
||||
|
||||
/** @brief Free a list builder
|
||||
*
|
||||
|
@ -408,7 +433,7 @@ void nix_list_builder_free(ListBuilder * list_builder);
|
|||
* @param[in] b bindings builder to use. Make sure to unref this afterwards.
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_make_attrs(nix_c_context * context, Value * value, BindingsBuilder * b);
|
||||
nix_err nix_make_attrs(nix_c_context * context, nix_value * value, BindingsBuilder * b);
|
||||
|
||||
/** @brief Set primop
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -417,14 +442,14 @@ nix_err nix_make_attrs(nix_c_context * context, Value * value, BindingsBuilder *
|
|||
* @see nix_alloc_primop
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_init_primop(nix_c_context * context, Value * value, PrimOp * op);
|
||||
nix_err nix_init_primop(nix_c_context * context, nix_value * value, PrimOp * op);
|
||||
/** @brief Copy from another value
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] source value to copy from
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_copy_value(nix_c_context * context, Value * value, const Value * source);
|
||||
nix_err nix_copy_value(nix_c_context * context, nix_value * value, const nix_value * source);
|
||||
/**@}*/
|
||||
|
||||
/** @brief Create a bindings builder
|
||||
|
@ -444,7 +469,7 @@ BindingsBuilder * nix_make_bindings_builder(nix_c_context * context, EvalState *
|
|||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err
|
||||
nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * builder, const char * name, Value * value);
|
||||
nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * builder, const char * name, nix_value * value);
|
||||
|
||||
/** @brief Free a bindings builder
|
||||
*
|
||||
|
@ -471,7 +496,7 @@ void nix_bindings_builder_free(BindingsBuilder * builder);
|
|||
You should set this to false when building for your application's purpose.
|
||||
* @return NULL if failed, are a new nix_realised_string, which must be freed with nix_realised_string_free
|
||||
*/
|
||||
nix_realised_string * nix_string_realise(nix_c_context * context, EvalState * state, Value * value, bool isIFD);
|
||||
nix_realised_string * nix_string_realise(nix_c_context * context, EvalState * state, nix_value * value, bool isIFD);
|
||||
|
||||
/** @brief Start of the string
|
||||
* @param[in] realised_string
|
||||
|
|
|
@ -31,7 +31,7 @@ struct CachedEvalError : EvalError
|
|||
class EvalCache : public std::enable_shared_from_this<EvalCache>
|
||||
{
|
||||
friend class AttrCursor;
|
||||
friend class CachedEvalError;
|
||||
friend struct CachedEvalError;
|
||||
|
||||
std::shared_ptr<AttrDb> db;
|
||||
EvalState & state;
|
||||
|
@ -87,7 +87,7 @@ typedef std::variant<
|
|||
class AttrCursor : public std::enable_shared_from_this<AttrCursor>
|
||||
{
|
||||
friend class EvalCache;
|
||||
friend class CachedEvalError;
|
||||
friend struct CachedEvalError;
|
||||
|
||||
ref<EvalCache> root;
|
||||
typedef std::optional<std::pair<std::shared_ptr<AttrCursor>, Symbol>> Parent;
|
||||
|
|
226
src/libexpr/eval-gc.cc
Normal file
226
src/libexpr/eval-gc.cc
Normal file
|
@ -0,0 +1,226 @@
|
|||
#include "error.hh"
|
||||
#include "environment-variables.hh"
|
||||
#include "serialise.hh"
|
||||
#include "eval-gc.hh"
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
|
||||
# include <pthread.h>
|
||||
# if __FreeBSD__
|
||||
# include <pthread_np.h>
|
||||
# endif
|
||||
|
||||
# include <gc/gc.h>
|
||||
# include <gc/gc_cpp.h>
|
||||
# include <gc/gc_allocator.h>
|
||||
|
||||
# include <boost/coroutine2/coroutine.hpp>
|
||||
# include <boost/coroutine2/protected_fixedsize_stack.hpp>
|
||||
# include <boost/context/stack_context.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
namespace nix {
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
/* Called when the Boehm GC runs out of memory. */
|
||||
static void * oomHandler(size_t requested)
|
||||
{
|
||||
/* Convert this to a proper C++ exception. */
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
class BoehmGCStackAllocator : public StackAllocator
|
||||
{
|
||||
boost::coroutines2::protected_fixedsize_stack stack{
|
||||
// We allocate 8 MB, the default max stack size on NixOS.
|
||||
// A smaller stack might be quicker to allocate but reduces the stack
|
||||
// depth available for source filter expressions etc.
|
||||
std::max(boost::context::stack_traits::default_size(), static_cast<std::size_t>(8 * 1024 * 1024))};
|
||||
|
||||
// This is specific to boost::coroutines2::protected_fixedsize_stack.
|
||||
// The stack protection page is included in sctx.size, so we have to
|
||||
// subtract one page size from the stack size.
|
||||
std::size_t pfss_usable_stack_size(boost::context::stack_context & sctx)
|
||||
{
|
||||
return sctx.size - boost::context::stack_traits::page_size();
|
||||
}
|
||||
|
||||
public:
|
||||
boost::context::stack_context allocate() override
|
||||
{
|
||||
auto sctx = stack.allocate();
|
||||
|
||||
// Stacks generally start at a high address and grow to lower addresses.
|
||||
// Architectures that do the opposite are rare; in fact so rare that
|
||||
// boost_routine does not implement it.
|
||||
// So we subtract the stack size.
|
||||
GC_add_roots(static_cast<char *>(sctx.sp) - pfss_usable_stack_size(sctx), sctx.sp);
|
||||
return sctx;
|
||||
}
|
||||
|
||||
void deallocate(boost::context::stack_context sctx) override
|
||||
{
|
||||
GC_remove_roots(static_cast<char *>(sctx.sp) - pfss_usable_stack_size(sctx), sctx.sp);
|
||||
stack.deallocate(sctx);
|
||||
}
|
||||
};
|
||||
|
||||
static BoehmGCStackAllocator boehmGCStackAllocator;
|
||||
|
||||
/**
|
||||
* When a thread goes into a coroutine, we lose its original sp until
|
||||
* control flow returns to the thread.
|
||||
* While in the coroutine, the sp points outside the thread stack,
|
||||
* so we can detect this and push the entire thread stack instead,
|
||||
* as an approximation.
|
||||
* The coroutine's stack is covered by `BoehmGCStackAllocator`.
|
||||
* This is not an optimal solution, because the garbage is scanned when a
|
||||
* coroutine is active, for both the coroutine and the original thread stack.
|
||||
* However, the implementation is quite lean, and usually we don't have active
|
||||
* coroutines during evaluation, so this is acceptable.
|
||||
*/
|
||||
void fixupBoehmStackPointer(void ** sp_ptr, void * _pthread_id)
|
||||
{
|
||||
void *& sp = *sp_ptr;
|
||||
auto pthread_id = reinterpret_cast<pthread_t>(_pthread_id);
|
||||
pthread_attr_t pattr;
|
||||
size_t osStackSize;
|
||||
void * osStackLow;
|
||||
void * osStackBase;
|
||||
|
||||
# ifdef __APPLE__
|
||||
osStackSize = pthread_get_stacksize_np(pthread_id);
|
||||
osStackLow = pthread_get_stackaddr_np(pthread_id);
|
||||
# else
|
||||
if (pthread_attr_init(&pattr)) {
|
||||
throw Error("fixupBoehmStackPointer: pthread_attr_init failed");
|
||||
}
|
||||
# ifdef HAVE_PTHREAD_GETATTR_NP
|
||||
if (pthread_getattr_np(pthread_id, &pattr)) {
|
||||
throw Error("fixupBoehmStackPointer: pthread_getattr_np failed");
|
||||
}
|
||||
# elif HAVE_PTHREAD_ATTR_GET_NP
|
||||
if (!pthread_attr_init(&pattr)) {
|
||||
throw Error("fixupBoehmStackPointer: pthread_attr_init failed");
|
||||
}
|
||||
if (!pthread_attr_get_np(pthread_id, &pattr)) {
|
||||
throw Error("fixupBoehmStackPointer: pthread_attr_get_np failed");
|
||||
}
|
||||
# else
|
||||
# error "Need one of `pthread_attr_get_np` or `pthread_getattr_np`"
|
||||
# endif
|
||||
if (pthread_attr_getstack(&pattr, &osStackLow, &osStackSize)) {
|
||||
throw Error("fixupBoehmStackPointer: pthread_attr_getstack failed");
|
||||
}
|
||||
if (pthread_attr_destroy(&pattr)) {
|
||||
throw Error("fixupBoehmStackPointer: pthread_attr_destroy failed");
|
||||
}
|
||||
# endif
|
||||
osStackBase = (char *) osStackLow + osStackSize;
|
||||
// NOTE: We assume the stack grows down, as it does on all architectures we support.
|
||||
// Architectures that grow the stack up are rare.
|
||||
if (sp >= osStackBase || sp < osStackLow) { // lo is outside the os stack
|
||||
sp = osStackBase;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable GC while this object lives. Used by CoroutineContext.
|
||||
*
|
||||
* Boehm keeps a count of GC_disable() and GC_enable() calls,
|
||||
* and only enables GC when the count matches.
|
||||
*/
|
||||
class BoehmDisableGC
|
||||
{
|
||||
public:
|
||||
BoehmDisableGC()
|
||||
{
|
||||
GC_disable();
|
||||
};
|
||||
~BoehmDisableGC()
|
||||
{
|
||||
GC_enable();
|
||||
};
|
||||
};
|
||||
|
||||
static inline void initGCReal()
|
||||
{
|
||||
/* Initialise the Boehm garbage collector. */
|
||||
|
||||
/* Don't look for interior pointers. This reduces the odds of
|
||||
misdetection a bit. */
|
||||
GC_set_all_interior_pointers(0);
|
||||
|
||||
/* We don't have any roots in data segments, so don't scan from
|
||||
there. */
|
||||
GC_set_no_dls(1);
|
||||
|
||||
GC_INIT();
|
||||
|
||||
GC_set_oom_fn(oomHandler);
|
||||
|
||||
StackAllocator::defaultAllocator = &boehmGCStackAllocator;
|
||||
|
||||
// TODO: Remove __APPLE__ condition.
|
||||
// Comment suggests an implementation that works on darwin and windows
|
||||
// https://github.com/ivmai/bdwgc/issues/362#issuecomment-1936672196
|
||||
# if GC_VERSION_MAJOR >= 8 && GC_VERSION_MINOR >= 2 && GC_VERSION_MICRO >= 4 && !defined(__APPLE__)
|
||||
GC_set_sp_corrector(&fixupBoehmStackPointer);
|
||||
|
||||
if (!GC_get_sp_corrector()) {
|
||||
printTalkative("BoehmGC on this platform does not support sp_corrector; will disable GC inside coroutines");
|
||||
/* Used to disable GC when entering coroutines on macOS */
|
||||
create_coro_gc_hook = []() -> std::shared_ptr<void> { return std::make_shared<BoehmDisableGC>(); };
|
||||
}
|
||||
# else
|
||||
# warning \
|
||||
"BoehmGC version does not support GC while coroutine exists. GC will be disabled inside coroutines. Consider updating bdw-gc to 8.2.4 or later."
|
||||
# endif
|
||||
|
||||
/* Set the initial heap size to something fairly big (25% of
|
||||
physical RAM, up to a maximum of 384 MiB) so that in most cases
|
||||
we don't need to garbage collect at all. (Collection has a
|
||||
fairly significant overhead.) The heap size can be overridden
|
||||
through libgc's GC_INITIAL_HEAP_SIZE environment variable. We
|
||||
should probably also provide a nix.conf setting for this. Note
|
||||
that GC_expand_hp() causes a lot of virtual, but not physical
|
||||
(resident) memory to be allocated. This might be a problem on
|
||||
systems that don't overcommit. */
|
||||
if (!getEnv("GC_INITIAL_HEAP_SIZE")) {
|
||||
size_t size = 32 * 1024 * 1024;
|
||||
# if HAVE_SYSCONF && defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
|
||||
size_t maxSize = 384 * 1024 * 1024;
|
||||
long pageSize = sysconf(_SC_PAGESIZE);
|
||||
long pages = sysconf(_SC_PHYS_PAGES);
|
||||
if (pageSize != -1)
|
||||
size = (pageSize * pages) / 4; // 25% of RAM
|
||||
if (size > maxSize)
|
||||
size = maxSize;
|
||||
# endif
|
||||
debug("setting initial heap size to %1% bytes", size);
|
||||
GC_expand_hp(size);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool gcInitialised = false;
|
||||
|
||||
void initGC()
|
||||
{
|
||||
if (gcInitialised)
|
||||
return;
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
initGCReal();
|
||||
#endif
|
||||
|
||||
gcInitialised = true;
|
||||
}
|
||||
|
||||
void assertGCInitialized()
|
||||
{
|
||||
assert(gcInitialised);
|
||||
}
|
||||
|
||||
}
|
16
src/libexpr/eval-gc.hh
Normal file
16
src/libexpr/eval-gc.hh
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* Initialise the Boehm GC, if applicable.
|
||||
*/
|
||||
void initGC();
|
||||
|
||||
/**
|
||||
* Make sure `initGC` has already been called.
|
||||
*/
|
||||
void assertGCInitialized();
|
||||
|
||||
}
|
|
@ -40,22 +40,16 @@
|
|||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#ifndef _WIN32 // TODO use portable implementation
|
||||
# include <sys/resource.h>
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
|
||||
#define GC_INCLUDE_NEW
|
||||
# define GC_INCLUDE_NEW
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <gc/gc.h>
|
||||
#include <gc/gc_cpp.h>
|
||||
#include <gc/gc_allocator.h>
|
||||
|
||||
#include <boost/coroutine2/coroutine.hpp>
|
||||
#include <boost/coroutine2/protected_fixedsize_stack.hpp>
|
||||
#include <boost/context/stack_context.hpp>
|
||||
# include <gc/gc.h>
|
||||
# include <gc/gc_cpp.h>
|
||||
# include <gc/gc_allocator.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -208,97 +202,6 @@ bool Value::isTrivial() const
|
|||
}
|
||||
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
/* Called when the Boehm GC runs out of memory. */
|
||||
static void * oomHandler(size_t requested)
|
||||
{
|
||||
/* Convert this to a proper C++ exception. */
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
class BoehmGCStackAllocator : public StackAllocator {
|
||||
boost::coroutines2::protected_fixedsize_stack stack {
|
||||
// We allocate 8 MB, the default max stack size on NixOS.
|
||||
// A smaller stack might be quicker to allocate but reduces the stack
|
||||
// depth available for source filter expressions etc.
|
||||
std::max(boost::context::stack_traits::default_size(), static_cast<std::size_t>(8 * 1024 * 1024))
|
||||
};
|
||||
|
||||
// This is specific to boost::coroutines2::protected_fixedsize_stack.
|
||||
// The stack protection page is included in sctx.size, so we have to
|
||||
// subtract one page size from the stack size.
|
||||
std::size_t pfss_usable_stack_size(boost::context::stack_context &sctx) {
|
||||
return sctx.size - boost::context::stack_traits::page_size();
|
||||
}
|
||||
|
||||
public:
|
||||
boost::context::stack_context allocate() override {
|
||||
auto sctx = stack.allocate();
|
||||
|
||||
// Stacks generally start at a high address and grow to lower addresses.
|
||||
// Architectures that do the opposite are rare; in fact so rare that
|
||||
// boost_routine does not implement it.
|
||||
// So we subtract the stack size.
|
||||
GC_add_roots(static_cast<char *>(sctx.sp) - pfss_usable_stack_size(sctx), sctx.sp);
|
||||
return sctx;
|
||||
}
|
||||
|
||||
void deallocate(boost::context::stack_context sctx) override {
|
||||
GC_remove_roots(static_cast<char *>(sctx.sp) - pfss_usable_stack_size(sctx), sctx.sp);
|
||||
stack.deallocate(sctx);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static BoehmGCStackAllocator boehmGCStackAllocator;
|
||||
|
||||
/**
|
||||
* When a thread goes into a coroutine, we lose its original sp until
|
||||
* control flow returns to the thread.
|
||||
* While in the coroutine, the sp points outside the thread stack,
|
||||
* so we can detect this and push the entire thread stack instead,
|
||||
* as an approximation.
|
||||
* The coroutine's stack is covered by `BoehmGCStackAllocator`.
|
||||
* This is not an optimal solution, because the garbage is scanned when a
|
||||
* coroutine is active, for both the coroutine and the original thread stack.
|
||||
* However, the implementation is quite lean, and usually we don't have active
|
||||
* coroutines during evaluation, so this is acceptable.
|
||||
*/
|
||||
void fixupBoehmStackPointer(void ** sp_ptr, void * pthread_id) {
|
||||
void *& sp = *sp_ptr;
|
||||
pthread_attr_t pattr;
|
||||
size_t osStackSize;
|
||||
void * osStackLow;
|
||||
void * osStackBase;
|
||||
|
||||
#ifdef __APPLE__
|
||||
osStackSize = pthread_get_stacksize_np((pthread_t)pthread_id);
|
||||
osStackLow = pthread_get_stackaddr_np((pthread_t)pthread_id);
|
||||
#else
|
||||
if (pthread_attr_init(&pattr)) {
|
||||
throw Error("fixupBoehmStackPointer: pthread_attr_init failed");
|
||||
}
|
||||
if (pthread_getattr_np((pthread_t)pthread_id, &pattr)) {
|
||||
throw Error("fixupBoehmStackPointer: pthread_getattr_np failed");
|
||||
}
|
||||
if (pthread_attr_getstack(&pattr, &osStackLow, &osStackSize)) {
|
||||
throw Error("fixupBoehmStackPointer: pthread_attr_getstack failed");
|
||||
}
|
||||
if (pthread_attr_destroy(&pattr)) {
|
||||
throw Error("fixupBoehmStackPointer: pthread_attr_destroy failed");
|
||||
}
|
||||
#endif
|
||||
osStackBase = (char *)osStackLow + osStackSize;
|
||||
// NOTE: We assume the stack grows down, as it does on all architectures we support.
|
||||
// Architectures that grow the stack up are rare.
|
||||
if (sp >= osStackBase || sp < osStackLow) { // lo is outside the os stack
|
||||
sp = osStackBase;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static Symbol getName(const AttrName & name, EvalState & state, Env & env)
|
||||
{
|
||||
if (name.symbol) {
|
||||
|
@ -311,92 +214,6 @@ static Symbol getName(const AttrName & name, EvalState & state, Env & env)
|
|||
}
|
||||
}
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
/* Disable GC while this object lives. Used by CoroutineContext.
|
||||
*
|
||||
* Boehm keeps a count of GC_disable() and GC_enable() calls,
|
||||
* and only enables GC when the count matches.
|
||||
*/
|
||||
class BoehmDisableGC {
|
||||
public:
|
||||
BoehmDisableGC() {
|
||||
GC_disable();
|
||||
};
|
||||
~BoehmDisableGC() {
|
||||
GC_enable();
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
static bool gcInitialised = false;
|
||||
|
||||
void initGC()
|
||||
{
|
||||
if (gcInitialised) return;
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
/* Initialise the Boehm garbage collector. */
|
||||
|
||||
/* Don't look for interior pointers. This reduces the odds of
|
||||
misdetection a bit. */
|
||||
GC_set_all_interior_pointers(0);
|
||||
|
||||
/* We don't have any roots in data segments, so don't scan from
|
||||
there. */
|
||||
GC_set_no_dls(1);
|
||||
|
||||
GC_INIT();
|
||||
|
||||
GC_set_oom_fn(oomHandler);
|
||||
|
||||
StackAllocator::defaultAllocator = &boehmGCStackAllocator;
|
||||
|
||||
// TODO: Remove __APPLE__ condition.
|
||||
// Comment suggests an implementation that works on darwin and windows
|
||||
// https://github.com/ivmai/bdwgc/issues/362#issuecomment-1936672196
|
||||
#if GC_VERSION_MAJOR >= 8 && GC_VERSION_MINOR >= 4 && !defined(__APPLE__)
|
||||
GC_set_sp_corrector(&fixupBoehmStackPointer);
|
||||
|
||||
if (!GC_get_sp_corrector()) {
|
||||
printTalkative("BoehmGC on this platform does not support sp_corrector; will disable GC inside coroutines");
|
||||
/* Used to disable GC when entering coroutines on macOS */
|
||||
create_coro_gc_hook = []() -> std::shared_ptr<void> {
|
||||
return std::make_shared<BoehmDisableGC>();
|
||||
};
|
||||
}
|
||||
#else
|
||||
#warning "BoehmGC version does not support GC while coroutine exists. GC will be disabled inside coroutines. Consider updating bwd-gc to 8.4 or later."
|
||||
#endif
|
||||
|
||||
|
||||
/* Set the initial heap size to something fairly big (25% of
|
||||
physical RAM, up to a maximum of 384 MiB) so that in most cases
|
||||
we don't need to garbage collect at all. (Collection has a
|
||||
fairly significant overhead.) The heap size can be overridden
|
||||
through libgc's GC_INITIAL_HEAP_SIZE environment variable. We
|
||||
should probably also provide a nix.conf setting for this. Note
|
||||
that GC_expand_hp() causes a lot of virtual, but not physical
|
||||
(resident) memory to be allocated. This might be a problem on
|
||||
systems that don't overcommit. */
|
||||
if (!getEnv("GC_INITIAL_HEAP_SIZE")) {
|
||||
size_t size = 32 * 1024 * 1024;
|
||||
#if HAVE_SYSCONF && defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
|
||||
size_t maxSize = 384 * 1024 * 1024;
|
||||
long pageSize = sysconf(_SC_PAGESIZE);
|
||||
long pages = sysconf(_SC_PHYS_PAGES);
|
||||
if (pageSize != -1)
|
||||
size = (pageSize * pages) / 4; // 25% of RAM
|
||||
if (size > maxSize) size = maxSize;
|
||||
#endif
|
||||
debug("setting initial heap size to %1% bytes", size);
|
||||
GC_expand_hp(size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
gcInitialised = true;
|
||||
}
|
||||
|
||||
static constexpr size_t BASE_ENV_SIZE = 128;
|
||||
|
||||
EvalState::EvalState(
|
||||
|
@ -493,7 +310,7 @@ EvalState::EvalState(
|
|||
|
||||
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
|
||||
|
||||
assert(gcInitialised);
|
||||
assertGCInitialized();
|
||||
|
||||
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "attr-set.hh"
|
||||
#include "eval-error.hh"
|
||||
#include "eval-gc.hh"
|
||||
#include "types.hh"
|
||||
#include "value.hh"
|
||||
#include "nixexpr.hh"
|
||||
|
@ -146,12 +147,6 @@ std::string printValue(EvalState & state, Value & v);
|
|||
std::ostream & operator << (std::ostream & os, const ValueType t);
|
||||
|
||||
|
||||
/**
|
||||
* Initialise the Boehm GC, if applicable.
|
||||
*/
|
||||
void initGC();
|
||||
|
||||
|
||||
struct RegexCache;
|
||||
|
||||
std::shared_ptr<RegexCache> makeRegexCache();
|
||||
|
|
|
@ -4062,17 +4062,23 @@ static RegisterPrimOp primop_convertHash({
|
|||
|
||||
struct RegexCache
|
||||
{
|
||||
// TODO use C++20 transparent comparison when available
|
||||
std::unordered_map<std::string_view, std::regex> cache;
|
||||
std::list<std::string> keys;
|
||||
struct State
|
||||
{
|
||||
// TODO use C++20 transparent comparison when available
|
||||
std::unordered_map<std::string_view, std::regex> cache;
|
||||
std::list<std::string> keys;
|
||||
};
|
||||
|
||||
Sync<State> state_;
|
||||
|
||||
std::regex get(std::string_view re)
|
||||
{
|
||||
auto it = cache.find(re);
|
||||
if (it != cache.end())
|
||||
auto state(state_.lock());
|
||||
auto it = state->cache.find(re);
|
||||
if (it != state->cache.end())
|
||||
return it->second;
|
||||
keys.emplace_back(re);
|
||||
return cache.emplace(keys.back(), std::regex(keys.back(), std::regex::extended)).first->second;
|
||||
state->keys.emplace_back(re);
|
||||
return state->cache.emplace(state->keys.back(), std::regex(state->keys.back(), std::regex::extended)).first->second;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
1
src/libstore/.version
Symbolic link
1
src/libstore/.version
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../.version
|
|
@ -25,6 +25,10 @@
|
|||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef _WIN32 // TODO abstract over proc exit status
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
@ -1033,7 +1037,7 @@ void DerivationGoal::buildDone()
|
|||
|
||||
BuildResult::Status st = BuildResult::MiscFailure;
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifndef _WIN32 // TODO abstract over proc exit status
|
||||
if (hook && WIFEXITED(status) && WEXITSTATUS(status) == 101)
|
||||
st = BuildResult::TimedOut;
|
||||
|
||||
|
|
10
src/libstore/linux/meson.build
Normal file
10
src/libstore/linux/meson.build
Normal file
|
@ -0,0 +1,10 @@
|
|||
sources += files(
|
||||
'personality.cc',
|
||||
)
|
||||
|
||||
include_dirs += include_directories('.')
|
||||
|
||||
headers += files(
|
||||
'fchmodat2-compat.hh',
|
||||
'personality.hh',
|
||||
)
|
|
@ -233,7 +233,7 @@ LocalStore::LocalStore(const Params & params)
|
|||
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
|
||||
if (!gr)
|
||||
printError("warning: the group '%1%' specified in 'build-users-group' does not exist", settings.buildUsersGroup);
|
||||
else {
|
||||
else if (!readOnly) {
|
||||
struct stat st;
|
||||
if (stat(realStoreDir.get().c_str(), &st))
|
||||
throw SysError("getting attributes of path '%1%'", realStoreDir);
|
||||
|
|
452
src/libstore/meson.build
Normal file
452
src/libstore/meson.build
Normal file
|
@ -0,0 +1,452 @@
|
|||
project('nix-store', 'cpp',
|
||||
version : files('.version'),
|
||||
default_options : [
|
||||
'cpp_std=c++2a',
|
||||
# TODO(Qyriad): increase the warning level
|
||||
'warning_level=1',
|
||||
'debug=true',
|
||||
'optimization=2',
|
||||
'errorlogs=true', # Please print logs for tests that fail
|
||||
],
|
||||
meson_version : '>= 1.1',
|
||||
license : 'LGPL-2.1-or-later',
|
||||
)
|
||||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
# See note in ../nix-util/meson.build
|
||||
deps_private = [ ]
|
||||
|
||||
# See note in ../nix-util/meson.build
|
||||
deps_public = [ ]
|
||||
|
||||
# See note in ../nix-util/meson.build
|
||||
deps_other = [ ]
|
||||
|
||||
configdata = configuration_data()
|
||||
|
||||
# TODO rename, because it will conflict with downstream projects
|
||||
configdata.set_quoted('PACKAGE_VERSION', meson.project_version())
|
||||
|
||||
configdata.set_quoted('SYSTEM', host_machine.system())
|
||||
|
||||
nix_util = dependency('nix-util')
|
||||
if nix_util.type_name() == 'internal'
|
||||
# subproject sadly no good for pkg-config module
|
||||
deps_other += nix_util
|
||||
else
|
||||
deps_public += nix_util
|
||||
endif
|
||||
|
||||
run_command('ln', '-s',
|
||||
meson.project_build_root() / '__nothing_link_target',
|
||||
meson.project_build_root() / '__nothing_symlink',
|
||||
check : true,
|
||||
)
|
||||
can_link_symlink = run_command('ln',
|
||||
meson.project_build_root() / '__nothing_symlink',
|
||||
meson.project_build_root() / '__nothing_hardlink',
|
||||
check : false,
|
||||
).returncode() == 0
|
||||
run_command('rm', '-f',
|
||||
meson.project_build_root() / '__nothing_symlink',
|
||||
meson.project_build_root() / '__nothing_hardlink',
|
||||
check : true,
|
||||
)
|
||||
summary('can hardlink to symlink', can_link_symlink, bool_yn : true)
|
||||
configdata.set('CAN_LINK_SYMLINK', can_link_symlink.to_int())
|
||||
|
||||
# Check for each of these functions, and create a define like `#define HAVE_LCHOWN 1`.
|
||||
#
|
||||
# Only need to do functions that deps (like `libnixutil`) didn't already
|
||||
# check for.
|
||||
check_funcs = [
|
||||
# Optionally used for canonicalising files from the build
|
||||
'lchown',
|
||||
]
|
||||
foreach funcspec : check_funcs
|
||||
define_name = 'HAVE_' + funcspec.underscorify().to_upper()
|
||||
define_value = cxx.has_function(funcspec).to_int()
|
||||
configdata.set(define_name, define_value)
|
||||
endforeach
|
||||
|
||||
has_acl_support = cxx.has_header('sys/xattr.h') \
|
||||
and cxx.has_function('llistxattr') \
|
||||
and cxx.has_function('lremovexattr')
|
||||
configdata.set('HAVE_ACL_SUPPORT', has_acl_support.to_int())
|
||||
|
||||
# This is only conditional to work around
|
||||
# https://github.com/mesonbuild/meson/issues/13293. It should be
|
||||
# unconditional.
|
||||
if not (host_machine.system() == 'windows' and cxx.get_id() == 'gcc')
|
||||
deps_private += dependency('threads')
|
||||
endif
|
||||
|
||||
boost = dependency(
|
||||
'boost',
|
||||
modules : ['container'],
|
||||
)
|
||||
# boost is a public dependency, but not a pkg-config dependency unfortunately, so we
|
||||
# put in `deps_other`.
|
||||
deps_other += boost
|
||||
|
||||
curl = dependency('libcurl', 'curl')
|
||||
deps_private += curl
|
||||
|
||||
# seccomp only makes sense on Linux
|
||||
is_linux = host_machine.system() == 'linux'
|
||||
seccomp_required = get_option('seccomp-sandboxing')
|
||||
if not is_linux and seccomp_required.enabled()
|
||||
warning('Force-enabling seccomp on non-Linux does not make sense')
|
||||
endif
|
||||
seccomp = dependency('libseccomp', 'seccomp', required : seccomp_required, version : '>=2.5.5')
|
||||
if is_linux and not seccomp.found()
|
||||
warning('Sandbox security is reduced because libseccomp has not been found! Please provide libseccomp if it supports your CPU architecture.')
|
||||
endif
|
||||
configdata.set('HAVE_SECCOMP', seccomp.found().to_int())
|
||||
deps_private += seccomp
|
||||
|
||||
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
|
||||
deps_public += nlohmann_json
|
||||
|
||||
sqlite = dependency('sqlite3', 'sqlite', version : '>=3.6.19')
|
||||
deps_private += sqlite
|
||||
|
||||
|
||||
enable_embedded_sandbox_shell = get_option('embedded-sandbox-shell')
|
||||
if enable_embedded_sandbox_shell
|
||||
# This one goes in config.h
|
||||
# The path to busybox is passed as a -D flag when compiling this_library.
|
||||
# Idk why, ask the old buildsystem.
|
||||
configdata.set('HAVE_EMBEDDED_SANDBOX_SHELL', 1)
|
||||
endif
|
||||
|
||||
generated_headers = []
|
||||
foreach header : [ 'schema.sql', 'ca-specific-schema.sql' ]
|
||||
generated_headers += custom_target(
|
||||
command : [ 'bash', '-c', '{ echo \'R"__NIX_STR(\' && cat @INPUT@ && echo \')__NIX_STR"\'; } > "$1"', '_ignored_argv0', '@OUTPUT@' ],
|
||||
input : header,
|
||||
output : '@PLAINNAME@.gen.hh',
|
||||
install : true,
|
||||
install_dir : get_option('includedir') / 'nix'
|
||||
)
|
||||
endforeach
|
||||
|
||||
if enable_embedded_sandbox_shell
|
||||
hexdump = find_program('hexdump', native : true)
|
||||
embedded_sandbox_shell_gen = custom_target(
|
||||
'embedded-sandbox-shell.gen.hh',
|
||||
command : [
|
||||
hexdump,
|
||||
'-v',
|
||||
'-e',
|
||||
'1/1 "0x%x," "\n"'
|
||||
],
|
||||
input : busybox.full_path(),
|
||||
output : 'embedded-sandbox-shell.gen.hh',
|
||||
capture : true,
|
||||
feed : true,
|
||||
)
|
||||
generated_headers += embedded_sandbox_shell_gen
|
||||
endif
|
||||
|
||||
config_h = configure_file(
|
||||
configuration : configdata,
|
||||
output : 'config-store.h',
|
||||
)
|
||||
|
||||
add_project_arguments(
|
||||
# TODO(Qyriad): Yes this is how the autoconf+Make system did it.
|
||||
# It would be nice for our headers to be idempotent instead.
|
||||
'-include', 'config-util.h',
|
||||
'-include', 'config-store.h',
|
||||
'-Wno-deprecated-declarations',
|
||||
'-Wimplicit-fallthrough',
|
||||
'-Werror=switch',
|
||||
'-Werror=switch-enum',
|
||||
'-Wdeprecated-copy',
|
||||
'-Wignored-qualifiers',
|
||||
# Enable assertions in libstdc++ by default. Harmless on libc++. Benchmarked
|
||||
# at ~1% overhead in `nix search`.
|
||||
#
|
||||
# FIXME: remove when we get meson 1.4.0 which will default this to on for us:
|
||||
# https://mesonbuild.com/Release-notes-for-1-4-0.html#ndebug-setting-now-controls-c-stdlib-assertions
|
||||
'-D_GLIBCXX_ASSERTIONS=1',
|
||||
language : 'cpp',
|
||||
)
|
||||
|
||||
sources = files(
|
||||
'binary-cache-store.cc',
|
||||
'build-result.cc',
|
||||
'build/derivation-goal.cc',
|
||||
'build/drv-output-substitution-goal.cc',
|
||||
'build/entry-points.cc',
|
||||
'build/goal.cc',
|
||||
'build/substitution-goal.cc',
|
||||
'build/worker.cc',
|
||||
'builtins/buildenv.cc',
|
||||
'builtins/fetchurl.cc',
|
||||
'builtins/unpack-channel.cc',
|
||||
'common-protocol.cc',
|
||||
'content-address.cc',
|
||||
'daemon.cc',
|
||||
'derivations.cc',
|
||||
'derived-path-map.cc',
|
||||
'derived-path.cc',
|
||||
'downstream-placeholder.cc',
|
||||
'dummy-store.cc',
|
||||
'export-import.cc',
|
||||
'filetransfer.cc',
|
||||
'gc.cc',
|
||||
'globals.cc',
|
||||
'http-binary-cache-store.cc',
|
||||
'indirect-root-store.cc',
|
||||
'keys.cc',
|
||||
'legacy-ssh-store.cc',
|
||||
'local-binary-cache-store.cc',
|
||||
'local-fs-store.cc',
|
||||
'local-overlay-store.cc',
|
||||
'local-store.cc',
|
||||
'log-store.cc',
|
||||
'machines.cc',
|
||||
'make-content-addressed.cc',
|
||||
'misc.cc',
|
||||
'names.cc',
|
||||
'nar-accessor.cc',
|
||||
'nar-info-disk-cache.cc',
|
||||
'nar-info.cc',
|
||||
'optimise-store.cc',
|
||||
'outputs-spec.cc',
|
||||
'parsed-derivations.cc',
|
||||
'path-info.cc',
|
||||
'path-references.cc',
|
||||
'path-with-outputs.cc',
|
||||
'path.cc',
|
||||
'pathlocks.cc',
|
||||
'posix-fs-canonicalise.cc',
|
||||
'profiles.cc',
|
||||
'realisation.cc',
|
||||
'remote-fs-accessor.cc',
|
||||
'remote-store.cc',
|
||||
's3-binary-cache-store.cc',
|
||||
'serve-protocol-connection.cc',
|
||||
'serve-protocol.cc',
|
||||
'sqlite.cc',
|
||||
'ssh-store-config.cc',
|
||||
'ssh-store.cc',
|
||||
'ssh.cc',
|
||||
'store-api.cc',
|
||||
'store-reference.cc',
|
||||
'uds-remote-store.cc',
|
||||
'worker-protocol-connection.cc',
|
||||
'worker-protocol.cc',
|
||||
)
|
||||
|
||||
include_dirs = [
|
||||
include_directories('.'),
|
||||
include_directories('build'),
|
||||
]
|
||||
|
||||
headers = [config_h] +files(
|
||||
'binary-cache-store.hh',
|
||||
'build-result.hh',
|
||||
'build/derivation-goal.hh',
|
||||
'build/drv-output-substitution-goal.hh',
|
||||
'build/goal.hh',
|
||||
'build/substitution-goal.hh',
|
||||
'build/worker.hh',
|
||||
'builtins.hh',
|
||||
'builtins/buildenv.hh',
|
||||
'common-protocol-impl.hh',
|
||||
'common-protocol.hh',
|
||||
'content-address.hh',
|
||||
'daemon.hh',
|
||||
'derivations.hh',
|
||||
'derived-path-map.hh',
|
||||
'derived-path.hh',
|
||||
'downstream-placeholder.hh',
|
||||
'filetransfer.hh',
|
||||
'gc-store.hh',
|
||||
'globals.hh',
|
||||
'indirect-root-store.hh',
|
||||
'keys.hh',
|
||||
'legacy-ssh-store.hh',
|
||||
'length-prefixed-protocol-helper.hh',
|
||||
'local-fs-store.hh',
|
||||
'local-overlay-store.hh',
|
||||
'local-store.hh',
|
||||
'log-store.hh',
|
||||
'machines.hh',
|
||||
'make-content-addressed.hh',
|
||||
'names.hh',
|
||||
'nar-accessor.hh',
|
||||
'nar-info-disk-cache.hh',
|
||||
'nar-info.hh',
|
||||
'outputs-spec.hh',
|
||||
'parsed-derivations.hh',
|
||||
'path-info.hh',
|
||||
'path-references.hh',
|
||||
'path-regex.hh',
|
||||
'path-with-outputs.hh',
|
||||
'path.hh',
|
||||
'pathlocks.hh',
|
||||
'posix-fs-canonicalise.hh',
|
||||
'profiles.hh',
|
||||
'realisation.hh',
|
||||
'remote-fs-accessor.hh',
|
||||
'remote-store-connection.hh',
|
||||
'remote-store.hh',
|
||||
's3-binary-cache-store.hh',
|
||||
's3.hh',
|
||||
'serve-protocol-connection.hh',
|
||||
'serve-protocol-impl.hh',
|
||||
'serve-protocol.hh',
|
||||
'sqlite.hh',
|
||||
'ssh-store-config.hh',
|
||||
'ssh.hh',
|
||||
'store-api.hh',
|
||||
'store-cast.hh',
|
||||
'store-dir-config.hh',
|
||||
'store-reference.hh',
|
||||
'uds-remote-store.hh',
|
||||
'worker-protocol-connection.hh',
|
||||
'worker-protocol-impl.hh',
|
||||
'worker-protocol.hh',
|
||||
)
|
||||
|
||||
if host_machine.system() == 'linux'
|
||||
subdir('linux')
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
subdir('windows')
|
||||
else
|
||||
subdir('unix')
|
||||
endif
|
||||
|
||||
fs = import('fs')
|
||||
|
||||
prefix = get_option('prefix')
|
||||
# For each of these paths, assume that it is relative to the prefix unless
|
||||
# it is already an absolute path (which is the default for store-dir, state-dir, and log-dir).
|
||||
path_opts = [
|
||||
# Meson built-ins.
|
||||
'datadir',
|
||||
'bindir',
|
||||
'mandir',
|
||||
'libdir',
|
||||
'includedir',
|
||||
'libexecdir',
|
||||
# Homecooked Nix directories.
|
||||
'store-dir',
|
||||
'state-dir',
|
||||
'log-dir',
|
||||
]
|
||||
# For your grepping pleasure, this loop sets the following variables that aren't mentioned
|
||||
# literally above:
|
||||
# store_dir
|
||||
# state_dir
|
||||
# log_dir
|
||||
# profile_dir
|
||||
foreach optname : path_opts
|
||||
varname = optname.replace('-', '_')
|
||||
path = get_option(optname)
|
||||
if fs.is_absolute(path)
|
||||
set_variable(varname, path)
|
||||
else
|
||||
set_variable(varname, prefix / path)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
# sysconfdir doesn't get anything installed to directly, and is only used to
|
||||
# tell Nix where to look for nix.conf, so it doesn't get appended to prefix.
|
||||
sysconfdir = get_option('sysconfdir')
|
||||
if not fs.is_absolute(sysconfdir)
|
||||
sysconfdir = '/' / sysconfdir
|
||||
endif
|
||||
|
||||
lsof = find_program('lsof', required : false)
|
||||
|
||||
# Aside from prefix itself, each of these was made into an absolute path
|
||||
# by joining it with prefix, unless it was already an absolute path
|
||||
# (which is the default for store-dir, state-dir, and log-dir).
|
||||
cpp_str_defines = {
|
||||
'NIX_PREFIX': prefix,
|
||||
'NIX_STORE_DIR': store_dir,
|
||||
'NIX_DATA_DIR': datadir,
|
||||
'NIX_STATE_DIR': state_dir / 'nix',
|
||||
'NIX_LOG_DIR': log_dir,
|
||||
'NIX_CONF_DIR': sysconfdir / 'nix',
|
||||
'NIX_BIN_DIR': bindir,
|
||||
'NIX_MAN_DIR': mandir,
|
||||
}
|
||||
|
||||
if lsof.found()
|
||||
lsof_path = lsof.full_path()
|
||||
else
|
||||
# Just look up on the PATH
|
||||
lsof_path = 'lsof'
|
||||
endif
|
||||
cpp_str_defines += {
|
||||
'LSOF': lsof_path
|
||||
}
|
||||
|
||||
#if busybox.found()
|
||||
cpp_str_defines += {
|
||||
# 'SANDBOX_SHELL': busybox.full_path()
|
||||
}
|
||||
#endif
|
||||
|
||||
cpp_args = []
|
||||
|
||||
foreach name, value : cpp_str_defines
|
||||
cpp_args += [
|
||||
'-D' + name + '=' + '"' + value + '"'
|
||||
]
|
||||
endforeach
|
||||
|
||||
if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
|
||||
# See note in `../nix-util/meson.build`
|
||||
linker_export_flags = ['-Wl,--export-all-symbols']
|
||||
else
|
||||
linker_export_flags = []
|
||||
endif
|
||||
|
||||
this_library = library(
|
||||
'nixstore',
|
||||
generated_headers,
|
||||
sources,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
cpp_args : cpp_args,
|
||||
link_args: linker_export_flags,
|
||||
install : true,
|
||||
)
|
||||
|
||||
install_headers(headers, subdir : 'nix', preserve_path : true)
|
||||
|
||||
requires = deps_public
|
||||
if nix_util.type_name() == 'internal'
|
||||
# `requires` cannot contain declared dependencies (from the
|
||||
# subproject), so we need to do this manually
|
||||
requires = [ 'nix-util' ] + requires
|
||||
endif
|
||||
|
||||
import('pkgconfig').generate(
|
||||
this_library,
|
||||
filebase : meson.project_name(),
|
||||
name : 'Nix',
|
||||
description : 'Nix Package Manager',
|
||||
subdirs : ['nix'],
|
||||
extra_cflags : ['-std=c++2a'],
|
||||
requires : requires,
|
||||
requires_private : deps_private,
|
||||
libraries_private : ['-lboost_container'],
|
||||
)
|
||||
|
||||
meson.override_dependency(meson.project_name(), declare_dependency(
|
||||
include_directories : include_dirs,
|
||||
link_with : this_library,
|
||||
compile_args : ['-std=c++2a'],
|
||||
dependencies : [nix_util],
|
||||
))
|
25
src/libstore/meson.options
Normal file
25
src/libstore/meson.options
Normal file
|
@ -0,0 +1,25 @@
|
|||
# vim: filetype=meson
|
||||
|
||||
option('embedded-sandbox-shell', type : 'boolean', value : false,
|
||||
description : 'include the sandbox shell in the Nix binary',
|
||||
)
|
||||
|
||||
option('seccomp-sandboxing', type : 'feature',
|
||||
description : 'build support for seccomp sandboxing (recommended unless your arch doesn\'t support libseccomp, only relevant on Linux)',
|
||||
)
|
||||
|
||||
option('sandbox-shell', type : 'string', value : 'busybox',
|
||||
description : 'path to a statically-linked shell to use as /bin/sh in sandboxes (usually busybox)',
|
||||
)
|
||||
|
||||
option('store-dir', type : 'string', value : '/nix/store',
|
||||
description : 'path of the Nix store',
|
||||
)
|
||||
|
||||
option('state-dir', type : 'string', value : '/nix/var',
|
||||
description : 'path to store state in for Nix',
|
||||
)
|
||||
|
||||
option('log-dir', type : 'string', value : '/nix/var/log/nix',
|
||||
description : 'path to store logs in for Nix',
|
||||
)
|
142
src/libstore/package.nix
Normal file
142
src/libstore/package.nix
Normal file
|
@ -0,0 +1,142 @@
|
|||
{ lib
|
||||
, stdenv
|
||||
, releaseTools
|
||||
, fileset
|
||||
|
||||
, meson
|
||||
, ninja
|
||||
, pkg-config
|
||||
|
||||
, nix-util
|
||||
, boost
|
||||
, curl
|
||||
, aws-sdk-cpp
|
||||
, libseccomp
|
||||
, nlohmann_json
|
||||
, man
|
||||
, sqlite
|
||||
|
||||
, busybox-sandbox-shell ? null
|
||||
|
||||
# Configuration Options
|
||||
|
||||
, versionSuffix ? ""
|
||||
, officialRelease ? false
|
||||
|
||||
# Check test coverage of Nix. Probably want to use with at least
|
||||
# one of `doCheck` or `doInstallCheck` enabled.
|
||||
, withCoverageChecks ? false
|
||||
|
||||
# Avoid setting things that would interfere with a functioning devShell
|
||||
, forDevShell ? false
|
||||
}:
|
||||
|
||||
let
|
||||
version = lib.fileContents ./.version + versionSuffix;
|
||||
|
||||
mkDerivation =
|
||||
if withCoverageChecks
|
||||
then
|
||||
# TODO support `finalAttrs` args function in
|
||||
# `releaseTools.coverageAnalysis`.
|
||||
argsFun:
|
||||
releaseTools.coverageAnalysis (let args = argsFun args; in args)
|
||||
else stdenv.mkDerivation;
|
||||
in
|
||||
|
||||
mkDerivation (finalAttrs: {
|
||||
pname = "nix-store";
|
||||
inherit version;
|
||||
|
||||
src = fileset.toSource {
|
||||
root = ./.;
|
||||
fileset = fileset.unions [
|
||||
./meson.build
|
||||
./meson.options
|
||||
./linux/meson.build
|
||||
./unix/meson.build
|
||||
./windows/meson.build
|
||||
(fileset.fileFilter (file: file.hasExt "cc") ./.)
|
||||
(fileset.fileFilter (file: file.hasExt "hh") ./.)
|
||||
(fileset.fileFilter (file: file.hasExt "sb") ./.)
|
||||
(fileset.fileFilter (file: file.hasExt "md") ./.)
|
||||
(fileset.fileFilter (file: file.hasExt "sql") ./.)
|
||||
];
|
||||
};
|
||||
|
||||
outputs = [ "out" "dev" ];
|
||||
|
||||
nativeBuildInputs = [
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
boost
|
||||
curl
|
||||
sqlite
|
||||
] ++ lib.optional stdenv.hostPlatform.isLinux libseccomp
|
||||
# There have been issues building these dependencies
|
||||
++ lib.optional (stdenv.hostPlatform == stdenv.buildPlatform && (stdenv.isLinux || stdenv.isDarwin))
|
||||
(aws-sdk-cpp.override {
|
||||
apis = ["s3" "transfer"];
|
||||
customMemoryManagement = false;
|
||||
})
|
||||
;
|
||||
|
||||
propagatedBuildInputs = [
|
||||
nix-util
|
||||
nlohmann_json
|
||||
];
|
||||
|
||||
disallowedReferences = [ boost ];
|
||||
|
||||
preConfigure =
|
||||
# "Inline" .version so it's not a symlink, and includes the suffix
|
||||
''
|
||||
echo ${version} > .version
|
||||
'';
|
||||
|
||||
mesonFlags = [
|
||||
(lib.mesonEnable "seccomp-sandboxing" stdenv.hostPlatform.isLinux)
|
||||
(lib.mesonBool "embedded-sandbox-shell" stdenv.hostPlatform.isStatic)
|
||||
] ++ lib.optionals stdenv.hostPlatform.isLinux [
|
||||
(lib.mesonOption "sandbox-shell" "${busybox-sandbox-shell}/bin/busybox")
|
||||
];
|
||||
|
||||
env = {
|
||||
# Needed for Meson to find Boost.
|
||||
# https://github.com/NixOS/nixpkgs/issues/86131.
|
||||
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
|
||||
BOOST_LIBRARYDIR = "${lib.getLib boost}/lib";
|
||||
} // lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) {
|
||||
LDFLAGS = "-fuse-ld=gold";
|
||||
};
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
||||
postInstall =
|
||||
# Remove absolute path to boost libs that ends up in `Libs.private`
|
||||
# by default, and would clash with out `disallowedReferences`. Part
|
||||
# of the https://github.com/NixOS/nixpkgs/issues/45462 workaround.
|
||||
''
|
||||
sed -i "$out/lib/pkgconfig/nix-store.pc" -e 's, ${lib.getLib boost}[^ ]*,,g'
|
||||
'';
|
||||
|
||||
separateDebugInfo = !stdenv.hostPlatform.isStatic;
|
||||
|
||||
# TODO Always true after https://github.com/NixOS/nixpkgs/issues/318564
|
||||
strictDeps = !withCoverageChecks;
|
||||
|
||||
hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie";
|
||||
|
||||
meta = {
|
||||
platforms = lib.platforms.unix ++ lib.platforms.windows;
|
||||
};
|
||||
|
||||
} // lib.optionalAttrs withCoverageChecks {
|
||||
lcovFilter = [ "*/boost/*" "*-tab.*" ];
|
||||
|
||||
hardeningDisable = [ "fortify" ];
|
||||
})
|
|
@ -1500,7 +1500,7 @@ void LocalDerivationGoal::startDaemon()
|
|||
throw SysError("accepting connection");
|
||||
}
|
||||
|
||||
closeOnExec(remote.get());
|
||||
unix::closeOnExec(remote.get());
|
||||
|
||||
debug("received daemon connection");
|
||||
|
||||
|
@ -1961,7 +1961,7 @@ void LocalDerivationGoal::runChild()
|
|||
throw SysError("changing into '%1%'", tmpDir);
|
||||
|
||||
/* Close all other file descriptors. */
|
||||
closeMostFDs({STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO});
|
||||
unix::closeMostFDs({STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO});
|
||||
|
||||
#if __linux__
|
||||
linux::setPersonality(drv->platform);
|
||||
|
|
|
@ -17,6 +17,9 @@ R""(
|
|||
; Allow POSIX semaphores and shared memory.
|
||||
(allow ipc-posix*)
|
||||
|
||||
; Allow SYSV semaphores and shared memory.
|
||||
(allow ipc-sysv*)
|
||||
|
||||
; Allow socket creation.
|
||||
(allow system-socket)
|
||||
|
||||
|
|
19
src/libstore/unix/meson.build
Normal file
19
src/libstore/unix/meson.build
Normal file
|
@ -0,0 +1,19 @@
|
|||
sources += files(
|
||||
'build/child.cc',
|
||||
'build/hook-instance.cc',
|
||||
'build/local-derivation-goal.cc',
|
||||
'pathlocks.cc',
|
||||
'user-lock.cc',
|
||||
)
|
||||
|
||||
include_dirs += include_directories(
|
||||
'.',
|
||||
'build',
|
||||
)
|
||||
|
||||
headers += files(
|
||||
'build/child.hh',
|
||||
'build/hook-instance.hh',
|
||||
'build/local-derivation-goal.hh',
|
||||
'user-lock.hh',
|
||||
)
|
11
src/libstore/windows/meson.build
Normal file
11
src/libstore/windows/meson.build
Normal file
|
@ -0,0 +1,11 @@
|
|||
sources += files(
|
||||
'pathlocks.cc',
|
||||
)
|
||||
|
||||
include_dirs += include_directories(
|
||||
'.',
|
||||
#'build',
|
||||
)
|
||||
|
||||
headers += files(
|
||||
)
|
1
src/libutil/.version
Symbolic link
1
src/libutil/.version
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../.version
|
|
@ -140,6 +140,7 @@ public:
|
|||
};
|
||||
|
||||
#ifndef _WIN32 // Not needed on Windows, where we don't fork
|
||||
namespace unix {
|
||||
|
||||
/**
|
||||
* Close all file descriptors except those listed in the given set.
|
||||
|
@ -152,13 +153,16 @@ void closeMostFDs(const std::set<Descriptor> & exceptions);
|
|||
*/
|
||||
void closeOnExec(Descriptor fd);
|
||||
|
||||
} // namespace unix
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# if _WIN32_WINNT >= 0x0600
|
||||
#if defined(_WIN32) && _WIN32_WINNT >= 0x0600
|
||||
namespace windows {
|
||||
|
||||
Path handleToPath(Descriptor handle);
|
||||
std::wstring handleToFileName(Descriptor handle);
|
||||
# endif
|
||||
|
||||
} // namespace windows
|
||||
#endif
|
||||
|
||||
MakeError(EndOfFile, Error);
|
||||
|
|
|
@ -525,7 +525,7 @@ std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix)
|
|||
if (!fd)
|
||||
throw SysError("creating temporary file '%s'", tmpl);
|
||||
#ifndef _WIN32
|
||||
closeOnExec(fd.get());
|
||||
unix::closeOnExec(fd.get());
|
||||
#endif
|
||||
return {std::move(fd), tmpl};
|
||||
}
|
||||
|
|
|
@ -52,11 +52,11 @@ bool Hash::operator == (const Hash & h2) const
|
|||
|
||||
std::strong_ordering Hash::operator <=> (const Hash & h) const
|
||||
{
|
||||
if (auto cmp = algo <=> h.algo; cmp != 0) return cmp;
|
||||
if (auto cmp = hashSize <=> h.hashSize; cmp != 0) return cmp;
|
||||
for (unsigned int i = 0; i < hashSize; i++) {
|
||||
if (auto cmp = hash[i] <=> h.hash[i]; cmp != 0) return cmp;
|
||||
}
|
||||
if (auto cmp = algo <=> h.algo; cmp != 0) return cmp;
|
||||
return std::strong_ordering::equivalent;
|
||||
}
|
||||
|
||||
|
|
11
src/libutil/linux/meson.build
Normal file
11
src/libutil/linux/meson.build
Normal file
|
@ -0,0 +1,11 @@
|
|||
sources += files(
|
||||
'cgroup.cc',
|
||||
'namespaces.cc',
|
||||
)
|
||||
|
||||
include_dirs += include_directories('.')
|
||||
|
||||
headers += files(
|
||||
'cgroup.hh',
|
||||
'namespaces.hh',
|
||||
)
|
332
src/libutil/meson.build
Normal file
332
src/libutil/meson.build
Normal file
|
@ -0,0 +1,332 @@
|
|||
project('nix-util', 'cpp',
|
||||
version : files('.version'),
|
||||
default_options : [
|
||||
'cpp_std=c++2a',
|
||||
# TODO(Qyriad): increase the warning level
|
||||
'warning_level=1',
|
||||
'debug=true',
|
||||
'optimization=2',
|
||||
'errorlogs=true', # Please print logs for tests that fail
|
||||
],
|
||||
meson_version : '>= 1.1',
|
||||
license : 'LGPL-2.1-or-later',
|
||||
)
|
||||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
# These are private dependencies with pkg-config files. What private
|
||||
# means is that the dependencies are used by the library but they are
|
||||
# *not* used (e.g. `#include`-ed) in any installed header file, and only
|
||||
# in regular source code (`*.cc`) or private, uninstalled headers. They
|
||||
# are thus part of the *implementation* of the library, but not its
|
||||
# *interface*.
|
||||
#
|
||||
# See `man pkg-config` for some details.
|
||||
deps_private = [ ]
|
||||
|
||||
# These are public dependencies with pkg-config files. Public is the
|
||||
# opposite of private: these dependencies are used in installed header
|
||||
# files. They are part of the interface (and implementation) of the
|
||||
# library.
|
||||
#
|
||||
# N.B. This concept is mostly unrelated to our own concept of a public
|
||||
# (stable) API, for consumption outside of the Nix repository.
|
||||
# `libnixutil` is an unstable C++ library, whose public interface is
|
||||
# likewise unstable. `libutilc` conversely is a hopefully-soon stable
|
||||
# C library, whose public interface --- including public but not private
|
||||
# dependencies --- will also likewise soon be stable.
|
||||
#
|
||||
# N.B. For distributions that care about "ABI" stablity and not just
|
||||
# "API" stability, the private dependencies also matter as they can
|
||||
# potentially affect the public ABI.
|
||||
deps_public = [ ]
|
||||
|
||||
# These are dependencencies without pkg-config files. Ideally they are
|
||||
# just private, but they may also be public (e.g. boost).
|
||||
deps_other = [ ]
|
||||
|
||||
configdata = configuration_data()
|
||||
|
||||
# Check for each of these functions, and create a define like `#define
|
||||
# HAVE_LUTIMES 1`. The `#define` is unconditional, 0 for not found and 1
|
||||
# for found. One therefore uses it with `#if` not `#ifdef`.
|
||||
check_funcs = [
|
||||
# Optionally used for changing the mtime of symlinks.
|
||||
'lutimes',
|
||||
# Optionally used for creating pipes on Unix
|
||||
'pipe2',
|
||||
# Optionally used to preallocate files to be large enough before
|
||||
# writing to them.
|
||||
'posix_fallocate',
|
||||
# Optionally used to get more information about processes failing due
|
||||
# to a signal on Unix.
|
||||
'strsignal',
|
||||
# Optionally used to try to close more file descriptors (e.g. before
|
||||
# forking) on Unix.
|
||||
'sysconf',
|
||||
]
|
||||
foreach funcspec : check_funcs
|
||||
define_name = 'HAVE_' + funcspec.underscorify().to_upper()
|
||||
define_value = cxx.has_function(funcspec).to_int()
|
||||
configdata.set(define_name, define_value)
|
||||
endforeach
|
||||
|
||||
# This is only conditional to work around
|
||||
# https://github.com/mesonbuild/meson/issues/13293. It should be
|
||||
# unconditional.
|
||||
if not (host_machine.system() == 'windows' and cxx.get_id() == 'gcc')
|
||||
deps_private += dependency('threads')
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
socket = cxx.find_library('ws2_32')
|
||||
deps_other += socket
|
||||
elif host_machine.system() == 'sunos'
|
||||
socket = cxx.find_library('socket')
|
||||
network_service_library = cxx.find_library('nsl')
|
||||
deps_other += [socket, network_service_library]
|
||||
endif
|
||||
|
||||
boost = dependency(
|
||||
'boost',
|
||||
modules : ['context', 'coroutine'],
|
||||
)
|
||||
# boost is a public dependency, but not a pkg-config dependency unfortunately, so we
|
||||
# put in `deps_other`.
|
||||
deps_other += boost
|
||||
|
||||
openssl = dependency(
|
||||
'libcrypto',
|
||||
'openssl',
|
||||
version : '>= 1.1.1',
|
||||
)
|
||||
deps_private += openssl
|
||||
|
||||
libarchive = dependency('libarchive', version : '>= 3.1.2')
|
||||
deps_public += libarchive
|
||||
if get_option('default_library') == 'static'
|
||||
# Workaround until https://github.com/libarchive/libarchive/issues/1446 is fixed
|
||||
add_project_arguments('-lz', language : 'cpp')
|
||||
endif
|
||||
|
||||
sodium = dependency('libsodium', 'sodium')
|
||||
deps_private += sodium
|
||||
|
||||
brotli = [
|
||||
dependency('libbrotlicommon'),
|
||||
dependency('libbrotlidec'),
|
||||
dependency('libbrotlienc'),
|
||||
]
|
||||
deps_private += brotli
|
||||
|
||||
cpuid_required = get_option('cpuid')
|
||||
if host_machine.cpu_family() != 'x86_64' and cpuid_required.enabled()
|
||||
warning('Force-enabling seccomp on non-x86_64 does not make sense')
|
||||
endif
|
||||
cpuid = dependency('libcpuid', 'cpuid', required : cpuid_required)
|
||||
configdata.set('HAVE_LIBCPUID', cpuid.found().to_int())
|
||||
deps_private += cpuid
|
||||
|
||||
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
|
||||
deps_public += nlohmann_json
|
||||
|
||||
config_h = configure_file(
|
||||
configuration : configdata,
|
||||
output : 'config-util.h',
|
||||
)
|
||||
|
||||
add_project_arguments(
|
||||
# TODO(Qyriad): Yes this is how the autoconf+Make system did it.
|
||||
# It would be nice for our headers to be idempotent instead.
|
||||
'-include', 'config-util.h',
|
||||
'-Wno-deprecated-declarations',
|
||||
'-Wimplicit-fallthrough',
|
||||
'-Werror=switch',
|
||||
'-Werror=switch-enum',
|
||||
'-Wdeprecated-copy',
|
||||
'-Wignored-qualifiers',
|
||||
# Enable assertions in libstdc++ by default. Harmless on libc++. Benchmarked
|
||||
# at ~1% overhead in `nix search`.
|
||||
#
|
||||
# FIXME: remove when we get meson 1.4.0 which will default this to on for us:
|
||||
# https://mesonbuild.com/Release-notes-for-1-4-0.html#ndebug-setting-now-controls-c-stdlib-assertions
|
||||
'-D_GLIBCXX_ASSERTIONS=1',
|
||||
language : 'cpp',
|
||||
)
|
||||
|
||||
sources = files(
|
||||
'archive.cc',
|
||||
'args.cc',
|
||||
'canon-path.cc',
|
||||
'compression.cc',
|
||||
'compute-levels.cc',
|
||||
'config.cc',
|
||||
'current-process.cc',
|
||||
'english.cc',
|
||||
'environment-variables.cc',
|
||||
'error.cc',
|
||||
'exit.cc',
|
||||
'experimental-features.cc',
|
||||
'file-content-address.cc',
|
||||
'file-descriptor.cc',
|
||||
'file-system.cc',
|
||||
'fs-sink.cc',
|
||||
'git.cc',
|
||||
'hash.cc',
|
||||
'hilite.cc',
|
||||
'json-utils.cc',
|
||||
'logging.cc',
|
||||
'memory-source-accessor.cc',
|
||||
'position.cc',
|
||||
'posix-source-accessor.cc',
|
||||
'references.cc',
|
||||
'serialise.cc',
|
||||
'signature/local-keys.cc',
|
||||
'signature/signer.cc',
|
||||
'source-accessor.cc',
|
||||
'source-path.cc',
|
||||
'suggestions.cc',
|
||||
'tarfile.cc',
|
||||
'terminal.cc',
|
||||
'thread-pool.cc',
|
||||
'unix-domain-socket.cc',
|
||||
'url.cc',
|
||||
'users.cc',
|
||||
'util.cc',
|
||||
'xml-writer.cc',
|
||||
)
|
||||
|
||||
include_dirs = [include_directories('.')]
|
||||
|
||||
headers = [config_h] + files(
|
||||
'abstract-setting-to-json.hh',
|
||||
'ansicolor.hh',
|
||||
'archive.hh',
|
||||
'args.hh',
|
||||
'args/root.hh',
|
||||
'callback.hh',
|
||||
'canon-path.hh',
|
||||
'chunked-vector.hh',
|
||||
'closure.hh',
|
||||
'comparator.hh',
|
||||
'compression.hh',
|
||||
'compute-levels.hh',
|
||||
'config-impl.hh',
|
||||
'config.hh',
|
||||
'current-process.hh',
|
||||
'english.hh',
|
||||
'environment-variables.hh',
|
||||
'error.hh',
|
||||
'exit.hh',
|
||||
'experimental-features.hh',
|
||||
'file-content-address.hh',
|
||||
'file-descriptor.hh',
|
||||
'file-path-impl.hh',
|
||||
'file-path.hh',
|
||||
'file-system.hh',
|
||||
'finally.hh',
|
||||
'fmt.hh',
|
||||
'fs-sink.hh',
|
||||
'git.hh',
|
||||
'hash.hh',
|
||||
'hilite.hh',
|
||||
'json-impls.hh',
|
||||
'json-utils.hh',
|
||||
'logging.hh',
|
||||
'lru-cache.hh',
|
||||
'memory-source-accessor.hh',
|
||||
'muxable-pipe.hh',
|
||||
'pool.hh',
|
||||
'position.hh',
|
||||
'posix-source-accessor.hh',
|
||||
'processes.hh',
|
||||
'ref.hh',
|
||||
'references.hh',
|
||||
'regex-combinators.hh',
|
||||
'repair-flag.hh',
|
||||
'serialise.hh',
|
||||
'signals.hh',
|
||||
'signature/local-keys.hh',
|
||||
'signature/signer.hh',
|
||||
'source-accessor.hh',
|
||||
'source-path.hh',
|
||||
'split.hh',
|
||||
'suggestions.hh',
|
||||
'sync.hh',
|
||||
'tarfile.hh',
|
||||
'terminal.hh',
|
||||
'thread-pool.hh',
|
||||
'topo-sort.hh',
|
||||
'types.hh',
|
||||
'unix-domain-socket.hh',
|
||||
'url-parts.hh',
|
||||
'url.hh',
|
||||
'users.hh',
|
||||
'util.hh',
|
||||
'variant-wrapper.hh',
|
||||
'xml-writer.hh',
|
||||
)
|
||||
|
||||
if host_machine.system() == 'linux'
|
||||
subdir('linux')
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
subdir('windows')
|
||||
else
|
||||
subdir('unix')
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
|
||||
# Windows DLLs are stricter about symbol visibility than Unix shared
|
||||
# objects --- see https://gcc.gnu.org/wiki/Visibility for details.
|
||||
# This is a temporary sledgehammer to export everything like on Unix,
|
||||
# and not detail with this yet.
|
||||
#
|
||||
# TODO do not do this, and instead do fine-grained export annotations.
|
||||
linker_export_flags = ['-Wl,--export-all-symbols']
|
||||
else
|
||||
linker_export_flags = []
|
||||
endif
|
||||
|
||||
this_library = library(
|
||||
'nixutil',
|
||||
sources,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args: linker_export_flags,
|
||||
install : true,
|
||||
)
|
||||
|
||||
install_headers(headers, subdir : 'nix', preserve_path : true)
|
||||
|
||||
# Part of how we copy boost libraries to a separate installation to
|
||||
# reduce closure size. These libraries will be copied to our `$out/bin`,
|
||||
# and these `-l` flags will pick them up there.
|
||||
#
|
||||
# https://github.com/NixOS/nixpkgs/issues/45462
|
||||
libraries_private = ['-lboost_context', '-lboost_coroutine']
|
||||
if host_machine.system() == 'windows'
|
||||
# `libraries_private` cannot contain ad-hoc dependencies (from
|
||||
# `find_library), so we need to do this manually
|
||||
libraries_private += ['-lws2_32']
|
||||
endif
|
||||
|
||||
import('pkgconfig').generate(
|
||||
this_library,
|
||||
filebase : meson.project_name(),
|
||||
name : 'Nix',
|
||||
description : 'Nix Package Manager',
|
||||
subdirs : ['nix'],
|
||||
extra_cflags : ['-std=c++2a'],
|
||||
requires : deps_public,
|
||||
requires_private : deps_private,
|
||||
libraries_private : libraries_private,
|
||||
)
|
||||
|
||||
meson.override_dependency(meson.project_name(), declare_dependency(
|
||||
include_directories : include_dirs,
|
||||
link_with : this_library,
|
||||
compile_args : ['-std=c++2a'],
|
||||
dependencies : [],
|
||||
))
|
5
src/libutil/meson.options
Normal file
5
src/libutil/meson.options
Normal file
|
@ -0,0 +1,5 @@
|
|||
# vim: filetype=meson
|
||||
|
||||
option('cpuid', type : 'feature',
|
||||
description : 'determine microarchitecture levels with libcpuid (only relevant on x86_64)',
|
||||
)
|
149
src/libutil/package.nix
Normal file
149
src/libutil/package.nix
Normal file
|
@ -0,0 +1,149 @@
|
|||
{ lib
|
||||
, stdenv
|
||||
, releaseTools
|
||||
, fileset
|
||||
|
||||
, meson
|
||||
, ninja
|
||||
, pkg-config
|
||||
|
||||
, boost
|
||||
, brotli
|
||||
, libarchive
|
||||
, libcpuid
|
||||
, libsodium
|
||||
, nlohmann_json
|
||||
, openssl
|
||||
|
||||
# Configuration Options
|
||||
|
||||
, versionSuffix ? ""
|
||||
, officialRelease ? false
|
||||
|
||||
# Check test coverage of Nix. Probably want to use with at least
|
||||
# one of `doCheck` or `doInstallCheck` enabled.
|
||||
, withCoverageChecks ? false
|
||||
}:
|
||||
|
||||
let
|
||||
version = lib.fileContents ./.version + versionSuffix;
|
||||
|
||||
mkDerivation =
|
||||
if withCoverageChecks
|
||||
then
|
||||
# TODO support `finalAttrs` args function in
|
||||
# `releaseTools.coverageAnalysis`.
|
||||
argsFun:
|
||||
releaseTools.coverageAnalysis (let args = argsFun args; in args)
|
||||
else stdenv.mkDerivation;
|
||||
in
|
||||
|
||||
mkDerivation (finalAttrs: {
|
||||
pname = "nix-util";
|
||||
inherit version;
|
||||
|
||||
src = fileset.toSource {
|
||||
root = ./.;
|
||||
fileset = fileset.unions [
|
||||
./meson.build
|
||||
./meson.options
|
||||
./linux/meson.build
|
||||
./unix/meson.build
|
||||
./windows/meson.build
|
||||
(fileset.fileFilter (file: file.hasExt "cc") ./.)
|
||||
(fileset.fileFilter (file: file.hasExt "hh") ./.)
|
||||
];
|
||||
};
|
||||
|
||||
outputs = [ "out" "dev" ];
|
||||
|
||||
nativeBuildInputs = [
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
boost
|
||||
brotli
|
||||
libsodium
|
||||
openssl
|
||||
] ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid
|
||||
;
|
||||
|
||||
propagatedBuildInputs = [
|
||||
libarchive
|
||||
nlohmann_json
|
||||
];
|
||||
|
||||
disallowedReferences = [ boost ];
|
||||
|
||||
preConfigure =
|
||||
# "Inline" .version so it's not a symlink, and includes the suffix
|
||||
''
|
||||
echo ${version} > .version
|
||||
''
|
||||
# Copy some boost libraries so we don't get all of Boost in our
|
||||
# closure. https://github.com/NixOS/nixpkgs/issues/45462
|
||||
+ lib.optionalString (!stdenv.hostPlatform.isStatic) (''
|
||||
mkdir -p $out/lib
|
||||
cp -pd ${boost}/lib/{libboost_context*,libboost_thread*,libboost_system*} $out/lib
|
||||
rm -f $out/lib/*.a
|
||||
'' + lib.optionalString stdenv.hostPlatform.isLinux ''
|
||||
chmod u+w $out/lib/*.so.*
|
||||
patchelf --set-rpath $out/lib:${stdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.*
|
||||
'' + lib.optionalString stdenv.hostPlatform.isDarwin ''
|
||||
for LIB in $out/lib/*.dylib; do
|
||||
chmod u+w $LIB
|
||||
install_name_tool -id $LIB $LIB
|
||||
install_name_tool -delete_rpath ${boost}/lib/ $LIB || true
|
||||
done
|
||||
install_name_tool -change ${boost}/lib/libboost_system.dylib $out/lib/libboost_system.dylib $out/lib/libboost_thread.dylib
|
||||
''
|
||||
);
|
||||
|
||||
mesonFlags = [
|
||||
(lib.mesonEnable "cpuid" stdenv.hostPlatform.isx86_64)
|
||||
];
|
||||
|
||||
env = {
|
||||
# Needed for Meson to find Boost.
|
||||
# https://github.com/NixOS/nixpkgs/issues/86131.
|
||||
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
|
||||
BOOST_LIBRARYDIR = "${lib.getLib boost}/lib";
|
||||
} // lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) {
|
||||
LDFLAGS = "-fuse-ld=gold";
|
||||
};
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
||||
postInstall =
|
||||
# Remove absolute path to boost libs that ends up in `Libs.private`
|
||||
# by default, and would clash with out `disallowedReferences`. Part
|
||||
# of the https://github.com/NixOS/nixpkgs/issues/45462 workaround.
|
||||
''
|
||||
sed -i "$out/lib/pkgconfig/nix-util.pc" -e 's, ${lib.getLib boost}[^ ]*,,g'
|
||||
''
|
||||
+ lib.optionalString stdenv.isDarwin ''
|
||||
install_name_tool \
|
||||
-change ${boost}/lib/libboost_context.dylib \
|
||||
$out/lib/libboost_context.dylib \
|
||||
$out/lib/libnixutil.dylib
|
||||
'';
|
||||
|
||||
separateDebugInfo = !stdenv.hostPlatform.isStatic;
|
||||
|
||||
# TODO Always true after https://github.com/NixOS/nixpkgs/issues/318564
|
||||
strictDeps = !withCoverageChecks;
|
||||
|
||||
hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie";
|
||||
|
||||
meta = {
|
||||
platforms = lib.platforms.unix ++ lib.platforms.windows;
|
||||
};
|
||||
|
||||
} // lib.optionalAttrs withCoverageChecks {
|
||||
lcovFilter = [ "*/boost/*" "*-tab.*" ];
|
||||
|
||||
hardeningDisable = [ "fortify" ];
|
||||
})
|
|
@ -79,7 +79,8 @@ TarArchive::TarArchive(Source & source, bool raw, std::optional<std::string> com
|
|||
}
|
||||
|
||||
if (!raw) {
|
||||
archive_read_support_format_all(archive);
|
||||
archive_read_support_format_tar(archive);
|
||||
archive_read_support_format_zip(archive);
|
||||
} else {
|
||||
archive_read_support_format_raw(archive);
|
||||
archive_read_support_format_empty(archive);
|
||||
|
@ -96,7 +97,8 @@ TarArchive::TarArchive(const Path & path)
|
|||
, buffer(defaultBufferSize)
|
||||
{
|
||||
archive_read_support_filter_all(archive);
|
||||
archive_read_support_format_all(archive);
|
||||
archive_read_support_format_tar(archive);
|
||||
archive_read_support_format_zip(archive);
|
||||
archive_read_set_option(archive, NULL, "mac-ext", NULL);
|
||||
check(archive_read_open_filename(archive, path.c_str(), 16384), "failed to open archive: %s");
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ AutoCloseFD createUnixDomainSocket()
|
|||
if (!fdSocket)
|
||||
throw SysError("cannot create Unix domain socket");
|
||||
#ifndef _WIN32
|
||||
closeOnExec(fdSocket.get());
|
||||
unix::closeOnExec(fdSocket.get());
|
||||
#endif
|
||||
return fdSocket;
|
||||
}
|
||||
|
|
|
@ -110,8 +110,8 @@ void Pipe::create()
|
|||
if (pipe2(fds, O_CLOEXEC) != 0) throw SysError("creating pipe");
|
||||
#else
|
||||
if (pipe(fds) != 0) throw SysError("creating pipe");
|
||||
closeOnExec(fds[0]);
|
||||
closeOnExec(fds[1]);
|
||||
unix::closeOnExec(fds[0]);
|
||||
unix::closeOnExec(fds[1]);
|
||||
#endif
|
||||
readSide = fds[0];
|
||||
writeSide = fds[1];
|
||||
|
@ -120,7 +120,7 @@ void Pipe::create()
|
|||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void closeMostFDs(const std::set<int> & exceptions)
|
||||
void unix::closeMostFDs(const std::set<int> & exceptions)
|
||||
{
|
||||
#if __linux__
|
||||
try {
|
||||
|
@ -139,14 +139,16 @@ void closeMostFDs(const std::set<int> & exceptions)
|
|||
#endif
|
||||
|
||||
int maxFD = 0;
|
||||
#if HAVE_SYSCONF
|
||||
maxFD = sysconf(_SC_OPEN_MAX);
|
||||
#endif
|
||||
for (int fd = 0; fd < maxFD; ++fd)
|
||||
if (!exceptions.count(fd))
|
||||
close(fd); /* ignore result */
|
||||
}
|
||||
|
||||
|
||||
void closeOnExec(int fd)
|
||||
void unix::closeOnExec(int fd)
|
||||
{
|
||||
int prev;
|
||||
if ((prev = fcntl(fd, F_GETFD, 0)) == -1 ||
|
||||
|
|
17
src/libutil/unix/meson.build
Normal file
17
src/libutil/unix/meson.build
Normal file
|
@ -0,0 +1,17 @@
|
|||
sources += files(
|
||||
'environment-variables.cc',
|
||||
'file-descriptor.cc',
|
||||
'file-path.cc',
|
||||
'file-system.cc',
|
||||
'muxable-pipe.cc',
|
||||
'processes.cc',
|
||||
'signals.cc',
|
||||
'users.cc',
|
||||
)
|
||||
|
||||
include_dirs += include_directories('.')
|
||||
|
||||
headers += files(
|
||||
'monitor-fd.hh',
|
||||
'signals-impl.hh',
|
||||
)
|
|
@ -122,7 +122,7 @@ void Pipe::create()
|
|||
|
||||
#if _WIN32_WINNT >= 0x0600
|
||||
|
||||
std::wstring handleToFileName(HANDLE handle) {
|
||||
std::wstring windows::handleToFileName(HANDLE handle) {
|
||||
std::vector<wchar_t> buf(0x100);
|
||||
DWORD dw = GetFinalPathNameByHandleW(handle, buf.data(), buf.size(), FILE_NAME_OPENED);
|
||||
if (dw == 0) {
|
||||
|
@ -141,7 +141,7 @@ std::wstring handleToFileName(HANDLE handle) {
|
|||
}
|
||||
|
||||
|
||||
Path handleToPath(HANDLE handle) {
|
||||
Path windows::handleToPath(HANDLE handle) {
|
||||
return os_string_to_string(handleToFileName(handle));
|
||||
}
|
||||
|
||||
|
|
19
src/libutil/windows/meson.build
Normal file
19
src/libutil/windows/meson.build
Normal file
|
@ -0,0 +1,19 @@
|
|||
sources += files(
|
||||
'environment-variables.cc',
|
||||
'file-descriptor.cc',
|
||||
'file-path.cc',
|
||||
'file-system.cc',
|
||||
'muxable-pipe.cc',
|
||||
'processes.cc',
|
||||
'users.cc',
|
||||
'windows-async-pipe.cc',
|
||||
'windows-error.cc',
|
||||
)
|
||||
|
||||
include_dirs += include_directories('.')
|
||||
|
||||
headers += files(
|
||||
'signals-impl.hh',
|
||||
'windows-async-pipe.hh',
|
||||
'windows-error.hh',
|
||||
)
|
|
@ -477,9 +477,7 @@ static void main_nix_build(int argc, char * * argv)
|
|||
// Set the environment.
|
||||
auto env = getEnv();
|
||||
|
||||
auto tmp = getEnvNonEmpty("TMPDIR");
|
||||
if (!tmp)
|
||||
tmp = getEnvNonEmpty("XDG_RUNTIME_DIR").value_or("/tmp");
|
||||
auto tmp = getEnvNonEmpty("TMPDIR").value_or("/tmp");
|
||||
|
||||
if (pure) {
|
||||
decltype(env) newEnv;
|
||||
|
@ -491,7 +489,7 @@ static void main_nix_build(int argc, char * * argv)
|
|||
env["__ETC_PROFILE_SOURCED"] = "1";
|
||||
}
|
||||
|
||||
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = *tmp;
|
||||
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmp;
|
||||
env["NIX_STORE"] = store->storeDir;
|
||||
env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores);
|
||||
|
||||
|
|
|
@ -295,7 +295,7 @@ static void daemonLoop(std::optional<TrustedFlag> forceTrustClientOpt)
|
|||
if (getEnv("LISTEN_PID") != std::to_string(getpid()) || listenFds != "1")
|
||||
throw Error("unexpected systemd environment variables");
|
||||
fdSocket = SD_LISTEN_FDS_START;
|
||||
closeOnExec(fdSocket.get());
|
||||
unix::closeOnExec(fdSocket.get());
|
||||
}
|
||||
|
||||
// Otherwise, create and bind to a Unix domain socket.
|
||||
|
@ -323,7 +323,7 @@ static void daemonLoop(std::optional<TrustedFlag> forceTrustClientOpt)
|
|||
throw SysError("accepting connection");
|
||||
}
|
||||
|
||||
closeOnExec(remote.get());
|
||||
unix::closeOnExec(remote.get());
|
||||
|
||||
PeerInfo peer { .pidKnown = false };
|
||||
TrustedFlag trusted;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue