diff --git a/packages/linuxcnc-with-ethercat/default.nix b/packages/linuxcnc-with-ethercat/default.nix new file mode 100644 index 0000000..36966c1 --- /dev/null +++ b/packages/linuxcnc-with-ethercat/default.nix @@ -0,0 +1,122 @@ +{ lib, stdenv, autoreconfHook, wrapGAppsHook, qt5, makeWrapper, fetchFromGitHub, libtool, pkgconfig, + readline_5, ncurses, libtirpc, systemd, libmodbus, libusb, glib, gtk2, gtk3, procps, kmod, sysctl, + util-linux, psmisc, intltool, tcl, tk, bwidget, tkimg, tclx, tkblt, pango, cairo, boost, espeak, gst_all_1, + python3Full, yapps, gobject-introspection, libGLU, xorg, libepoxy, hicolor-icon-theme, glxinfo, bash, + hal-cia402, linuxcnc-ethercat +}: +let + pythonPkg = (python3Full.withPackages (ps: [ + yapps + ps.pyopengl + ps.pygobject3 + ps.pycairo + ps.boost + ps.numpy + ps.pyqtwebengine + ps.pyqt5 + ps.opencv4 + ps.gst-python + ps.xlib + ps.qscintilla + ])); + boost_python = (boost.override { enablePython = true; python = pythonPkg; }); +in +stdenv.mkDerivation rec { + hardeningDisable = [ "all" ]; + enableParallelBuilding = true; + pname = "linuxcnc"; + version = "2.9-git"; + name = "${pname}-${version}"; + + src = fetchFromGitHub { + owner = "LinuxCNC"; + repo = "linuxcnc"; + rev = "f77537cd4d4dc6191d4bb981e0e1c9d897039fc6"; + sha256 = "05kuTx2J7wdrcoUQ8Tengb0ohXAeGjZV9g9XriWgQL4="; + }; + + nativeBuildInputs = [ + autoreconfHook + makeWrapper + wrapGAppsHook + qt5.wrapQtAppsHook + gobject-introspection + ]; + + dontWrapGApps = true; + dontWrapQtApps = true; + + buildInputs = [ + libtool pkgconfig libtirpc systemd libmodbus libusb glib gtk2 gtk3 procps kmod sysctl util-linux + psmisc intltool tcl tk bwidget tkimg tclx tkblt pango cairo pythonPkg.pkgs.pygobject3 gobject-introspection + boost_python pythonPkg.pkgs.boost pythonPkg qt5.qtbase espeak gst_all_1.gstreamer + ncurses readline_5 libGLU xorg.libXmu libepoxy hicolor-icon-theme glxinfo + hal-cia402 linuxcnc-ethercat + ]; + + preAutoreconf = '' + # cd into ./src here instead of setting sourceRoot as the build process uses the original sourceRoot + cd ./src + + # make halcmd search for setuid apps on PATH, to find setuid wrappers + substituteInPlace hal/utils/halcmd_commands.c --replace 'EMC2_BIN_DIR "/' '"' + ''; + + patches = [ + ./fix_make.patch # Some lines don't respect --prefix + ./pncconf_paths.patch # Corrects a search path in pncconf + ./rtapi_app_setuid.patch # Remove hard coded checks for setuid from rtapi_app + ]; + + postAutoreconf = '' + # We need -lncurses for -lreadline, but the configure script discards the env set by NixOS before checking for -lreadline + substituteInPlace configure --replace '-lreadline' '-lreadline -lncurses' + + substituteInPlace emc/usr_intf/pncconf/private_data.py --replace '/usr/share/themes' '${gtk3}/share/themes' + substituteInPlace emc/usr_intf/pncconf/private_data.py --replace 'self.FIRMDIR = "/lib/firmware/hm2/"' 'self.FIRMDIR = os.environ.get("HM2_FIRMWARE_DIR", "${placeholder "out"}/firmware/hm2")' + + substituteInPlace hal/drivers/mesa-hostmot2/hm2_eth.c --replace '/sbin/iptables' '/run/current-system/sw/bin/iptables' + substituteInPlace hal/drivers/mesa-hostmot2/hm2_eth.c --replace '/sbin/sysctl' '${sysctl}/bin/sysctl' + substituteInPlace hal/drivers/mesa-hostmot2/hm2_rpspi.c --replace '/sbin/modprobe' '${kmod}/bin/modprobe' + substituteInPlace hal/drivers/mesa-hostmot2/hm2_rpspi.c --replace '/sbin/rmmod' '${kmod}/bin/rmmod' + substituteInPlace module_helper/module_helper.c --replace '/sbin/insmod' '${kmod}/bin/insmod' + substituteInPlace module_helper/module_helper.c --replace '/sbin/rmmod' '${kmod}/bin/rmmod' + ''; + + configureFlags = [ + "--with-tclConfig=${tcl}/lib/tclConfig.sh" + "--with-tkConfig=${tk}/lib/tkConfig.sh" + "--with-boost-libdir=${boost_python}/lib" + "--with-boost-python=boost_python3" + "--with-locale-dir=$(out)/locale" + "--exec-prefix=${placeholder "out"}" + ]; + + preInstall = '' + # Stop the Makefile attempting to set ownship+perms, it fails on NixOS + sed -i -e 's/chown.*//' -e 's/-o root//g' -e 's/-m [0-9]\+//g' Makefile + ''; + + installFlags = [ "SITEPY=${placeholder "out"}/${pythonPkg.sitePackages}" ]; + + postInstall = '' + mkdir -p "$out/firmware/hm2" + ''; + + # Binaries listed here are renamed to ${filename}-nosetuid, to be targetted by setuid wrappers + setuidApps = [ "rtapi_app" "linuxcnc_module_helper" "pci_write" "pci_read" ]; + + preFixup = '' + for prog in $(find $out/bin -type f ! \( ${lib.concatMapStringsSep " -o " (f: "-name " + f + " ") setuidApps} \)); do + wrapProgram "$prog" \ + --prefix PATH : ${lib.makeBinPath [tk glxinfo]} \ + --prefix TCLLIBPATH ' ' "$out/lib/tcltk/linuxcnc ${tk}/lib ${tcl}/lib ${tclx}/lib ${tkblt}/lib ${tkimg}/lib ${bwidget}/lib/bwidget${bwidget.version}" \ + --prefix PYTHONPATH : "${pythonPkg}/${pythonPkg.sitePackages}:$out/${pythonPkg.sitePackages}" \ + "''${gappsWrapperArgs[@]}" \ + "''${qtWrapperArgs[@]}" + done + for prog in $(find $out/bin -type f \( ${lib.concatMapStringsSep " -o " (f: "-name " + f + " ") setuidApps} \)); do + mv "$prog" "$prog-nosetuid" + done + ''; +} diff --git a/packages/linuxcnc-with-ethercat/fix_make.patch b/packages/linuxcnc-with-ethercat/fix_make.patch new file mode 100644 index 0000000..f8436fc --- /dev/null +++ b/packages/linuxcnc-with-ethercat/fix_make.patch @@ -0,0 +1,25 @@ +diff --git a/src/Makefile b/src/Makefile +index 5bde17598d..856af19e08 100644 +--- a/src/Makefile ++++ b/src/Makefile +@@ -616,9 +616,9 @@ install: install-kernel-dep install-kernel-indep + install-dirs: + $(DIR) $(DESTDIR)$(EMC2_RTLIB_DIR) \ + $(DESTDIR)$(sysconfdir)/linuxcnc $(DESTDIR)$(bindir) $(DESTDIR)$(libdir) \ +- $(DESTDIR)/lib/linuxcnc $(DESTDIR)$(includedir)/linuxcnc \ ++ $(DESTDIR)$(prefix)/lib/linuxcnc $(DESTDIR)$(includedir)/linuxcnc \ + $(DESTDIR)$(docsdir) $(DESTDIR)$(ncfilesdir) \ +- $(DESTDIR)/etc/X11/app-defaults $(DESTDIR)$(tcldir)/bin \ ++ $(DESTDIR)$(prefix)/etc/X11/app-defaults $(DESTDIR)$(tcldir)/bin \ + $(DESTDIR)$(tcldir)/scripts \ + $(DESTDIR)$(mandir)/man1 \ + $(DESTDIR)$(mandir)/man3 \ +@@ -686,7 +686,7 @@ install-kernel-indep: install-dirs + $(FILE) $(DOCS_HELP) $(DESTDIR)$(docsdir) + $(TREE) $(NC_FILES) $(DESTDIR)$(ncfilesdir) + $(EXE) ../nc_files/M101 $(DESTDIR)$(ncfilesdir) +- $(FILE) ../tcl/TkLinuxCNC $(DESTDIR)/etc/X11/app-defaults ++ $(FILE) ../tcl/TkLinuxCNC $(DESTDIR)$(prefix)/etc/X11/app-defaults + $(FILE) Makefile.modinc $(DESTDIR)$(datadir)/linuxcnc + $(EXE) $(TCL) $(DESTDIR)$(tcldir) + $(FILE) ../tcl/hal.so $(DESTDIR)$(tcldir) diff --git a/packages/linuxcnc-with-ethercat/pncconf_paths.patch b/packages/linuxcnc-with-ethercat/pncconf_paths.patch new file mode 100644 index 0000000..4ea11e4 --- /dev/null +++ b/packages/linuxcnc-with-ethercat/pncconf_paths.patch @@ -0,0 +1,13 @@ +diff --git a/src/emc/usr_intf/pncconf/private_data.py b/src/emc/usr_intf/pncconf/private_data.py +index 7bb8127ea4..88e99934ca 100644 +--- a/src/emc/usr_intf/pncconf/private_data.py ++++ b/src/emc/usr_intf/pncconf/private_data.py +@@ -74,7 +74,7 @@ class Private_Data: + self._METRIC = 1 + + self.DATADIR = linuxcnc.SHARE + "/linuxcnc/pncconf" +- self.WIZARD = os.path.join(self.DATADIR, "linuxcnc-wizard.gif") ++ self.WIZARD = linuxcnc.SHARE + "/linuxcnc/linuxcnc-wizard.gif" + if not os.path.isfile(self.WIZARD): + self.WIZARD = os.path.join("/etc/linuxcnc/linuxcnc-wizard.gif") + if not os.path.isfile(self.WIZARD): diff --git a/packages/linuxcnc-with-ethercat/rtapi_app_setuid.patch b/packages/linuxcnc-with-ethercat/rtapi_app_setuid.patch new file mode 100644 index 0000000..1b62109 --- /dev/null +++ b/packages/linuxcnc-with-ethercat/rtapi_app_setuid.patch @@ -0,0 +1,19 @@ +diff --git a/src/rtapi/uspace_common.h b/src/rtapi/uspace_common.h +index 8dde420142..f9ff6f0cb2 100644 +--- a/src/rtapi/uspace_common.h ++++ b/src/rtapi/uspace_common.h +@@ -381,9 +381,11 @@ static int detect_env_override() { + + static int detect_realtime() { + struct stat st; +- if ((stat(EMC2_BIN_DIR "/rtapi_app", &st) < 0) +- || st.st_uid != 0 || !(st.st_mode & S_ISUID)) +- return 0; ++ //setuid programs are forbidden from the nix store, a wrapper outside of the store is created instead ++ //this check fails under those circumstances, disable it and hope for the best ++ /* if ((stat(EMC2_BIN_DIR "/rtapi_app", &st) < 0) */ ++ /* || st.st_uid != 0 || !(st.st_mode & S_ISUID)) */ ++ /* return 0; */ + return detect_env_override() || detect_preempt_rt() || detect_rtai() || detect_xenomai(); + } +