[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
27/118: Add importNative primop
From: |
Ludovic Courtès |
Subject: |
27/118: Add importNative primop |
Date: |
Tue, 19 May 2015 14:45:23 +0000 |
civodul pushed a commit to branch nix
in repository guix.
commit 5cd022d6c099c583c0494bdacd06f4eb32661135
Author: Shea Levy <address@hidden>
Date: Sun Jun 1 10:42:56 2014 -0400
Add importNative primop
This can be used to import a dynamic shared object and return an
arbitrary value, including new primops. This can be used both to test
new primops without having to recompile nix every time, and to build
specialized primops that probably don't belong upstream (e.g. a function
that calls out to gpg to decrypt a nixops secret as-needed).
The imported function should initialize the Value & as needed. A single
import can define multiple values by creating an attrset or list, of
course.
An example initialization function might look like:
extern "C" void initialize(nix::EvalState & state, nix::Value & v)
{
v.type = nix::tPrimOp;
v.primOp = NEW nix::PrimOp(myFun, 1, state.symbols.create("myFun"));
}
Then `builtins.importNative ./example.so "initialize"` will evaluate to
the primop defined in the myFun function.
---
src/libexpr/local.mk | 2 ++
src/libexpr/primops.cc | 42 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/src/libexpr/local.mk b/src/libexpr/local.mk
index b3b4086..75a0e18 100644
--- a/src/libexpr/local.mk
+++ b/src/libexpr/local.mk
@@ -8,6 +8,8 @@ libexpr_SOURCES := $(wildcard $(d)/*.cc) $(d)/lexer-tab.cc
$(d)/parser-tab.cc
libexpr_LIBS = libutil libstore libformat
+libexpr_LDFLAGS = -ldl
+
# The dependency on libgc must be propagated (i.e. meaning that
# programs/libraries that use libexpr must explicitly pass -lgc),
# because inline functions in libexpr's header files call libgc.
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 366911b..d6ac7c9 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -15,6 +15,7 @@
#include <algorithm>
#include <cstring>
+#include <dlfcn.h>
namespace nix {
@@ -129,6 +130,46 @@ static void prim_scopedImport(EvalState & state, const Pos
& pos, Value * * args
}
+/* Want reasonable symbol names, so extern C */
+/* !!! Should we pass the Pos or the file name too? */
+extern "C" typedef void (*ValueInitializer)(EvalState & state, Value & v);
+
+/* Load a ValueInitializer from a dso and return whatever it initializes */
+static void prim_importNative(EvalState & state, const Pos & pos, Value * *
args, Value & v)
+{
+ PathSet context;
+ Path path = state.coerceToPath(pos, *args[0], context);
+
+ try {
+ realiseContext(context);
+ } catch (InvalidPathError & e) {
+ throw EvalError(format("cannot import `%1%', since path `%2%' is not
valid, at %3%")
+ % path % e.path % pos);
+ }
+
+ string sym = state.forceStringNoCtx(*args[1], pos);
+
+ void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
+ if (!handle)
+ throw EvalError(format("could not open `%1%': %2%") % path %
dlerror());
+
+ dlerror();
+ ValueInitializer func = (ValueInitializer) dlsym(handle, sym.c_str());
+ if(!func) {
+ char *message = dlerror();
+ if (message)
+ throw EvalError(format("could not load symbol `%1%' from `%2%':
%3%") % sym % path % message);
+ else
+ throw EvalError(format("symbol `%1%' from `%2%' resolved to NULL
when a function pointer was expected")
+ % sym % path);
+ }
+
+ (func)(state, v);
+
+ /* We don't dlclose because v may be a primop referencing a function in
the shared object file */
+}
+
+
/* Return a string representing the type of the expression. */
static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args,
Value & v)
{
@@ -1327,6 +1368,7 @@ void EvalState::createBaseEnv()
mkApp(v, *baseEnv.values[baseEnvDispl - 1], *v2);
forceValue(v);
addConstant("import", v);
+ addPrimOp("__importNative", 2, prim_importNative);
addPrimOp("__typeOf", 1, prim_typeOf);
addPrimOp("isNull", 1, prim_isNull);
addPrimOp("__isFunction", 1, prim_isFunction);
- 20/118: == operator: Ignore string context, (continued)
- 20/118: == operator: Ignore string context, Ludovic Courtès, 2015/05/19
- 17/118: nix-env -qa --json: Generate valid JSON even if there are invalid meta attrs, Ludovic Courtès, 2015/05/19
- 23/118: findFile: Realise the context of the path attributes, Ludovic Courtès, 2015/05/19
- 11/118: Rephrase @ operator description, Ludovic Courtès, 2015/05/19
- 29/118: Merge branch 'shlevy-import-native', Ludovic Courtès, 2015/05/19
- 12/118: dev-shell is a bash script, not sh, Ludovic Courtès, 2015/05/19
- 22/118: Share code between scopedImport and import, Ludovic Courtès, 2015/05/19
- 26/118: Don't use member initialisers, Ludovic Courtès, 2015/05/19
- 31/118: Add `--json` argument to `nix-instantiate`, Ludovic Courtès, 2015/05/19
- 18/118: Print a warning when loading a large path into memory, Ludovic Courtès, 2015/05/19
- 27/118: Add importNative primop,
Ludovic Courtès <=
- 24/118: Drop ImportError and FindError, Ludovic Courtès, 2015/05/19
- 28/118: Only add the importNative primop if the allow-arbitrary-code-during-evaluation option is true (default false), Ludovic Courtès, 2015/05/19
- 30/118: allow-arbitrary-code-during-evaluation -> allow-unsafe-native-code-during-evaluation, Ludovic Courtès, 2015/05/19
- 34/118: Add builtin function ‘fromJSON’, Ludovic Courtès, 2015/05/19
- 36/118: Fix compilation error on some versions of GCC, Ludovic Courtès, 2015/05/19
- 32/118: Style fix, Ludovic Courtès, 2015/05/19
- 46/118: Fix use of sysread, Ludovic Courtès, 2015/05/19
- 33/118: Manual: html -> xhtml, Ludovic Courtès, 2015/05/19
- 45/118: nix-copy-closure -s: Do substitutions via ‘nix-store --serve’, Ludovic Courtès, 2015/05/19
- 40/118: Remove maybeVfork, Ludovic Courtès, 2015/05/19