 Sondra van der Berg talking to us today about deploying NPM packages with the NICS package manager. Okay, thank you for the introduction. So this presentation will be about something that I've been working on for quite a while for about two years. And this project isn't actually something I really like that much doing. There's actually another reason why I'm doing this. And by basically making the NPM and NICS integration possible, you can do lots of cool things. So by the way, before I start my presentation, how many of you have heard of the NICS package manager or NICS OS? Oh, that's actually quite a few. So I'm a NICS developer since 2007. I'm using it in my daily work, also my home computers and pretty much everything else I could run it on. And the purpose of the NICS package manager is basically the NICS project is a family of deployment tools. And what they all have in common is that they support declarative deployment. So the idea is you write what you want to declare the specification. And from one single specification, you automate the full deployment process. And the basis of everything is the NICS package manager. But we have other sub-projects as well, like NICS OS, which is a Linux distribution build around that concept. We have something called HYDRA, that's a continuous integration server built on the same concepts. We have this NICS, that's also a project that I've been doing since 2008. You can use that to model distributed systems consisting of microservices or other web services and deploy them automatically to a network. There's also NICSops, which you can use to deploy a network of NICS OS machines into the cloud, such as Amazon EC2. So besides automated deployment, the tools in the NICS project also have a number of interesting non-functional properties. So one of them is that all the NICS solutions are generic solutions. So that means it shouldn't really matter what technology you use. If you use the C program language, C++ program language, make files, Perl, Python, Ruby, Java, it shouldn't really matter. You can use the NICS package manager for all these technologies. Also another important property of the NICS package manager is reproducible deployment. So what NICS tries to do is it tries to hide as many impurities that will potentially influence package builds as possible. And that typically means that if the inputs of a certain build are the same, then it doesn't really matter where you perform the build. The builds should always yield the same result. Another property of the NICS project is reliable deployment. So in order to support reliable deployment, NICS, for example, ensures that dependencies are always complete and also offers things like almost automatic upgrades and rollbacks. And another thing that NICS tries to do is it tries to be efficient in the sense that it only carries out the activities that it needs to do and nothing more trying to make deployment process not unnecessarily long. So if you, for example, take any sub-project in the NICS project like NICS OS, if you want to install NICS OS on your machine, then this is the typical workflow. So it looks a bit odd compared to conventional Linux distributions. What you do in NICS OS is you provide a declarative specification of your machine structure. So, for example, this configuration in this slide could represent my laptop's configuration. So you can describe things like I want to use the Grub Bootloader. I want to use these file system partitions. I want to use these swap partitions. As a system server, I want to run open SSH. I want the Xserver running the KDE4 desktop. I can also provide all the end-user packages that I want such as the Firefox web browser and the Midnight Commander. And what you then typically do is you run one single comment line instruction, NICS OS RebuildSwitch, for example. And what happens is NICS OS RebuildSwitch will deploy the entire machine configuration from scratch. So it will obtain all the necessary dependencies packages. It will build everything from source code if it's required. It will also generate all configuration files. And the end result is you have a running system with all your system services, your desktop, and everything else that you want. What you can also do is you can change this specification to have different properties. And if you run NICS OS RebuildSwitch again, then it will upgrade the system. And upgrades are always safe. So NICS will never overwrite anything. So you can always, for example, if you break your system, switch back to any previous configuration. And that's also, for example, something you can see in the Grub Bootloader. You have a question? Yeah, why did they always? Well, that's because, for example, if we upgrade the system, we use, for example, system D to manage system services. And they need to be stopped and restarted. And then you still observe a bit of downtime. And that's, yeah, system services are unavailable for a while. So from a static point of view, your system is upgraded atomically. But because you still need to change things at runtime, yeah, there's still observable side effects. And that prevents it from being truly atomic. So this is what the Grub Bootloader looks like. So if you boot NICS OS by default, it boots your latest configuration. But all previous configurations that you have garbage collected yet, you can also pick them. So if after an upgrade, for example, you suddenly have no display anymore because your display driver broke, you just pick an older configuration and then you're safe again. So the basis of the NICS project and knowledge sub-project is the NICS Package Manager. So the idea of the NICS Package Manager is actually its package organization, which looks a bit scary if you look at this slide. And the scary part is actually the file names. So the NICS Package Manager stores everything in a so-called NICS store in isolation. And as you can see, the first component of each path is a hash code. And we derived that hash code from all involved build time dependencies to build a package. So for example, the source code, the versions of the compilers, linkers, the build scripts, all these properties are reflected in the hash. And if I would, for example, upgrade GCC to a newer version and I would compile Firefox again, then it will yield a different hash code. And because every package has a hash prefix and a unique name, we can easily store multiple variants of many packages safely next to each other without any interference. Another property of the NICS Package Manager is the NICS Package Manager, like NICS, so as is also declarative. So it uses so-called NICS expressions to build packages from source code and its dependencies. And in this slide, this NICS expression is used to compile open SSH from source code and its dependencies. So a NICS expression, for example, the expression shown in this slide, is basically a function definition in a purely functional programming language. And the first line is basically the function arguments of that function. And they correspond to the build time dependencies that you need to build the package. So the first two arguments, the STDN, that's a standard UNIX environment providing common UNIX utilities like CAT and LS and MAKE. FATUREL is something that can be used to download files from external locations. And open SSL and ZLIP are required library dependencies of open SSH. And what we do in the body is we call the MAKE derivation function. That's basically the NICS way of saying I want to build something from source code. We provide some metadata parameters, like the name and version. And we download the open SSH star above from the open SSH server. And what we do in the body is we provide a number of build instructions to build open SSH from source code. So open SSH uses an auto-tools-like build procedure. So that basically means untar the tar ball and run configure, make and make install. So there's one practical issue with this expression. So this expression basically describes how to build a package from source code and its dependencies. But we also, for example, need to know which version of ZLIP do we want to use and which version of open SSL. And that's actually done in a second expression. So the first expression here is basically a function definition. But you need to invoke a function with function arguments. So what I do in this expression here, for example, is I import my expression in the previous slide. And as function parameters, I provide the build time dependencies that I want to use at that moment. So that means a specific version of open SSL and a specific version of ZLIP. And also, all the other packages, open SSL, ZLIP, Perl and even G-Lap C, are composed in a similar way. And if you would run, for example, in the command lines instruction, this command line, this instruction here, what it will do is it will build all the build time dependencies first and then the package itself. And the end result would be a NIC stored path corresponding to our open SSLH build. So using hash codes to isolate packages, that's quite nice. But the inconvenience is if you're an end user and you want to start, for example, Firefox installed by NICs, there's no way that you can remember a hash code. So you need some kind of mechanism built around it to make packages more accessible. So for this, NICs introduces the concept of user environments. So the idea is if you, as an end user, install packages, what happens is it will compose a user environment, as you can see in the top, and that's basically a symboling tree, basically synthesizing the contents of all the packages into one huge symboling tree so that it becomes accessible from one single location. And it also uses a number of indirections. So each time you install software, there's a generation symboling created that refers to our user environment. And there's also a current symboling referring to our current set of installed packages. And by adding the location to that symboling in the user's path environment variable, if you would, for example, type Firefox on the command line because it indirectly results to the user environment, you can start Firefox. So with a number of indirections, you can circumvent users from remembering hash codes. What you can also do at some point is you may want to update OpenSSH to a newer version, for example. What would happen is if you run this command line instruction, it will install a new OpenSSH version next to the existing packages so nothing will be overwritten. And then it generates a new user environment with a new version of SSH inside it. And then it creates a new version symboling for D3, and finally it flips the current symboling to the latest generation. And flipping a symboling is actually an atomic operation on Unix. And because a flipping symboling is atomic, also package upgrades with Nix are atomic. Then there's another thing you might also want to get rid of obsolete packages. I can imagine that you want to get rid of this old OpenSSH version that's highly insecure. So in Nix you never directly remove packages. What you do instead is you simply remove it from your user environment. And the Nix package manager sees which paths are still reachable from a generation symboling. And by removing the old symbolings, for example by executing this command line instruction, that removes the symboling 42, Nix sees this path is no longer reachable. And if you're in the garbage collector, then it safely removes all the packages that are no longer in use. And also besides user generation symbolings, open files and running processes are considered garbage collector routes. So that means if your program happens to be running, Nix will not remove it. So you can basically always run Nix, collect garbage at any point in time without being afraid that something that you might use is accidentally deleted. So I've shown you this expression for OpenSSH. Now some people tell me that Nix is actually a build tool. But I think that is basically a mistake. Nix is actually not building anything. What it actually does is it complements existing build tools with a pure environment. But in that environment you can basically run whatever you want. You can run make, but you can also run other build tools like CMake, SCONS, and you can build any kind of software in it. So to make builds pure, Nix basically takes a number of precautions in the build environment to take as many side effects away that will potentially influence the build reproducibility. So for example what Nix does is it clears almost all environment variables or it sets them to dummy values. But it also does with search environment variables like path or Python path. It configures them in such a way that they only contain the Nix store paths of the packages implementing them. So you can't use global dependencies. You can only use the Nix packages that you have specified. And if you forget to specify for example dependency then the build might fail. But that's actually a good thing because if you would silently allow a build to succeed because of a global dependency that means it might work on my machine but it might not work on another machine. It also does some other tricks. So for example it only allows packages to write in designated output folders. So if you build a package on your machine it isn't allowed to pollute your file system. It can only write in one designated output folder and that's it. It also does things like resetting time step to one and it can optionally use crude environments to even reduce the amount of side effects even further. And it also restricts network access while doing a build. And that's also a good thing because if you would for example download a file from a remote server you don't really know for sure what you get unless you for example provide an output hash allowing you to validate the end result. So in Nix network access is allowed except if you provide a build with an output hash against which we can validate. So what I basically explained is that Nix has all kinds of nice features right. So reproducibility, reliability and you can also use it for many kinds of software. But what about Node.js? Is here anyone using Node.js by the way? So quite a few. So it would be nice that we can also have best of both worlds right. So we use Node.js but we also at the same time want to profit from Nix's nice deployment properties. But there's one problem. If you use Node.js you basically can't get around NPM. Is there anyone using Node.js without NPM? Which package manager are you using? How do the geeks important? Oh okay. That's interesting. Yeah. Does it yarn? Yarn yes. Yeah and IED that's another project I'm aware of. But yeah most people are using NPM so there's basically no way around it. But the problem with NPM is NPM isn't a build tool. It's also a dependency manager. And that actually conflicts with Nix's dependency management features. And also Nix gains arch potential benefits from the way it organizes the dependency management. And if you would bypass that then there's no point in using Nix right. So this is basically how you would normally I guess most of you probably already know. For example if you're a development project what you typically do is you provide a packageization file that might look like this. You provide some metadata and for example you provide the dependencies that you want. And what you then do is you run NPM install in the command line. And what NPM does is fetches all the dependencies and puts them into the node folders of the same project. Now how can we deal with this conflict? The solution is actually quite simple from a theoretical perspective at least. You just substitute the conflict in the dependency manager by doing the dependency management yourself in the Nix environment. And if you somehow fetch the dependencies yourself first then node NPM doesn't have to install them anymore. That sounds very simple. So basically you could do something like this. So this is the NPM install instruction that I run in the Nix expression. And before that I somehow obtain the node dependencies I want and I put them in the node modules folder. What I can even do is if you take a closer look at this expression here and the packageization you see that they capture quite similar properties. So I could even automatically generate the Nix expression. So everything appears to be quite straightforward right? But is it really that straightforward? I have to tell you it's actually much more complicated than just that. And there are actually many reasons for that. The first reason is if you would look at for example the packageization documentation then you'll see that NPM has many kinds of dependencies. For example it has a concept of dependencies corresponding to runtime dependencies. But also it has a notion of development dependencies. In Nix there is no notion between runtime dependencies and build time dependencies in the sense that you just provide dependencies to build their environment and the builder should figure out what to do with it. NPM also has peer dependencies that's basically used as a conflict resolution mechanism. But the NPM authors don't seem to know themselves even what it's supposed to mean because in older versions peer dependencies were also automatically installed but later they changed this behavior to purely a check. So you also have to cope with that difference in generating an expression for example. And also it has bundle dependencies. Bundle dependencies are basically node modules already in the package that you don't have to download again. And also it supports optional dependencies in the sense that optional dependencies are allowed to fail. And if they fail then the package installation still succeeds. And that's also somewhat incompatible with the Nix deployment model especially if these failures are non-deterministic for example because of a network failure or something. But if you want to create a generator what we basically only have to do is we only have to look at the dependencies and development dependencies if they have been requested and we have to subtract the optional dependencies. And peer dependencies for example we don't have to do anything with them because they're merely a check. Then there's another thing. So version numbers in NPM are basically semantically versioned so that means they consist of three version components having a specific meaning. And these version numbers are typically used to refer to packages in the NPM registry. But you can use this, you can use precise version numbers. They refer to one specific version in the NPM registry but you can also use version ranges so you can specify things like I want the version of this package to be 1.0.1 or higher or something like that. You can also use tags and tags indirectly resolved to version numbers. But besides NPM, packages that come from the NPM registry you can also use your own external location so you can also refer to dependencies in your own home directory. You can refer to Git URLs, you can refer to repositories on GitHub and Bitbucket and so on. Now if you want to make a translation so in NICS we use hash codes to identify packages and in NPM they use a name and a version number. So how can we make a translation between these two means of specifying versions? And there's only one solution from my perspective. So for example converting a specific version is easy because you know what you get from the NPM registry but if you have a version range for example any version higher than 1.0 that's incompatible with NICS because if for example you would relate a hash code to a version range that means if I would download the package today I might get version 1.0 and tomorrow I get version 1.1 and I still get the same hash code so I lose the ability to reproduce. So the only solution to cope with this is you snapshot basically the version that you want to use. So you basically look at where does that version range resolved to today and I use that version and I generate an output hash for that and that's what I use for my packages. Then there's another challenge and I have to admit that this is actually quite difficult to explain because the first time I studied this I think it baffled me at least 10 times and if you don't understand what I'm explaining in the next two slides I forgive you because it's still baffling me in some sense still and also feel free to ask questions about it. So in Node.js you have the common JS module loader system so if you would for example refer to a module that's provided as a package for example the slash package that's one of my own modules but it basically uses some kind of lookup strategy so it will first consult the Node.js folder of the project but if the package isn't in there it will consult the parents Node.js folder and will recursively look upwards until the dependency has been found and this has all kinds of implications so this is also for example how private and shared dependencies are implemented in NPM so a private dependency is basically just a dependency residing in a package Node.js folder and any package that can be reached through a parent Node.js folder is a shared dependency now this having shared dependencies and private dependencies is nice but there are some things you may probably not know about NPM so if for example you have a package that declares a version range like I want a package that's 1.0.0 higher and there's a shared dependency that's older than the newest version it will use that shared dependency instead of downloading the latest dependency from the NPM registry so in certain scenarios it might happen that you don't use the latest version while you might expect that you have and I think this is really really bad because you might reintroduce security flaws for example of which you probably have expected them to be resolved and the same thing is also cycles are allowed and there are actually quite a few Node packages depending on packages with cyclic dependencies but NPM, I don't think it's the intention to permit cyclic dependencies but because they use this strategy in which they don't install shared dependencies again they break the cycle but for a generator we have to simulate that kind of odd behavior because in NICS you can't support it so if you would for example use any version of NPM lower than 3.0 what happens is if you're an NPM installed then all packages are installed privately by default unless there is a shared dependency already satisfying any of the versions of SFIRIS so what you can see here for example is an example of that application that depends on express and EJS and these are accepts and array, flatten, content disposition are installed privately for the express package what happens in the newer NPM, so in 3.0 and higher everything is shared by default so what would happen is it will move all the library dependencies as high in the Node modules here as it possibly can until a conflict has been encountered so what you see for example here is that the dependencies of express, so accepts array, flatten and content disposition are in the same folders express itself that's also quite strange the first time I saw this I sort of had a headache like oh man how am I going to deal with this I don't know what to do anymore also the NPM developers realized that they made the mistake because what for example happens is if you have a project and you run NPM install and at some point you change the packages and you run NPM install again then the resulting Node modules tree is different than a fresh NPM installation so the order in which you install packages suddenly matters so NPM installers isn't deterministic anymore by introducing flat module installations so in my generator because of all these properties the node modules dependency tree is an imperative operation that means after I have built packages I need to modify the dependency tree in such a way that it becomes flat again but NICS packages can never be changed after they have been built so I have to find for another solution in the generator to deal with that and the only option I see is I need to compose the entire dependency tree ahead of time so instead of translating an NPM package to NICS package I basically translate an NPM package and all its dependencies to one single package and that's basically the only option I can think of and then something else so in my presentation I had this theory that if I would provide the dependencies of NPM myself and I run NPM install then I don't have to download anything anymore but it is also not entirely true if you use for example the git URLs in your package then for each NPM install run NPM will always try to remotely connect to the repository to see to what version it resolves so I need to bypass that and what I do currently is I bypass the version number by a star but that's not really a nice solution because sometimes NPM gets confused by it but better would probably be to fake the git process to always give a deterministic result but that's still a work in progress because I'm thinking about so the solution so if I would take all my lessons into account that I've described previously and I create the tool out of it which I actually did then I can use nix to deploy node packages so I have the solution well sort of the solution I mean there are still some flaws in it but it works we can actually get quite far with it so how can you use node to nix you can use it on project level so it's particularly useful if you're doing development I can actually show you how it works so for example this is the node to nix generator tool that I've created it's a node project itself what you would normally do in development mode is you run NPM install to get the dependencies what I can also do instead is I run node to nix to generate nix expressions instead maybe I should do this better so I already generated the expressions in order to save time but this is what you get what I can then do for example is I can run the nix package manager to build my project and this should be relatively fast let's see how much time this takes okay I already pre-built the package but this is the resulting package as you can see it also has a nix store pad with a hash prefix and I can simply run my tool like this and it should work just fine what I can also do is what I just did is I created the package that you would normally use as an end user but what you can also do is you can start an interactive shell session like this and that's really useful while actually coding so if you're coding you also need all NPM dependencies to present in order to run your tool in this shell basically the node path environment variable so as you can see the node path environment variable has been configured to contain all the node dependencies that I need and also in this shell I can for example run my tool like this and because the node path environment variable has been set to the dependencies obtained by the nix package manager it works another use case is this is particularly useful for end user packages so if for example you want to run Bower on the command line or the Grunt CLI you can also specify in an array the packages you want and you can use any version specifier that NPM supports and from this JSON file you can also create a nix expression allowing you to deploy any package from the package set like node to nix so typically you would use npm install dash g and this is actually a nix alternative for npm install dash g and there's also a third use case so there are also some tools using npm as a plugin manager for example Grunt is a build tool and it uses npm to obtain the Grunt plugins and what you typically do is you define them as development dependencies what you then do is you run npm install after you do npm install and this workflow is also supported by node to nix so what you can do is you can provide the global packages that you want in a supplemental json configuration and if you generate an expression like this so you provide the package json file but also the supplemental json configuration then you can fully automate for example Grunt workflow so what I for example specify the expression here is I overwrite the early expression and I state here that run after npm install run grunt and then I can build grunt projects in a nix environment and you can also use this for other builders so for gullop and eslint this also should work fine so yeah that basically concludes my presentation so what I've been trying to explain in this presentation is the difference between nix and npm's deployment concepts I've also shown you node to nix which you can use to generate nix expressions you can use the nix package manager to deploy npm packages and why is this useful so besides having the nix package manager to deploy node packages you can also for example include node packages in your nix OS configuration and deploy it as part of an entire system and you can even deploy entire networks of machines with node processes inside them and that's actually why this node to nix generator is such a great thing to develop it but the potential applications that you can build on top of that is awesome I think and then there are some lessons I learned from this experience so if you for whatever reason need to develop a language specific package manager self I would advise first of all think about how to name packages so I would say naming a package by a name and a version only that typically doesn't suffice so in nix we use hash codes for that reason but also if you take a look at Microsoft for example they use for the .NET global assembly concept called strong names which includes cryptographic keys also organization is important so isolate your dependencies well don't put them in some kind of global name space and also cyclic dependencies disallow them I see this quite a lot but packages are supposed to be units of reuse and if two packages are mutually dependent on each other then it's no longer reuse anymore they should ideally belong together so if you want to know more this is not node to nix is not the only generation attempt there's also npm to nix which is actually older than node to nix it's actually much faster because it actually constructs packages for each npm dependency but it's less compatible and there's also a Haskell implementation called nix from npm that implements the same concepts but they also support partial regeneration to make things faster and then there's also some npm alternatives so there's yarn for example the main difference between npm and yarn is that yarn for example supports a lot of parallelization to improve the speed of deployment and it also supports version blocking so whenever you install a version from a version range yarn will create a yarn lock file pinpointing your installation to that version so that you can reproduce an installation elsewhere and there's also IED and IED I think that's a really nice effort because the author first of all says I draw I basically use nix as my inspiration source for developing this package manager and also he supports things like content addressable store, atomicity and maximal sharing of dependencies so if you want to know more so here are some references the nixOS website a link to the nix package manager and of course the note to nix generator itself so that you can start using the nix package manager for deploying your npm packages so that's it any questions? yeah you explained that A the build inputs are used to manage and B that the build is to be deterministic so what happens if I have a C program that uses a timestamp at which it is built to display the front time if I build it twice it will have the same harsh bits that's a very good question so in an earlier slide I've shown you some of the precautions that nix takes I think they're here but this is not sufficient there are still ways to cheat and get impurities sneaked in and timestamps the ones you refer to like if you would for example use a C call to obtain the time then you have an impure build that's not something nix would guard you against so nix has lots of means to guard you against certain things but by no means it's enough and timestamps is actually still the biggest source of impurities but we're working on that do you guys have similar models when building a cabal to nix and is there a pip to nix as well there is pipi to nix but I have to admit that I haven't used it myself that much and there's also cabal to nix and cabal to nix I must admit it's been over 10 years ago that I did Haskell development so I'm probably not the best person to ask but we have a very mature generation tool already supporting actually quite a few packages so there's actually a developer spending a significant time a significant portion of his spare time in making that generator other questions I couldn't hear you but it was about hashes right what is actually included in the hash you mean which properties the question is which properties are included in the hash so hashes are actually computed recursively in nix if you want to know more about it but for example if you take this expression here as you can see on top that's a function decoration the function header is the first line what you basically do in the body is you invoke the make derivation function all properties to the make derivation function all function parameters are except for the meta property but that's not used in the slide is basically used to compute the hash yes well actually the output hash of the tar file is used and the same thing for example with the dependency so open as a zl and zlib are basically nix store paths having own unique hash code as well so hash codes are computed recursively so that also means for example if you use another zlib function you have a zlib with a different nix store path and as a result the hash of the corresponding build will also be different yeah do you know if there were experiments to run the nix package manager on other distributions nix OS? that's also an interesting question yes so the nix packages the basis of nix OS but it can also be used as an independent package manager in other systems and besides linux also you can use conventional linux distributions of course OS x is quite well supported some people want to make it an alternative to homebrew and there's also some limited success with nix on free bsd and sikwin and open bsd and several other unix clones about the darwin support for OS x i mean it's part of the nix OS 3.0 stuff could you repeat so it's about darwin yeah so from the nix yeah yeah i still don't know what the question is maybe because you're in the back oh okay sorry never mind but it's great that contributing to nix that's awesome i appreciate it very much other questions so the nix command line that's sometimes a bit difficult to use mostly for established reasons and there was a bit of issue or pro request about free implementing of the whole command line system but i think there's not so much progress so yeah there's indeed so nix and for example was historically inspired by rpm and also the command line options that it implements are similar to it yeah there's indeed a new effort i think it's already in progress for a year or something like that but i believe there are many more big things on going in the nix code base for example also reorganizing substitutions and stuff like that and i think it will still take a while before that completes but you have to ask the nix maintainer he's doing most of the development work on it so are you trying to distinguish between already compiled and minified javascript do you try to build javascript packages completely from source or do you download the minified you mean as an npm dependency or in general well we just we try to mimic whatever npm does in certain scenarios so if that happens to be a minified version of javascript then that's also what you get there's no specific objective besides mimicking what npm does because i also would like to change many things to npm besides but yeah i'm afraid i can do that so yeah other questions you have certain packages i think like fibers when you install them and the binary will be compiled how do you handle that you mean how to handle software that isn't available in source form or yeah that's also a very good question so in principle nix is a source based package manager it supports binary deployment for example by its reproducibility properties and the hash codes for example if you install nix os and you compile a package a package yields a hash code and it also for example she says there's a build server remotely with an identical hash code so i can download that instead but there's also indeed software that doesn't exist in source form to make them work that's quite tough actually in nix there's actually a tool called patch elf that you need to use for that purpose because for example binary is compiled elf executables compiled in the nix environment have the patch to the libraries that you need hardwired into the rpath header and for pre-built binaries there is no rpath header with the locations to the libraries so if you would run a pre-built executable on the nix os then it won't work but there's a tool called patch elf that you can also run in nix expression to provide the missing build paths and then the patch executable will run without problems on nix os other questions i guess that's it