Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C API: Add libflake-c (backport #11940) #11949

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ jobs:
- uses: cachix/install-nix-action@V27
with:
# The sandbox would otherwise be disabled by default on Darwin
extra_nix_config: "sandbox = true"
extra_nix_config: |
sandbox = true
max-jobs = 1
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
- uses: cachix/cachix-action@v15
if: needs.check_secrets.outputs.cachix == 'true'
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ subproject('external-api-docs')
subproject('libutil-c')
subproject('libstore-c')
subproject('libexpr-c')
subproject('libflake-c')
subproject('libmain-c')

# Language Bindings
Expand Down
5 changes: 5 additions & 0 deletions packaging/components.nix
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ in
nix-expr-tests = callPackage ../tests/unit/libexpr/package.nix { };

nix-flake = callPackage ../src/libflake/package.nix { };
<<<<<<< HEAD
nix-flake-tests = callPackage ../tests/unit/libflake/package.nix { };
=======
nix-flake-c = callPackage ../src/libflake-c/package.nix { };
nix-flake-tests = callPackage ../src/libflake-tests/package.nix { };
>>>>>>> 4eecf3c20 (Add nix-flake-c, nix_flake_init_global, nix_flake_settings_new)

nix-main = callPackage ../src/libmain/package.nix { };
nix-main-c = callPackage ../src/libmain-c/package.nix { };
Expand Down
202 changes: 202 additions & 0 deletions packaging/everything.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
{
lib,
stdenv,
buildEnv,

nix-util,
nix-util-c,
nix-util-tests,

nix-store,
nix-store-c,
nix-store-tests,

nix-fetchers,
nix-fetchers-tests,

nix-expr,
nix-expr-c,
nix-expr-tests,

nix-flake,
nix-flake-c,
nix-flake-tests,

nix-main,
nix-main-c,

nix-cmd,

nix-cli,

nix-functional-tests,

nix-manual,
nix-internal-api-docs,
nix-external-api-docs,

nix-perl-bindings,

testers,
runCommand,
}:

let
dev = stdenv.mkDerivation (finalAttrs: {
name = "nix-${nix-cli.version}-dev";
pname = "nix";
version = nix-cli.version;
dontUnpack = true;
dontBuild = true;
libs = map lib.getDev [
nix-cmd
nix-expr
nix-expr-c
nix-fetchers
nix-flake
nix-flake-c
nix-main
nix-main-c
nix-store
nix-store-c
nix-util
nix-util-c
nix-perl-bindings
];
installPhase = ''
mkdir -p $out/nix-support
echo $libs >> $out/nix-support/propagated-build-inputs
'';
passthru = {
tests = {
pkg-config =
testers.hasPkgConfigModules {
package = finalAttrs.finalPackage;
};
};

# If we were to fully emulate output selection here, we'd confuse the Nix CLIs,
# because they rely on `drvPath`.
dev = finalAttrs.finalPackage.out;

libs = throw "`nix.dev.libs` is not meant to be used; use `nix.libs` instead.";
};
meta = {
pkgConfigModules = [
"nix-cmd"
"nix-expr"
"nix-expr-c"
"nix-fetchers"
"nix-flake"
"nix-flake-c"
"nix-main"
"nix-main-c"
"nix-store"
"nix-store-c"
"nix-util"
"nix-util-c"
];
};
});
devdoc = buildEnv {
name = "nix-${nix-cli.version}-devdoc";
paths = [
nix-internal-api-docs
nix-external-api-docs
];
};

in
(buildEnv {
name = "nix-${nix-cli.version}";
paths = [
nix-cli
nix-manual.man
];

meta.mainProgram = "nix";
}).overrideAttrs (finalAttrs: prevAttrs: {
doCheck = true;
doInstallCheck = true;

checkInputs = [
# Make sure the unit tests have passed
nix-util-tests.tests.run
nix-store-tests.tests.run
nix-expr-tests.tests.run
nix-fetchers-tests.tests.run
nix-flake-tests.tests.run

# dev bundle is ok
# (checkInputs must be empty paths??)
(runCommand "check-pkg-config" { checked = dev.tests.pkg-config; } "mkdir $out")
] ++
(if stdenv.buildPlatform.canExecute stdenv.hostPlatform
then [
# TODO: add perl.tests
nix-perl-bindings
]
else [
nix-perl-bindings
]);
installCheckInputs = [
nix-functional-tests
];
passthru = prevAttrs.passthru // {
inherit (nix-cli) version;

/**
These are the libraries that are part of the Nix project. They are used
by the Nix CLI and other tools.

If you need to use these libraries in your project, we recommend to use
the `-c` C API libraries exclusively, if possible.

We also recommend that you build the complete package to ensure that the unit tests pass.
You could do this in CI, or by passing it in an unused environment variable. e.g in a `mkDerivation` call:

```nix
buildInputs = [ nix.libs.nix-util-c nix.libs.nix-store-c ];
# Make sure the nix libs we use are ok
unusedInputsForTests = [ nix ];
disallowedReferences = nix.all;
```
*/
libs = {
inherit
nix-util
nix-util-c
nix-store
nix-store-c
nix-fetchers
nix-expr
nix-expr-c
nix-flake
nix-flake-c
nix-main
nix-main-c
;
};

tests = prevAttrs.passthru.tests or {} // {
# TODO: create a proper fixpoint and:
# pkg-config =
# testers.hasPkgConfigModules {
# package = finalPackage;
# };
};

/**
A derivation referencing the `dev` outputs of the Nix libraries.
*/
inherit dev;
inherit devdoc;
doc = nix-manual;
outputs = [ "out" "dev" "devdoc" "doc" ];
all = lib.attrValues (lib.genAttrs finalAttrs.passthru.outputs (outName: finalAttrs.finalPackage.${outName}));
};
meta = prevAttrs.meta // {
description = "The Nix package manager";
pkgConfigModules = dev.meta.pkgConfigModules;
};
})
1 change: 1 addition & 0 deletions src/external-api-docs/doxygen.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ GENERATE_LATEX = NO
INPUT = \
@src@/src/libutil-c \
@src@/src/libexpr-c \
@src@/src/libflake-c \
@src@/src/libstore-c \
@src@/doc/external-api/README.md

