Skip to content

Commit 88cd2d4

Browse files
committed
Add plugins to make Nix more extensible.
All plugins in plugin-files will be dlopened, allowing them to statically construct instances of the various Register* types Nix supports.
1 parent f201b77 commit 88cd2d4

File tree

24 files changed

+122
-3
lines changed

24 files changed

+122
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ perl/Makefile.config
3838
/scripts/nix-copy-closure
3939
/scripts/nix-reduce-build
4040
/scripts/nix-http-export.cgi
41+
/scripts/nix-profile-daemon.sh
4142

4243
# /src/libexpr/
4344
/src/libexpr/lexer-tab.cc

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ makefiles = \
2424
misc/launchd/local.mk \
2525
misc/upstart/local.mk \
2626
doc/manual/local.mk \
27-
tests/local.mk
27+
tests/local.mk \
28+
tests/plugins/local.mk
2829

2930
GLOBAL_CXXFLAGS += -std=c++14 -g -Wall -include config.h
3031

doc/manual/command-ref/conf-file.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,33 @@ builtins.fetchurl {
742742
</varlistentry>
743743

744744

745+
<varlistentry xml:id="conf-plugin-files">
746+
<term><literal>plugin-files</literal></term>
747+
<listitem>
748+
<para>
749+
A list of plugin files to be loaded by Nix. Each of these
750+
files will be dlopened by Nix, allowing them to affect
751+
execution through static initialization. In particular, these
752+
plugins may construct static instances of RegisterPrimOp to
753+
add new primops to the expression language,
754+
RegisterStoreImplementation to add new store implementations,
755+
and RegisterCommand to add new subcommands to the
756+
<literal>nix</literal> command. See the constructors for those
757+
types for more details.
758+
</para>
759+
<para>
760+
Since these files are loaded into the same address space as
761+
Nix itself, they must be DSOs compatible with the instance of
762+
Nix running at the time (i.e. compiled against the same
763+
headers, not linked to any incompatible libraries). They
764+
should not be linked to any Nix libs directly, as those will
765+
be available already at load time.
766+
</para>
767+
</listitem>
768+
769+
</varlistentry>
770+
771+
745772
</variablelist>
746773

747774
</para>

doc/manual/release-notes/rl-2.0.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,13 @@ configureFlags = "--prefix=${placeholder "out"} --includedir=${placeholder "dev"
389389
</para>
390390
</listitem>
391391

392+
<listitem>
393+
<para>
394+
Nix can now be extended with plugins. See the documentation of
395+
the 'plugin-files' option for more details.
396+
</para>
397+
</listitem>
398+
392399
</itemizedlist>
393400

394401
<para>Some features were removed:</para>

mk/libraries.mk

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ endif
4545
# - $(1)_INSTALL_DIR: the directory where the library will be
4646
# installed. Defaults to $(libdir).
4747
#
48+
# - $(1)_EXCLUDE_FROM_LIBRARY_LIST: if defined, the library will not
49+
# be automatically marked as a dependency of the top-level all
50+
# target andwill not be listed in the make help output. This is
51+
# useful for libraries built solely for testing, for example.
52+
#
4853
# - BUILD_SHARED_LIBS: if equal to ‘1’, a dynamic library will be
4954
# built, otherwise a static library.
5055
define build-library
@@ -149,7 +154,9 @@ define build-library
149154
$(1)_DEPS := $$(foreach fn, $$($(1)_OBJS), $$(call filename-to-dep, $$(fn)))
150155
-include $$($(1)_DEPS)
151156

157+
ifndef $(1)_EXCLUDE_FROM_LIBRARY_LIST
152158
libs-list += $$($(1)_PATH)
159+
endif
153160
clean-files += $$(_d)/*.a $$(_d)/*.$(SO_EXT) $$(_d)/*.o $$(_d)/.*.dep $$($(1)_DEPS) $$($(1)_OBJS)
154161
dist-files += $$(_srcs)
155162
endef

src/build-remote/build-remote.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ int main (int argc, char * * argv)
6464

6565
settings.maxBuildJobs.set("1"); // hack to make tests with local?root= work
6666

67+
initPlugins();
68+
6769
auto store = openStore().cast<LocalStore>();
6870

6971
/* It would be more appropriate to use $XDG_RUNTIME_DIR, since

src/libmain/shared.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public:
2222

2323
int handleExceptions(const string & programName, std::function<void()> fun);
2424

25+
/* Don't forget to call initPlugins() after settings are initialized! */
2526
void initNix();
2627

2728
void parseCmdLine(int argc, char * * argv,

src/libstore/globals.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <algorithm>
77
#include <map>
88
#include <thread>
9+
#include <dlfcn.h>
910

1011

1112
namespace nix {
@@ -137,4 +138,18 @@ void MaxBuildJobsSetting::set(const std::string & str)
137138
throw UsageError("configuration setting '%s' should be 'auto' or an integer", name);
138139
}
139140

141+
142+
void initPlugins()
143+
{
144+
for (const auto & pluginFile : settings.pluginFiles.get()) {
145+
/* handle is purposefully leaked as there may be state in the
146+
DSO needed by the action of the plugin. */
147+
void *handle =
148+
dlopen(pluginFile.c_str(), RTLD_LAZY | RTLD_LOCAL);
149+
if (!handle)
150+
throw Error(format("could not dynamically open plugin file '%1%': %2%") % pluginFile % dlerror());
151+
}
152+
}
153+
154+
140155
}

src/libstore/globals.hh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,12 +367,19 @@ public:
367367

368368
Setting<Strings> allowedUris{this, {}, "allowed-uris",
369369
"Prefixes of URIs that builtin functions such as fetchurl and fetchGit are allowed to fetch."};
370+
371+
Setting<Paths> pluginFiles{this, {}, "plugin-files",
372+
"Plugins to dynamically load at nix initialization time."};
370373
};
371374

372375

373376
// FIXME: don't use a global variable.
374377
extern Settings settings;
375378

379+
/* This should be called after settings are initialized, but before
380+
anything else */
381+
void initPlugins();
382+
376383

377384
extern const string nixVersion;
378385

src/libstore/local.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ libstore_SOURCES := $(wildcard $(d)/*.cc)
99
libstore_LIBS = libutil libformat
1010

1111
libstore_LDFLAGS = $(SQLITE3_LIBS) -lbz2 $(LIBCURL_LIBS) $(SODIUM_LIBS) -pthread
12+
ifneq ($(OS), FreeBSD)
13+
libstore_LDFLAGS += -ldl
14+
endif
1215

1316
libstore_FILES = sandbox-defaults.sb sandbox-minimal.sb sandbox-network.sb
1417

0 commit comments

Comments
 (0)