Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nix develop? #94

Closed
mikepurvis opened this issue Apr 18, 2021 · 7 comments
Closed

nix develop? #94

mikepurvis opened this issue Apr 18, 2021 · 7 comments

Comments

@mikepurvis
Copy link
Contributor

I was wondering if it were possible to get nix develop and nix build working, for which the main barrier seems to be impurity issues. I enabled Flakes on my system, and then following #52 and a similar modification as #64 (comment), I ended up with this default.nix:

{ nixpkgs ? builtins.fetchTarball {
  url = "https://github.com/lopsided98/nixpkgs/archive/2d5ea251675e5c00334e577f37acf988559bbc32.tar.gz";
  sha256 = "0400allb79dsa26hz5yhn1r0qkrq7c45ifich2a7s974mfwxxvg0";
}
, overlays ? [], ... }@args: import nixpkgs {
  overlays = [ (import ./overlay.nix) ] ++ overlays;
} // args

And this flake.nix:

{
  description = "ROS overlay for the Nix package manager";

  inputs = {
    nixpkgs.url = "github:lopsided98/nixpkgs/nix-ros";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils }:
    with flake-utils.lib;
    eachSystem allSystems (system: let
      pkgs = import nixpkgs {
        inherit system;
        overlays = [ self.overlay ];
      };
    in {
      packages = pkgs.rosPackages;
      devShell = import ./ros-base.nix { inherit pkgs; rosPackages = pkgs.rosPackages;};
    }) // {
      overlay = import ./overlay.nix;
      nixosModule = import ./modules;
    };
}

And this ros-base.nix, which works fine when run with, eg nix-shell ros-base.nix:

with import ./. {};
with rosPackages.noetic;
with pythonPackages;

mkShell {
  buildInputs = [
    glibcLocales
    (buildEnv { paths = [
      ros-base
    ]; })
  ];

  ROS_HOSTNAME = "localhost";
  ROS_MASTER_URI = "http://localhost:11311";
}

However, trying to run nix develop in this path, I get:

error: cached failure of attribute 'devShell.x86_64-linux'

Or, depending on various bits of fiddling I can instead get:

error: attribute 'packages.x86_64-linux.devShell' already defined at /nix/store/g07ps14skfcpdaiim58vp5443n47qjcj-source/flake.nix:17:7

       at /nix/store/g07ps14skfcpdaiim58vp5443n47qjcj-source/flake.nix:18:7:

           17|       packages = pkgs.rosPackages;
           18|       packages.x86_64-linux.devShell = import ./ros-base.nix { inherit pkgs; rosPackages = pkgs.rosPackages;};
             |       ^
           19|     }) //

Or:

error: flake 'git+file:///home/administrator/nix-ros-overlay?shallow=1' does not provide attribute 'packages.x86_64-linux.devShell.x86_64-linux', 'legacyPackages.x86_64-linux.devShell.x86_64-linux', 'devShell.x86_64-linux' or 'defaultPackage.x86_64-linux'

Or sometimes:

error: attribute 'currentSystem' missing

       at /nix/store/5s8qz8mcbhb0byrdwym9vg3x72fkmg5r-source/pkgs/top-level/impure.nix:18:43:

           17|   # (build, in GNU Autotools parlance) platform.
           18|   localSystem ? { system = args.system or builtins.currentSystem; }
             |                                           ^
           19|

I feel certain I must be doing something silly wrong here. Any pointers greatly appreciated.

@mikepurvis
Copy link
Contributor Author

mikepurvis commented Apr 18, 2021

Oh wait— got it. Needed to avoid the import ./. in ros-base.nix. It works as expected with:

{ pkgs,
  rosPackages
}:
with rosPackages.noetic;
with pythonPackages;

pkgs.mkShell {
  buildInputs = [
    pkgs.glibcLocales
    (buildEnv { paths = [
      ros-base
    ]; })
  ];

  ROS_HOSTNAME = "localhost";
  ROS_MASTER_URI = "http://localhost:11311";
}

