How do I override a (seemingly) unreachable part of a nix package?

The freeswitch package is incomplete. It is missing dependencies. I don’t have the confidence or skillset yet to submit a change for fear it might negatively affect others using the package. Additionally, I’m not entirely sure about the requirements for doing so.

In this package there is a modules.nix file. It is used to declare the dependencies for each source freeswitch module for freeswitch compilation. From the comment, you can see that it is missing required inputs.

As an example, the erlang_event source module requires erlang, but that is not provided in the source. So adding anything that requires the erlang input will cause compilation to fail.

Here is what I’m using right now:

{
  description = "Telex flake";
  
  inputs = {
    nixpkgs.url = "nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils }:
   flake-utils.lib.eachDefaultSystem (system:
    let
      pkgs = import nixpkgs { 
        inherit system;
      };

      erlangVersion = "erlangR25";
      elixirVersion = "elixir_1_15";

      erlang = pkgs.beam.interpreters.${erlangVersion};
      beamPackages = pkgs.beam.packages.${erlangVersion};
      elixir = beamPackages.${elixirVersion};

      freeswitch = pkgs.freeswitch.override({ 
        modules = mods: with mods; [
          # other modules
          event_handlers.kazoo
        ] ++ pkgs.lib.optionals pkgs.stdenv.isLinux [ endpoints.gsmopen ];
      });
    in
    with pkgs; {
      packages.start-switch = pkgs.writeScriptBin "start-switch" ''
        ${freeswitch}/bin/freeswitch -base .freeswitch -mod ${freeswitch}/lib/freeswitch/mod
      '';

      devShells.default = pkgs.mkShell {
        buildInputs = [
          erlang
          elixir
          freeswitch
        ]
        ++ lib.optionals stdenv.isLinux [
          libnotify 
          inotify-tools
        ]
        ++ lib.optionals stdenv.isDarwin [
          terminal-notifier 
          darwin.apple_sdk.frameworks.CoreFoundation
          darwin.apple_sdk.frameworks.CoreServices
        ];

        shellHook = ''
        # allows mix to work on the local directory
        mkdir -p .nix-mix
        mkdir -p .nix-hex
        export MIX_HOME=$PWD/.nix-mix
        export HEX_HOME=$PWD/.nix-hex
        export ERL_LIBS=$HEX_HOME/lib/erlang/lib

        # concats PATH
        export PATH=$MIX_HOME/bin:$PATH
        export PATH=$MIX_HOME/escripts:$PATH
        export PATH=$HEX_HOME/bin:$PATH

        # enables history for IEx
        export ERL_AFLAGS="-kernel shell_history enabled -kernel shell_history_path '\"$PWD/.erlang-history\"'"
      '';
      };
    }
   );
}

The problem here is that an override isn’t enough. modules.nix needs to take additional inputs as arguments. How do I go about providing the correct inputs to modules.nix so that the source file can build?

I worked with someone elsewhere where we used overrideAttrs, but it defeats the purpose of the modules.nix file entirely. And it will get potentially unwieldy if additional items need more build inputs.

1 Like

For just adding an input to a module, you could do something like this (shown as an overlay for simplicity’s sake):

_final: prev: {
  freeswitch = pkgs.freeswitch.override {
    modules = mods: with mods; [
      # <snip>
      (event_handlers.erlang_event // {
        inputs = (event_handlers.erlang_event.inputs or []) ++ [ prev.erlang ];
      })
    ];
  };
}

Or you could use overrideAttrs to inject additional derivations into buildInputs, as that’s where all of the modules’ inputs end up.

Agree re unwieldiness; it would be nice if the default module list could be extended rather than needing to override it entirely, and also if modifying individual modules had a nicer interface than the one demonstrated above.

2 Likes

@voughtdq Were you able to figure this out? I’m just embarking on a journey to “nix-wrap” our phone service for the blind (on Ubuntu / Debian, for now. Will document it as I go along. Fingers crossed.)

1 Like

I ended up forking it and making some modifications - you might find them useful. The fork is located here. You can just copy this directly into your source tree (especially because you probably don’t care about the patches I apply to mod_kazoo). You can also override it like this:

      freeswitch = let
        modules = mods: builtins.attrValues {
          inherit (mods.applications) commands conference db dptools esf esl expr hash;
          inherit (mods.dialplans) xml;
          inherit (mods.endpoints) loopback sofia;
          inherit (mods.event_handlers) cdr_csv event_socket kazoo;
          inherit (mods.formats) native_file sndfile; 
          inherit (mods.loggers) console logfile;
          inherit (mods.xml_int) rpc;
        };
      in
      (pkgs.callPackage ./nix/freeswitch { 
        inherit (pkgs.darwin.apple_sdk.frameworks) SystemConfiguration; # why tho
        inherit modules;
      }).overrideAttrs (prevAttrs: {
        src = pkgs.fetchFromGitHub {
          owner = "voughtdq";
          repo = "freeswitch";
          rev = "15e4f73fdb845921a6d82ff4a9d09338a25f97e4";
          hash = "sha256-51wpP5KRBJ5Rj6iBawoMUUgmPP/6u83zK/F1IBFq0dU=";
        };
      });

One note of warning - that freeswitch package referenced in src no longer exists, because I now use the patches attr to apply the patches I need to freeswitch.

1 Like

Thanks a lot! I started to convince myself to re-write the FreeSWITCH package from scratch as a flake to get to know its internals better and to finally learn flakes, but I’ll post it here if I end up doing it.

Not using mod_kazoo, but I do need to apply a PR that the FreeSWITCH folks have been unwilling to merge for years, and I had no clue how to do it. Thanks again!

No problem. This can actually be used in a flake too. IIRC my flake uses that same callpackage call.

1 Like