I’ve read a lot, but didn’t get a simple answer for 3 topics I’m interested about:

  1. Are there any 3rd party repos for NixOS? It seems some people overlay one package, but I cannot find entire packagesets such as the one in Nixpkgs. Are channels used for that? Would I be able to have my own repo with several packages? Can I have more than 1 repo in my Nix system, and set which package install each program from?
  2. Would it be possible, for propietary software compiled directly for NixOS, to have a binary-only (as opposed to source, or binary+patched) repository? Everything I see is either source+cache or binary+patched, but nothing like binary especifically for NixOS.
  3. Let’s say I want to add some extra, propietary codecs unavailable to NixOS. How would I be able to change a dependency so that each package dependent on it automatically picked it? Could I switch a dependency for a certain repo from one of another, different repo?

Thank you for your support guys!

  • @Laser
    link
    fedilink
    111 months ago

    I know genAttrs “generate[s] an attribute set by mapping a function over a list of attribute names”, however for this piece of code I’d have trouble locating the list of attribute names.

    You mean packageNamesToModify? You have to provide those. I don’t know which packages could be built with my-proprietary-codec and it’s not feasible to figure that out automatically.

    Not really. Looking at genAttrs, it says that it’s genAttrs :: [ String ] -> (String -> Any) -> AttrSet, and the example code is

    genAttrs [ "foo" "bar" ] (name: "x_" + name)
    => { foo = "x_foo"; bar = "x_bar"; }
    

    So I’d expect a list of strings and the mapping function. However, from my first naive glance at the code you posted, there’s no list of strings there, and rather directly a function definition that makes use of overrideAttrs, for which for me the documentation is unclear if it can only set attributes, create attributes or what else; also buildInputs at first naive glance isn’t an attribute of the packages, but rather of stdenv (sorry if all of this is wrong), all of which isn’t exactly intuitive if you’ve only worked with imperative languages.

    I’ma let you in on a little secret: We’re not actually a binary distribution. We’re source-based.

    I do know that, that’s why I worded it like I did. In fact I have created a single package myself before and as such, did read a bit about FOB and all that, how the cache works (not that I can fully recall everything or claim that I understood it all) with input-hashes etc. I tripped over some stuff back then when I found out that which is not part of the sandbox. The program however is a bit niche and there’s another component it needs that I didn’t write a derivation for so I also never wrote a pull request, plus the build process is somewhat ugly. So I wouldn’t call myself a beginner exactly but I definitely have trouble with advanced usage of the language and the intricacies of the system.

    However, while source-based, I think it’s a common understanding that the binary cache is a huge appeal, otherwise the discussion about the cost it wouldn’t be had.

    • Atemu
      link
      fedilink
      English
      111 months ago

      Not really. Looking at genAttrs, it says that it’s genAttrs :: [ String ] -> (String -> Any) -> AttrSet, and the example code is

      genAttrs [ "foo" "bar" ] (name: "x_" + name)
      => { foo = "x_foo"; bar = "x_bar"; }
      

      So I’d expect a list of strings and the mapping function. However, from my first naive glance at the code you posted, there’s no list of strings there, and rather directly a function definition

      That’s my bad. I didn’t actually look at how the function works, so I got the arguments flipped. This is just a rough outline of how I’d imagine it to work; pseudo-code. 100% untested. Only there for the sake of argument.

      packageNamesToModify is the list of strings you’re looking for here. As I said though, I can’t know which packages are supposed to be changed. That’s a piece of info you’d need to research and define yourself. This is just how you’d apply that knowledge through a mechanism.

      that makes use of overrideAttrs, for which for me the documentation is unclear if it can only set attributes, create attributes or what else

      A function cannot “set” or “create” attributes. For better of for worse, there’s no real meta-programming in Nix.

      A function can only ever return a value. That value may be any of the primitive types such as booleans, strings, numbers, lists, attrsets etc. or even another function but it’s always a value.

      In the case of overrideAttrs { ... }, the return value is a derivation. In the case of genAttrs, it’s an attrset.

      buildInputs at first naive glance isn’t an attribute of the packages, but rather of stdenv (sorry if all of this is wrong)

      That is correct. However note how I said that overrideAttrs is about overriding arguments to mkDerivation? The canonical path to mkDerivation is stdenv.mkDerivation ;)

      mkDerivation is the way you set arguments for the stdenv. .overrideAttrs is how you “modify” the arguments to the stdenv of an existing package.

      all of which isn’t exactly intuitive if you’ve only worked with imperative languages.

      I can absolutely see that. You’ll get used to it though. When I was new to Nix, it took me quite a while to realise how you’d even do something like creating loops (spoiler: you don’t).

      I’d highly recommend familiarising yourself with basic functional programming concepts such as immutability, everything being a value (including functions, see lambdas), recursion, basic functional list comprehension (head/tail, map, filter, reduce) and perhaps even currying.

      Nix is a great learning ground for the basics of functional programming as it’s a pure expression language which is quite a bit more limited than an actual functional programming language.

      I tripped over some stuff back then when I found out that which is not part of the sandbox.

      That’s what buildInputs are for. Add which to buildInputs and it’s available inside the sandbox. The stdenv takes care of putting its binaries into $PATH and making its libraries discoverable.

      In the case of which, you’d probably need it in order to execute its binary during the build process though, so nativeBuildInputs is more appropriate but that only truly matters for cross-compilation.

      • @Laser
        link
        fedilink
        111 months ago

        Thanks for the explanation. I didn’t make the connection that buildInputs is an attribute itself as it is an attribute of stdenv instead of the function describing the derivation directly. Or at least I think that’s where my confusion comes from.

        I tripped over some stuff back then when I found out that which is not part of the sandbox.

        That’s what buildInputs are for. Add which to buildInputs and it’s available inside the sandbox. The stdenv takes care of putting its binaries into $PATH and making its libraries discoverable.

        In the case of which, you’d probably need it in order to execute its binary during the build process though, so nativeBuildInputs is more appropriate but that only truly matters for cross-compilation.

        Small correction, it wasn’t which, but rather env, I had those mixed up. The “issue” is described here: https://github.com/NixOS/nixpkgs/issues/6227 What created more problems was that patchShebangs wouldn’t work here because it appeared in a configure script that was created and run during the actual build process (I think the build process is horrible, but here it is in case you’re inclined: https://github.com/BSI-Bund/TaSK/tree/master/tlstesttool the stuff in the 3rdparty directory gets downloaded, configured and linked against in the main program’s build phase so you have no opportunity to actually follow the solution in that issue, similar to what is described here https://github.com/NixOS/nixpkgs/issues/6227#issuecomment-73410536. I got it to work in the end and like to tell myself that it’s elegant but the project’s build process is just bad in my opinion.

        https://pastebin.com/0GwLk1wP if you want to see an example of my level of nix-fu. I have programming basics but the nix language can be confusing sometimes. I’d say I have a basic understanding of things but as said before the more intricate stuff still escapes me.

        • Atemu
          link
          fedilink
          English
          111 months ago

          it wasn’t which, but rather env, I had those mixed up. The “issue” is described here: https://github.com/NixOS/nixpkgs/issues/6227

          The problem there isn’t that env isn’t available (it is, we have coreutils in stdenv) but rather that /usr/bin/env (that specific path) does not exist in the sandbox.

          What created more problems was that patchShebangs wouldn’t work here because it appeared in a configure script that was created and run during the actual build process (I think the build process is horrible, but here it is in case you’re inclined: https://github.com/BSI-Bund/TaSK/tree/master/tlstesttool the stuff in the 3rdparty directory gets downloaded, configured and linked against in the main program’s build phase

          Yikes, you don’t want that.

          so you have no opportunity to actually follow the solution in that issue

          I didn’t read the issue in full but, since everything is pre-downloaded, you can always fix these scripts.

          For the auto-generated configure script for example, you’d have to patch the build step which generates the configure script to put in ${coreutils}/bin/env rather than /usr/bin/env. Simple as that.

          3rd party repositories can be patched during their respective fetches. You have to inject them anyways since there’s no way to download 3rd party repos during a build.

          https://pastebin.com/0GwLk1wP if you want to see an example of my level of nix-fu. I have programming basics but the nix language can be confusing sometimes. I’d say I have a basic understanding of things but as said before the more intricate stuff still escapes me.

          You have to differentiate between the Nix expression language and using Nixpkgs’ frameworks to define packages here. These are two entirely different skillsets with only a slight dependence on the former by the latter.

          If you take a look at your expression, it only required fairly basic Nix syntax: Simple function calls, declaring recursive attrsets, string interpolation and attribute access. Most packages are like this.
          Figuring out which attributes need to be set how and what that means is an entirely different skillset. Defining patchPhase in that attrset is trivial syntax-wise but figuring out what needs to be substituted using which stdenv “library” function is something else entirely.

          Looks pretty good btw. I’d look into whether the build could be coerced to link against Nixpkgs’ versions of those libraries though instead of vendoring dependencies. Especially security-critical stuff like openssl. That’d probably also save you the trouble with the interpreter.
          If you take a look at the build definition, there’s this handy dandy USE_3RDPARTYBUILD option.

          I’d wager if you did cmakeFlags = [ ... "-DUSE_3RDPARTYBUILD=OFF" ]; and buildInputs = [ asio zlib openssl ... ]; (from pkgs, not your fetched sources) it’d just work. (Might need pkg-config in nativeBuildInputs but I don’t think it uses that and will instead discover those deps via cmake.)

          If you can get rid of the vendoring, feel free to submit that to Nixpkgs ;)