1{
2 stdenv,
3 lib,
4 fetchFromGitHub,
5 fetchurl,
6 jdk,
7 ant,
8 stripJavaArchivesHook,
9 libusb-compat-0_1,
10 libusb1,
11 unzip,
12 zlib,
13 ncurses,
14 readline,
15 withGui ? false,
16 gtk3,
17 wrapGAppsHook3,
18 withTeensyduino ? false,
19 # Packages needed for Teensyduino
20 upx,
21 fontconfig,
22 xorg,
23 gcc,
24 atk,
25 glib,
26 pango,
27 gdk-pixbuf,
28 gtk2,
29 libpng12,
30 expat,
31 freetype,
32 cairo,
33 udev,
34}:
35
36assert withTeensyduino -> withGui;
37let
38 externalDownloads = import ./downloads.nix {
39 inherit fetchurl;
40 inherit (lib) optionalAttrs;
41 inherit (stdenv.hostPlatform) system;
42 };
43 # Some .so-files are later copied from .jar-s to $HOME, so patch them beforehand
44 patchelfInJars =
45 lib.optional (stdenv.hostPlatform.system == "aarch64-linux") {
46 jar = "share/arduino/lib/jssc-2.8.0-arduino4.jar";
47 file = "libs/linux/libjSSC-2.8_aarch64.so";
48 }
49 ++ lib.optional (builtins.match "armv[67]l-linux" stdenv.hostPlatform.system != null) {
50 jar = "share/arduino/lib/jssc-2.8.0-arduino4.jar";
51 file = "libs/linux/libjSSC-2.8_armhf.so";
52 }
53 ++ lib.optional (stdenv.hostPlatform.system == "x86_64-linux") {
54 jar = "share/arduino/lib/jssc-2.8.0-arduino4.jar";
55 file = "libs/linux/libjSSC-2.8_x86_64.so";
56 }
57 ++ lib.optional (stdenv.hostPlatform.system == "i686-linux") {
58 jar = "share/arduino/lib/jssc-2.8.0-arduino4.jar";
59 file = "libs/linux/libjSSC-2.8_x86.so";
60 };
61 # abiVersion 6 is default, but we need 5 for `avrdude_bin` executable
62 ncurses5 = ncurses.override { abiVersion = "5"; };
63 teensy_libpath = lib.makeLibraryPath [
64 atk
65 cairo
66 expat
67 fontconfig
68 freetype
69 gcc.cc.lib
70 gdk-pixbuf
71 glib
72 gtk2
73 libpng12
74 libusb-compat-0_1
75 pango
76 udev
77 xorg.libSM
78 xorg.libX11
79 xorg.libXext
80 xorg.libXft
81 xorg.libXinerama
82 xorg.libXxf86vm
83 zlib
84 ];
85 teensy_architecture =
86 if stdenv.hostPlatform.isx86_32 then
87 "linux32"
88 else if stdenv.hostPlatform.isx86_64 then
89 "linux64"
90 else if stdenv.hostPlatform.isAarch64 then
91 "linuxaarch64"
92 else if stdenv.hostPlatform.isAarch32 then
93 "linuxarm"
94 else
95 throw "${stdenv.hostPlatform.system} is not supported in teensy";
96
97in
98stdenv.mkDerivation rec {
99 pname =
100 (if withTeensyduino then "teensyduino" else "arduino") + lib.optionalString (!withGui) "-core";
101 version = "1.8.19";
102
103 src = fetchFromGitHub {
104 owner = "arduino";
105 repo = "Arduino";
106 rev = version;
107 sha256 = "sha256-I+PvfGc5F8H/NJOGRa18z7dKyKcO8I8Cg7Tj5yxkYAQ=";
108 };
109
110 teensyduino_version = "156";
111 teensyduino_src = fetchurl {
112 url = "https://www.pjrc.com/teensy/td_${teensyduino_version}/TeensyduinoInstall.${teensy_architecture}";
113 sha256 =
114 {
115 linux64 = "sha256-4DbhmmYrx+rCBpDrYFaC0A88Qv9UEeNlQAkFi3zAstk=";
116 linux32 = "sha256-DlRPOtDxmMPv2Qzhib7vNZdKNZCxmm9YmVNnwUKXK/E=";
117 linuxarm = "sha256-d+DbpER/4lFPcPDFeMG5f3WaUGn8pFchdIDo7Hm0XWs=";
118 linuxaarch64 = "sha256-8keQzhWq7QlAGIbfHEe3lfxpJleMMvBORuPaNrLmM6Y=";
119 }
120 .${teensy_architecture} or (throw "No arduino binaries for ${teensy_architecture}");
121 };
122 # Used because teensyduino requires jars be a specific size
123 arduino_dist_src = fetchurl {
124 url = "https://downloads.arduino.cc/arduino-${version}-${teensy_architecture}.tar.xz";
125 sha256 =
126 {
127 linux64 = "sha256-62i93B0cASC+L8oTUKA+40Uxzzf1GEeyEhC25wVFvJs=";
128 linux32 = "sha256-wSxtx3BqXMQCeWQDK8PHkWLlQqQM1Csao8bIk98FrFg=";
129 linuxarm = "sha256-lJ/R1ePq7YtDk3bvloFcn8jswrJH+L63tvH5QpTqfXs=";
130 linuxaarch64 = "sha256-gm8cDjLKNfpcaeO7fw6Kyv1TnWV/ZmH4u++nun9X6jo=";
131 }
132 .${teensy_architecture} or (throw "No arduino binaries for ${teensy_architecture}");
133 };
134
135 # the glib setup hook will populate GSETTINGS_SCHEMAS_PATH,
136 # wrapGAppHooks (among other things) adds it to XDG_DATA_DIRS
137 # so 'save as...' works:
138 nativeBuildInputs = [
139 glib
140 stripJavaArchivesHook
141 wrapGAppsHook3
142 unzip
143 ];
144 buildInputs = [
145 jdk
146 ant
147 libusb-compat-0_1
148 libusb1
149 zlib
150 ncurses5
151 readline
152 ]
153 ++ lib.optionals withTeensyduino [ upx ];
154 downloadSrcList = builtins.attrValues externalDownloads;
155 downloadDstList = builtins.attrNames externalDownloads;
156
157 buildPhase = ''
158 # Copy pre-downloaded files to proper locations
159 download_src=($downloadSrcList)
160 download_dst=($downloadDstList)
161 while [[ "''${#download_src[@]}" -ne 0 ]]; do
162 file_src=''${download_src[0]}
163 file_dst=''${download_dst[0]}
164 mkdir -p $(dirname $file_dst)
165 download_src=(''${download_src[@]:1})
166 download_dst=(''${download_dst[@]:1})
167 cp -v $file_src $file_dst
168 done
169
170 # Deliberately break build.xml's download statement in order to cause
171 # an error if anything needed is missing from download.nix.
172 substituteInPlace build/build.xml \
173 --replace 'ignoreerrors="true"' 'ignoreerrors="false"'
174
175 cd ./arduino-core && ant
176 cd ../build && ant
177 cd ..
178 '';
179
180 # This will be patched into `arduino` wrapper script
181 # Java loads gtk dynamically, so we need to provide it using LD_LIBRARY_PATH
182 dynamicLibraryPath = lib.makeLibraryPath [ gtk3 ];
183 javaPath = lib.makeBinPath [ jdk ];
184
185 # Everything else will be patched into rpath
186 rpath = lib.makeLibraryPath [
187 zlib
188 libusb-compat-0_1
189 libusb1
190 readline
191 ncurses5
192 stdenv.cc.cc
193 ];
194
195 installPhase = ''
196 mkdir -p $out/share/arduino
197 cp -r ./build/linux/work/* "$out/share/arduino/"
198 echo -n ${version} > $out/share/arduino/lib/version.txt
199
200 ${lib.optionalString withGui ''
201 mkdir -p $out/bin
202 substituteInPlace $out/share/arduino/arduino \
203 --replace "JAVA=java" "JAVA=$javaPath/java" \
204 --replace "LD_LIBRARY_PATH=" "LD_LIBRARY_PATH=$dynamicLibraryPath:"
205 ln -sr "$out/share/arduino/arduino" "$out/bin/arduino"
206
207 cp -r build/shared/icons $out/share/arduino
208 mkdir -p $out/share/applications
209 cp build/linux/dist/desktop.template $out/share/applications/arduino.desktop
210 substituteInPlace $out/share/applications/arduino.desktop \
211 --replace '<BINARY_LOCATION>' "$out/bin/arduino" \
212 --replace '<ICON_NAME>' "$out/share/arduino/icons/128x128/apps/arduino.png"
213 ''}
214
215 ${lib.optionalString withTeensyduino ''
216 # Back up the original jars
217 mv $out/share/arduino/lib/arduino-core.jar $out/share/arduino/lib/arduino-core.jar.bak
218 mv $out/share/arduino/lib/pde.jar $out/share/arduino/lib/pde.jar.bak
219 # Extract jars from the arduino distributable package
220 mkdir arduino_dist
221 cd arduino_dist
222 tar xfJ ${arduino_dist_src} arduino-${version}/lib/arduino-core.jar arduino-${version}/lib/pde.jar
223 cd ..
224 # Replace the built jars with the official arduino jars
225 mv arduino_dist/arduino-${version}/lib/{arduino-core,pde}.jar $out/share/arduino/lib/
226 # Delete the directory now that the jars are copied out
227 rm -r arduino_dist
228 # Extract and patch the Teensyduino installer
229 cp ${teensyduino_src} ./TeensyduinoInstall.${teensy_architecture}
230 chmod +w ./TeensyduinoInstall.${teensy_architecture}
231 upx -d ./TeensyduinoInstall.${teensy_architecture}
232 patchelf --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \
233 --set-rpath "${teensy_libpath}" \
234 ./TeensyduinoInstall.${teensy_architecture}
235 chmod +x ./TeensyduinoInstall.${teensy_architecture}
236 ./TeensyduinoInstall.${teensy_architecture} --dir=$out/share/arduino
237 # Check for successful installation
238 [ -d $out/share/arduino/hardware/teensy ] || exit 1
239 # After the install, copy the built jars back
240 mv $out/share/arduino/lib/arduino-core.jar.bak $out/share/arduino/lib/arduino-core.jar
241 mv $out/share/arduino/lib/pde.jar.bak $out/share/arduino/lib/pde.jar
242 ''}
243 '';
244
245 # So we don't accidentally mess with firmware files
246 dontStrip = true;
247 dontPatchELF = true;
248
249 preFixup = ''
250 for file in $(find $out -type f \( -perm /0111 -o -name \*.so\* \) ); do
251 patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$file" || true
252 patchelf --set-rpath ${rpath}:$out/lib $file || true
253 done
254
255 ${lib.concatMapStringsSep "\n" (
256 { jar, file }:
257 ''
258 jar xvf $out/${jar} ${file}
259 patchelf --set-rpath $rpath ${file}
260 jar uvf $out/${jar} ${file}
261 rm -f ${file}
262 ''
263 ) patchelfInJars}
264
265 # avrdude_bin is linked against libtinfo.so.5
266 mkdir $out/lib/
267 ln -s ${lib.makeLibraryPath [ ncurses5 ]}/libtinfo.so.5 $out/lib/libtinfo.so.5
268
269 ${lib.optionalString withTeensyduino ''
270 # Patch the Teensy loader binary
271 patchelf --debug \
272 --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \
273 --set-rpath "${teensy_libpath}" \
274 $out/share/arduino/hardware/tools/teensy{,_ports,_reboot,_restart,_serialmon}
275 ''}
276 '';
277
278 meta = with lib; {
279 description = "Open-source electronics prototyping platform";
280 mainProgram = "arduino";
281 homepage = "https://www.arduino.cc/";
282 license = if withTeensyduino then licenses.unfreeRedistributable else licenses.gpl2;
283 sourceProvenance = with sourceTypes; [
284 binaryBytecode
285 binaryNativeCode
286 ];
287 platforms = platforms.linux;
288 maintainers = with maintainers; [
289 antono
290 auntie
291 robberer
292 bjornfor
293 bergey
294 ];
295 };
296}