Expand Down
1 change: 1 addition & 0 deletions src/external-api-docs/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mkMesonDerivation (finalAttrs: {
# Source is not compiled, but still must be available for Doxygen
# to gather comments.
(cpp ../libexpr-c)
(cpp ../libflake-c)
(cpp ../libstore-c)
(cpp ../libutil-c)
];
Expand Down
114 changes: 96 additions & 18 deletions src/libexpr-c/nix_api_expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "eval-gc.hh"
#include "globals.hh"
#include "eval-settings.hh"
#include "ref.hh"

#include "nix_api_expr.h"
#include "nix_api_expr_internal.h"
Expand All @@ -20,6 +21,29 @@
# include "gc_cpp.h"
#endif

/**
* @brief Allocate and initialize using self-reference
*
* This allows a brace initializer to reference the object being constructed.
*
* @warning Use with care, as the pointer points to an object that is not fully constructed yet.
*
* @tparam T Type to allocate
* @tparam F A function type for `init`, taking a T* and returning the initializer for T
* @param init Function that takes a T* and returns the initializer for T
* @return Pointer to allocated and initialized object
*/
template <typename T, typename F>
static T * unsafe_new_with_self(F && init)
{
// Allocate
void * p = ::operator new(
sizeof(T),
static_cast<std::align_val_t>(alignof(T)));
// Initialize with placement new
return new (p) T(init(static_cast<T *>(p)));
}

nix_err nix_libexpr_init(nix_c_context * context)
{
if (context)
Expand Down Expand Up @@ -95,7 +119,42 @@ nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_val
NIXC_CATCH_ERRS
}

EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c, Store * store)
nix_eval_state_builder * nix_eval_state_builder_new(nix_c_context * context, Store * store)
{
if (context)
context->last_err_code = NIX_OK;
try {
return unsafe_new_with_self<nix_eval_state_builder>([&](auto * self) {
return nix_eval_state_builder{
.store = nix::ref<nix::Store>(store->ptr),
.settings = nix::EvalSettings{/* &bool */ self->readOnlyMode},
.fetchSettings = nix::fetchers::Settings{},
.readOnlyMode = true,
};
});
}
NIXC_CATCH_ERRS_NULL
}

void nix_eval_state_builder_free(nix_eval_state_builder * builder)
{
delete builder;
}

nix_err nix_eval_state_builder_load(nix_c_context * context, nix_eval_state_builder * builder)
{
if (context)
context->last_err_code = NIX_OK;
try {
// TODO: load in one go?
builder->settings.readOnlyMode = nix::settings.readOnlyMode;
loadConfFile(builder->settings);
loadConfFile(builder->fetchSettings);
}
NIXC_CATCH_ERRS
}

nix_err nix_eval_state_builder_set_lookup_path(nix_c_context * context, nix_eval_state_builder * builder, const char ** lookupPath_c)
{
if (context)
context->last_err_code = NIX_OK;
Expand All @@ -104,28 +163,47 @@ EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c
if (lookupPath_c != nullptr)
for (size_t i = 0; lookupPath_c[i] != nullptr; i++)
lookupPath.push_back(lookupPath_c[i]);
builder->lookupPath = nix::LookupPath::parse(lookupPath);
}
NIXC_CATCH_ERRS
}

void * p = ::operator new(
sizeof(EvalState),
static_cast<std::align_val_t>(alignof(EvalState)));
auto * p2 = static_cast<EvalState *>(p);
new (p) EvalState {
.fetchSettings = nix::fetchers::Settings{},
.settings = nix::EvalSettings{
nix::settings.readOnlyMode,
},
.state = nix::EvalState(
nix::LookupPath::parse(lookupPath),
store->ptr,
p2->fetchSettings,
p2->settings),
};
loadConfFile(p2->settings);
return p2;
EvalState * nix_eval_state_build(nix_c_context * context, nix_eval_state_builder * builder)
{
if (context)
context->last_err_code = NIX_OK;
try {
return unsafe_new_with_self<EvalState>([&](auto * self) {
return EvalState{
.fetchSettings = std::move(builder->fetchSettings),
.settings = std::move(builder->settings),
.state = nix::EvalState(
builder->lookupPath,
builder->store,
self->fetchSettings,
self->settings),
};
});
}
NIXC_CATCH_ERRS_NULL
}

EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c, Store * store)
{
auto builder = nix_eval_state_builder_new(context, store);
if (builder == nullptr)
return nullptr;

if (nix_eval_state_builder_load(context, builder) != NIX_OK)
return nullptr;

if (nix_eval_state_builder_set_lookup_path(context, builder, lookupPath_c)
!= NIX_OK)
return nullptr;

return nix_eval_state_build(context, builder);
}

void nix_state_free(EvalState * state)
{
delete state;
Expand Down
Loading
Loading