Skip to content

Commit 03ec0c5

Browse files
bresillaesteve
andauthored
chore: add nix flake development shell (#617)
* Add Nix flake development shell * Address Nix flake review feedback * add support for multiple ROS distros --------- Co-authored-by: Esteve Fernandez <esteve@apache.org>
1 parent c427e1d commit 03ec0c5

2 files changed

Lines changed: 394 additions & 0 deletions

File tree

flake.lock

Lines changed: 152 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
{
2+
description = "ros flake";
3+
4+
inputs = {
5+
nix-ros-overlay.url = "github:lopsided98/nix-ros-overlay";
6+
nixpkgs.follows = "nix-ros-overlay/nixpkgs";
7+
rust-overlay.url = "github:oxalica/rust-overlay";
8+
flake-utils.url = "github:numtide/flake-utils";
9+
};
10+
11+
outputs =
12+
{ self, nixpkgs, rust-overlay, flake-utils, nix-ros-overlay, ... }:
13+
flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (
14+
system:
15+
let
16+
overlays = [ (import rust-overlay) nix-ros-overlay.overlays.default ];
17+
18+
pkgs = import nixpkgs {
19+
inherit system overlays;
20+
};
21+
22+
supportedDistros = builtins.filter
23+
(name:
24+
let value = pkgs.rosPackages.${name};
25+
in builtins.isAttrs value && builtins.hasAttr "ros-core" value
26+
)
27+
(builtins.attrNames pkgs.rosPackages);
28+
defaultDistro = "jazzy";
29+
30+
rustToolchain = pkgs.rust-bin.stable.latest.default.override {
31+
extensions = [ "rust-src" ];
32+
};
33+
34+
mkRosDevShell = distroName:
35+
let
36+
rosDistro = pkgs.rosPackages.${distroName};
37+
rosPrefixes = "${rosDistro.ament-cmake}:${rosDistro.ament-cmake-core}:${rosDistro.python-cmake-module}:${rosDistro.rmw}:${rosDistro.rosidl-default-generators}:${rosDistro.rosidl-runtime-c}:${rosDistro.rosidl-typesupport-c}:${rosDistro.rosidl-typesupport-interface}:${rosDistro.std-msgs}:${rosDistro.test-msgs}";
38+
in
39+
pkgs.mkShell {
40+
packages =
41+
[
42+
rustToolchain
43+
pkgs.gcc
44+
pkgs.clang
45+
pkgs.cmake
46+
pkgs.mold
47+
pkgs.pkg-config
48+
pkgs.colcon
49+
(with rosDistro; buildEnv {
50+
paths = [
51+
ros-core
52+
ros-base
53+
cyclonedds
54+
rmw-cyclonedds-cpp
55+
test-msgs
56+
];
57+
})
58+
];
59+
60+
RUST_SRC_PATH = "${rustToolchain}/lib/rustlib/src/rust/library";
61+
62+
shellHook = ''
63+
export LIBCLANG_PATH="${pkgs.llvmPackages.libclang.lib}/lib"
64+
export LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
65+
export CC=clang
66+
export CXX=clang++
67+
68+
dedup_flags() {
69+
local var_name="$1"
70+
local current_value
71+
current_value="$(printenv "$var_name" 2>/dev/null || true)"
72+
73+
if [ -z "$current_value" ]; then
74+
return
75+
fi
76+
77+
export "$var_name=$(
78+
printf '%s' "$current_value" \
79+
| tr ' ' '\n' \
80+
| awk '
81+
function flush_entry(entry_key, entry_value) {
82+
if (!(entry_key in seen)) {
83+
seen[entry_key] = 1
84+
print entry_value
85+
}
86+
}
87+
88+
BEGIN {
89+
expects_value["-I"] = 1
90+
expects_value["-L"] = 1
91+
expects_value["-B"] = 1
92+
expects_value["-include"] = 1
93+
expects_value["-iquote"] = 1
94+
expects_value["-idirafter"] = 1
95+
expects_value["-isystem"] = 1
96+
expects_value["-isysroot"] = 1
97+
expects_value["-iframework"] = 1
98+
}
99+
100+
NF == 0 {
101+
next
102+
}
103+
104+
pending_option != "" {
105+
flush_entry(pending_option SUBSEP $0, pending_option " " $0)
106+
pending_option = ""
107+
next
108+
}
109+
110+
{
111+
if ($0 in expects_value) {
112+
pending_option = $0
113+
next
114+
}
115+
116+
flush_entry($0, $0)
117+
}
118+
119+
END {
120+
if (pending_option != "") {
121+
flush_entry(pending_option, pending_option)
122+
}
123+
}
124+
' \
125+
| paste -sd ' ' -
126+
)"
127+
}
128+
129+
dedup_flags NIX_CFLAGS_COMPILE
130+
dedup_flags NIX_CXXFLAGS_COMPILE
131+
dedup_flags NIX_LDFLAGS
132+
133+
prepend_prefixes() {
134+
local var_name="$1"
135+
local existing_value
136+
137+
existing_value="$(printenv "$var_name" 2>/dev/null || true)"
138+
if [ -n "$existing_value" ]; then
139+
export "$var_name=${rosPrefixes}:$existing_value"
140+
else
141+
export "$var_name=${rosPrefixes}"
142+
fi
143+
}
144+
145+
prepend_prefixes CMAKE_PREFIX_PATH
146+
147+
setup_synthetic_ament_prefix() {
148+
local base_dir
149+
local synthetic_prefix
150+
local source_prefixes
151+
local old_ifs="$IFS"
152+
local prefix
153+
local category_dir
154+
local resource
155+
local existing_value
156+
local filtered=""
157+
158+
if [ -n "''${XDG_CACHE_HOME:-}" ]; then
159+
base_dir="$XDG_CACHE_HOME"
160+
elif [ -n "''${TMPDIR:-}" ]; then
161+
base_dir="$TMPDIR"
162+
else
163+
base_dir="/tmp"
164+
fi
165+
166+
synthetic_prefix="$base_dir/ros2-rust-nix-ament-prefix-${system}"
167+
mkdir -p "$synthetic_prefix/share/ament_index/resource_index/packages"
168+
169+
printf '%s\n' '#!/usr/bin/env sh' > "$synthetic_prefix/local_setup.sh"
170+
printf '%s\n' '#!/usr/bin/env bash' > "$synthetic_prefix/local_setup.bash"
171+
printf '%s\n' '#!/usr/bin/env zsh' > "$synthetic_prefix/local_setup.zsh"
172+
chmod +x \
173+
"$synthetic_prefix/local_setup.sh" \
174+
"$synthetic_prefix/local_setup.bash" \
175+
"$synthetic_prefix/local_setup.zsh"
176+
177+
find "$synthetic_prefix/share/ament_index/resource_index" -mindepth 1 -delete
178+
179+
source_prefixes="$(printenv CMAKE_PREFIX_PATH 2>/dev/null || true)"
180+
IFS=:
181+
for prefix in $source_prefixes; do
182+
if [ ! -d "$prefix/share/ament_index/resource_index" ]; then
183+
continue
184+
fi
185+
186+
for category_dir in "$prefix"/share/ament_index/resource_index/*; do
187+
if [ ! -d "$category_dir" ]; then
188+
continue
189+
fi
190+
191+
mkdir -p "$synthetic_prefix/share/ament_index/resource_index/$(basename "$category_dir")"
192+
for resource in "$category_dir"/*; do
193+
if [ ! -f "$resource" ]; then
194+
continue
195+
fi
196+
ln -sf "$resource" \
197+
"$synthetic_prefix/share/ament_index/resource_index/$(basename "$category_dir")/$(basename "$resource")"
198+
done
199+
done
200+
done
201+
IFS="$old_ifs"
202+
203+
existing_value="$(printenv AMENT_PREFIX_PATH 2>/dev/null || true)"
204+
if [ -n "$existing_value" ]; then
205+
IFS=:
206+
for prefix in $existing_value; do
207+
if [ -f "$prefix/local_setup.sh" ] || [ -f "$prefix/local_setup.bash" ] || [ -f "$prefix/local_setup.zsh" ]; then
208+
if [ -n "$filtered" ]; then
209+
filtered="$filtered:$prefix"
210+
else
211+
filtered="$prefix"
212+
fi
213+
fi
214+
done
215+
IFS="$old_ifs"
216+
fi
217+
218+
if [ -n "$filtered" ]; then
219+
export AMENT_PREFIX_PATH="$synthetic_prefix:$filtered"
220+
else
221+
export AMENT_PREFIX_PATH="$synthetic_prefix"
222+
fi
223+
}
224+
225+
setup_synthetic_ament_prefix
226+
'';
227+
};
228+
229+
distroShells = builtins.listToAttrs (
230+
map (name: { inherit name; value = mkRosDevShell name; }) supportedDistros
231+
);
232+
in
233+
{
234+
devShells = distroShells // { default = distroShells.${defaultDistro}; };
235+
}
236+
);
237+
238+
nixConfig = {
239+
extra-substituters = [ "https://ros.cachix.org" ];
240+
extra-trusted-public-keys = [ "ros.cachix.org-1:dSyZxI8geDCJrwgvCOHDoAfOm5sV1wCPjBkKL+38Rvo=" ];
241+
};
242+
}

0 commit comments

Comments
 (0)