yosys: enable loading "out of band" plugins

By default, when yosys looks for plugins with the `-m` flag or `plugin`
command, it always looks in `YOSYS_PREFIX/share/yosys/plugins` for a
`.so` file, and loads that.

By design, this is intended to be a single, global, mutable location
such as `/usr/share/yosys/...` on disk, and plugins are supposed to
install their `.so` files here after yosys is installed, and they all
coexist together. Obviously, this won't work for us, but users might
expect these plugins to still work. More importantly, they won't want to
add special cases to their build systems.

Instead, to allow Nix users to use yosys plugins with the same UX (e.g.
natively call `plugin bluespec` or `-m ghdl`), we add a patch to yosys
that allows it to search a new `NIX_YOSYS_PLUGIN_DIRS` search path
environment variable. In tandem, we add a setup hook that adds to this
search path if a package has a `$out/share/yosys/plugins` directory.

Thus, it's enough to just include `yosys`, and any package that has a
yosys plugin in `$out/share/yosys/plugins`, and you can load it with
`-m` or the `plugin` command.

We could use a style like the haskellPackages set, where the set of
packages are "encased" in a lambda, and we pass packages that are
compatible with that version of the compiler:

    haskell.packages.ghc8102.ghcWithPackages (p: with p; [ ... ])

but, realistically, there will probably only ever be one version of
yosys and one set of compatible plugins, so this seems overdone.

Signed-off-by: Austin Seipp <aseipp@pobox.com>
This commit is contained in:
Austin Seipp 2021-01-14 23:52:23 -06:00
parent 51d1125f24
commit 2660037f8c
No known key found for this signature in database
GPG Key ID: 25D2038DEB08021D
3 changed files with 42 additions and 0 deletions

View File

@ -49,6 +49,7 @@ stdenv.mkDerivation rec {
makeFlags = [ "ENABLE_PROTOBUF=1" "PREFIX=${placeholder "out"}"];
patchPhase = ''
patch -p1 < ${./plugin-search-dirs.patch}
substituteInPlace ./Makefile \
--replace 'CXX = clang' "" \
--replace 'LD = clang++' 'LD = $(CXX)' \
@ -96,6 +97,8 @@ stdenv.mkDerivation rec {
postBuild = "ln -sfv ${abc-verifier}/bin/abc ./yosys-abc";
postInstall = "ln -sfv ${abc-verifier}/bin/abc $out/bin/yosys-abc";
setupHook = ./setup-hook.sh;
meta = with stdenv.lib; {
description = "Open RTL synthesis framework and tools";
homepage = "http://www.clifford.at/yosys/";

View File

@ -0,0 +1,34 @@
diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc
index 3ed19497..f9534bd0 100644
--- a/passes/cmds/plugin.cc
+++ b/passes/cmds/plugin.cc
@@ -75,8 +75,27 @@ void load_plugin(std::string filename, std::vector<std::string> aliases)
#endif
void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL);
- if (hdl == NULL && orig_filename.find('/') == std::string::npos)
- hdl = dlopen((proc_share_dirname() + "plugins/" + orig_filename + ".so").c_str(), RTLD_LAZY|RTLD_LOCAL);
+ if (hdl == NULL && orig_filename.find('/') == std::string::npos) {
+ std::string install_dir = proc_share_dirname() + "plugins";
+
+ vector<string> all_dirs;
+ all_dirs.push_back(install_dir);
+
+ char* plugin_dirs = getenv("NIX_YOSYS_PLUGIN_DIRS");
+ if (plugin_dirs != NULL) {
+ std::string p(plugin_dirs), t;
+ std::stringstream ss(p);
+
+ while(std::getline(ss, t, ':')) {
+ all_dirs.push_back(t);
+ }
+ }
+
+ for (auto dir : all_dirs) {
+ hdl = dlopen((dir + "/" + orig_filename + ".so").c_str(), RTLD_LAZY|RTLD_LOCAL);
+ if (hdl != NULL) break;
+ }
+ }
if (hdl == NULL)
log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror());
loaded_plugins[orig_filename] = hdl;

View File

@ -0,0 +1,5 @@
addYosysPluginPath() {
addToSearchPath NIX_YOSYS_PLUGIN_DIRS "$1/share/yosys/plugins"
}
addEnvHooks "$targetOffset" addYosysPluginPath