And with this setup, I can also do stuff like:

nix build .#noetic.rviz

They're not kidding about the nix learning curve!

@lopsided98
Copy link
Owner

This is what I was writing before your response, but I'm posting it anyway in case it helps you understand the details of what was going wrong:

The ros-base.nix shell file you are using is not compatible with the way you are importing it from the flake. In flake.nix, you are attempting to call the expression in ros-base.nix as a function, passing an attrset with pkgs and rosPackages attrs as the argument. On the other hand, ros-base.nix is not a function, so you would normally get an error saying as much, but there are other errors happening first. When you do import ./. {}, you end up importing nixpkgs through my wrapper that adds the overlay, and by default nixpkgs tries to detect the current system with builtins.currentSystem, which is impure and therefore not allowed with flakes.

Also, nix build .#noetic.rviz and similar works for me without any modifications. A more maintainable way to create a shell environment with flakes without modifying this repo is to create your own minimal flake that has github:lopsided98/nix-ros-overlay as an input and basically replace self.overlay with nix-ros-overlay.overlay.

@mikepurvis
Copy link
Contributor Author

Nice, thank you for the additional explanation; my original attempt was indeed to do this in a separate repo, but I was completely hitting a wall on that and so went to incremental change. :) Now that this basic step is working, I'll return to that.

Interestingly, though, the caching side doesn't seem to be working— nix develop still takes about ~4 seconds to launch for me, despite that I do seem to have fresh content being created in ~/.cache/nix/eval-cache-v2/.

Also, the difference between nix develop and nix shell is teaching me about the magic of your custom buildEnv implementation. I feel like there might be synergies/efficiencies to be had there with taking advantage of how colcon does envvar management with its dsv files (though of course it would mean all ROS package builds being wrapped in colcon rather than being their "native" CMake).

@lopsided98
Copy link
Owner

I'm not sure what's going on with eval caching. It only works when the eval is exactly the same as a previous one; even the most minor change invalidates the cache.

I've always considered my buildEnv wrapper to be kind of hacky, but it is necessary to stop large environments from exceeding the maximum environment variable length. It definitely needs some work, particularly because it doesn't handle ROS2 correctly right now. I currently use the the ament generated local_setup.sh to setup environment variables, but I haven't figured out how to generate a setup.sh for buildEnv. Would you happen to know where the code that generates install/setup.sh in a colcon workspace is located, because I haven't been able to find it?

I considered using colcon to build the packages, particularly for ROS2, but I found the current approach to be easier, at least for now.

@mikepurvis
Copy link
Contributor Author

mikepurvis commented Apr 21, 2021

It only works when the eval is exactly the same as a previous one; even the most minor change invalidates the cache.

This was my assumption, but surely it should be clean when it's called twice back to back, right?

Regarding the setup files in colcon, I found this very confusing as well and initiated a conversation here that I thought turned out pretty helpful: colcon/colcon-core#262

Basically the short answer is that colcon completely takes over environment management from the underlying build tools and replaces all the workspace sourcing files with a tiny declarative DSL for envvar operations like prepending and appending (the dsv files). This scheme has a number of benefits including that isolated workspaces can be trivially merged together, but it's also way better from a perf point of view because you can determine the environment without having to source hundreds of shell scripts.

This request is probably also relevant to our interests: colcon/colcon-core#365 ;)

@lopsided98
Copy link
Owner

Yeah, I don't know why the eval cache wouldn't work in that case.

Thanks for those links! it looks like they should have the information I need. I've been working on other projects recently, but I'll take a look at them more closely when I get a chance and see if there is anything I can integrate into the overlay.

@mikepurvis
Copy link
Contributor Author

Just popping back in here to say that the eval cache does seem to be working for me now— I don't know exactly the issue was before, but for the moment I've taken the liberty of temporarily forking and locking everything down (nixpkgs + the poco patches, nix-ros-overlay), so that may be part of it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants