Hello!
I was looking at an extension to get gestures for Gnome on x11, and it a program called touchegg. I saw that this program was actually packaged for Nix, but I could not get it to work. This led me to believe that a newer version of touchegg was needed, and since it had no maintainer, I decided to try and create a derivation for it. (If anyone has gotten this to work I would also be interested in hearing how!)
I took some inspiration from the current touchegg derivation and looked at the nix pills and some other random places, and this is what I currently have:
with (import <nixpkgs> {});
stdenv.mkDerivation rec {
name = "touchegg";
pname = "${name}";
version = "2.0.8";
src = fetchurl {
url = "https://github.com/JoseExposito/${pname}/archive/${version}.tar.gz";
sha256 = "6905963bec8fc6d73c39780f5ae4648dc89fda052449f267b4b5bfbadb218ce0";
};
nativeBuildInputs = [
gcc
pkg-config
gdb
cmake
libudev
libinput
pugixml
cairo
xorg.libX11
xorg.libXtst
xorg.libXrandr
xorg.libXi
xorg.libXdmcp
xorg.libpthreadstubs
xorg.libxcb
gtk3-x11
pcre
mount
];
configurePhase = ''
cmake -DCMAKE_BUILD_TYPE=Release .
'';
buildPhase = ''
make -j$(nproc)
'';
installPhase = ''
mkdir -p $out/bin
mv touchegg $out/bin/touchegg
mkdir -p $out/usr/share/touchegg
mv installation/touchegg.conf $out/usr/share/touchegg/touchegg.conf
'';
}
When I try to run the program for the result link, I get the following error
File /usr/share/touchegg/touchegg.conf not found.
My hope was that since i copied the touchegg.conf over in the last two lines of the install phase it would be able to find it, but as is evident, it did not. I searched around for “wrapping” and so on, but I think I fundamentally do not know what I am trying to do.
So, my question is: what is the right way to fix this error? How should the environment be emulated?
Any general pointers to improving this derivation would also be helpful! (And in particular if anything is needed to make this acceptable for upstream nixpkgs)
Thanks!
First you will want to pass -DCMAKE_INSTALL_PREFIX=$out
so that CMake knows it should install the project to $out
instead of /usr
. Also cmake
package in Nixpkgs has a setup hook that will run cmake
with correct flaks by default, if configurePhase
is not overridden. (Same for buildPhase
and installPhase
).
Unfortunately, the project does not respect the GNUInstallDirs
variables so no matter what you do, it will try to install stuff to /usr
and load it from there. To make it work, you will need to patch its source code.
- Delete this line
- Change
/lib
in this line to ${CMAKE_INSTALL_LIBDIR}
-
here
/etc
→ ${CMAKE_INSTALL_SYSCONFDIR}
- Populate this path in CMakeLists.txt, e.g. using
configure_file
– this is also the reason your program cannot find the config file. It looks into /usr
but Nix never installs to /usr
, only to Nix store.
See also GitHub - jtojnar/cmake-snips: Portability problems I frequently encounter in projects using CMake for more information about how to make CMake projects portable.
You can do all of the changes by just replacing /usr
for $out
and /etc
or /lib
for $out/etc
or $out/lib
using sed
/substituteInPlace
calls in postPatch
/preConfigure
in your Nix packages but it is preferable to make the project properly portable by creating a patch against the touchegg repository and opening a pull request upstream.
3 Likes
Thank you very much!
I started a fork and am trying to implement your suggested changes. The last one is giving me some troubles, I am not too experienced with C++ and CMake. As I understand it
- remove src/utils/paths.cpp
- Create a file like
paths.cpp.in
in the cmake
directory
- add the following (or something like that) to that file
#cmakedefine CONFIG_PATH_CUSTOM
#cmakedefine CONFIG_PATH "@CONFIG_PATH@"
- Replace the line you linked with
return std::filesystem::path{CONFIG_PATH};
- add the following to CMakeList.txt
option(CONFIG_PATH_CUSTOM "Enable custom config path" ON)
if(CONFIG_PATH_CUSTOM)
set(CONFIG_PATH NEW_CONFIG_PATH)
else()
set(CONFIG_PATH "/usr/share/touchegg/touchegg.conf")
endif()
configure_file(${PROJECT_SOURCE_DIR}/cmake/paths.cpp.in ${PROJECT_SOURCE_DIR}/src/utils/paths.cpp @ONLY)
include_directories(${PROJECT_SOURCE_DIR}/src/utils/)
Does that look right? How do I set the CONFIG_PATH_CUSTOM
and CONFIG_PATH
then?
Thanks!
EDIT: My fork is here https://github.com/Hvassaa/touchegg
Okay I once again tried with all the changes, but I am now getting some C++ errors. Could this be related to a misconfiguration on my part? Thanks again
Sorry, this method would probably need more changes to the build file (the CMake script collects cpp files to ${SOURCE_FILES}
so we would need to add it there manually). Also writing to the source directory is not very kosher.
Since this is a code, it might be actually easier to use preprocessor definitions:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3128219..ab3b3e7 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -70,6 +70,11 @@ endif()
# https://cmake.org/cmake/help/v3.12/module/CPack.html
# https://cmake.org/cmake/help/v3.7/module/CPackRPM.html
include(GNUInstallDirs)
+
+set(SHARED_CONFIG_PATH "${CMAKE_INSTALL_FULL_DATAROOTDIR}/touchegg/touchegg.conf")
+target_compile_definitions(touchegg PUBLIC SHARED_CONFIG_PATH=\"${SHARED_CONFIG_PATH}\")
+
+
install(FILES ${PROJECT_SOURCE_DIR}/installation/touchegg.conf DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/touchegg) # /usr/share/touchegg/touchegg.conf
install(FILES ${PROJECT_SOURCE_DIR}/installation/touchegg.service DESTINATION ${CMAKE_INSTALL_LIBDIR}/systemd/system)
install(FILES ${PROJECT_SOURCE_DIR}/installation/touchegg.desktop DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/xdg/autostart)
@@ -106,11 +111,4 @@ list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/etc")
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/etc/xdg")
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/etc/xdg/autostart")
-option(CONFIG_PATH_CUSTOM "Enable custom config path" ON)
-if(CONFIG_PATH_CUSTOM)
- set(CONFIG_PATH NEW_CONFIG_PATH)
-endif()
-configure_file(${PROJECT_SOURCE_DIR}/cmake/paths.cpp.in ${PROJECT_SOURCE_DIR}/src/utils/paths.cpp @ONLY)
-include_directories(${PROJECT_SOURCE_DIR}/src/utils/)
-
include(CPack)
diff --git a/default.nix b/default.nix
index 4ae4697..c0ccbaa 100644
--- a/default.nix
+++ b/default.nix
@@ -15,7 +15,7 @@ stdenv.mkDerivation rec {
pkg-config
gdb
cmake
- libudev
+ systemd
libinput
pugixml
cairo
@@ -31,15 +31,6 @@ stdenv.mkDerivation rec {
mount
];
- preConfigure = ''
- CONFIG_PATH_CUSTOM=1
- CONFIG_PATH="$out/usr/share/touchegg/touchegg.conf"
- '';
-
- configurePhase = ''
- cmake -DCMAKE_INSTALL_PREFIX=$out -DCMAKE_BUILD_TYPE=Release .
- '';
-
# buildPhase = ''
# make -j$(nproc)
# '';
diff --git a/src/utils/paths.cpp b/src/utils/paths.cpp
index 13bab15..470ef7f 100644
--- a/src/utils/paths.cpp
+++ b/src/utils/paths.cpp
@@ -25,9 +25,6 @@
#include <stdexcept>
-#define CONFIG_PATH_CUSTOM
-#define CONFIG_PATH "NEW_CONFIG_PATH"
-
std::filesystem::path Paths::getHomePath() {
// $HOME should be checked first
const char *homeEnvVar = getenv("HOME");
@@ -71,7 +68,7 @@ std::filesystem::path Paths::getUserLockFilePath() {
}
std::filesystem::path Paths::getSystemConfigFilePath() {
- return std::filesystem::path{CONFIG_PATH};
+ return std::filesystem::path{SHARED_CONFIG_PATH};
}
void Paths::createUserConfigDir() {
1 Like
Thanks, I really appreciate the help. This CMake stuff is magic to me!
With your changes, it is now building.
When the binary is run as result/bin/touchegg
it comlpains about not being able to connect to a daemon.
When I run result/bin/touchegg --daemon
it says it should be run by systemd or $USER should be in the input
group. So, after I added myself to the input
group, it actually worked, with the extension and everything! Brilliant!
I guess it would be desirable for it to work with systemd. There is a systemd unit at result/lib/systemd/system/touchegg.service
with the following content:
[Unit]
Description=Touchégg Daemon
Documentation=https://github.com/JoseExposito/touchegg/tree/master/installation#readme
[Service]
Type=simple
Group=input
ExecStart=/usr/bin/touchegg --daemon
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
How would you go about adding this service to NixOS?
And if you don’t mind, I also have another question. Do you think these changes would be suitable for upstream touchegg?
Thanks again! 
The service needs to be handled through the configure_file
treatment. There at least it should work just fine at least.
After you fix the path, you can add the package to systemd.packages
options in your configuration.nix
and that will enable it.
Yes, these changes are very suitable for upstream. I always encourage people to make compatibility changes upstreamable so that Nixpkgs is simpler and other distros can benefit from the changes too.
Great thanks! I think everything is working properly now.
I will try send a PR upstream to touchegg and then try to make a PR for nixpkgs after. Thank you so much for the help!