emcrisostomo / fswatch

A cross-platform file change monitor with multiple backends: Apple OS X File System Events, *BSD kqueue, Solaris/Illumos File Events Notification, Linux inotify, Microsoft Windows and a stat()-based backend.
https://emcrisostomo.github.io/fswatch/
GNU General Public License v3.0
5.06k stars 330 forks source link

Building with MinGW (not Cygwin) #214

Open brechtsanders opened 6 years ago

brechtsanders commented 6 years ago

Hi, I had problems building fswatch with MinGW-w64 (both 32 and 64 bit versions), but in the end I was able to build a working version of fswatch by doing the following:

This gives me a working fswatch binary and both static and shared libraries for native Windows. I tested it and it works with windows_monitor, but not with poll_monitor, which is good enough for me.

I'm including my shell commands below (made for 1.12.0, but also working with 1.13.0). Hopefully this helps you in making a native Windows port.

Regards Brecht Sanders

# fix missing S_ISLNK in libfswatch/src/libfswatch/c++/poll_monitor.cpp
patch -ulbf libfswatch/src/libfswatch/c++/poll_monitor.cpp << EOF
@@ -131,2 +131,3 @@

+#ifndef _WIN32
     if (follow_symlinks && S_ISLNK(fd_stat.st_mode))
@@ -139,2 +140,3 @@
     }
+#endif

EOF
# fix missing realpath/lstat in libfswatch/src/libfswatch/c++/path_utils.cpp
patch -ulbf libfswatch/src/libfswatch/c++/path_utils.cpp << EOF
@@ -59,2 +59,5 @@
   {
+#ifdef _WIN32
+    return false;
+#else
     char *real_path = realpath(path.c_str(), nullptr);
@@ -66,2 +69,3 @@
     return ret;
+#endif
   }
@@ -82,2 +86,6 @@
   {
+#ifdef _WIN32
+    fsw_logf_perror(_("Cannot lstat %s (not implemented on Windows)"), path.c_str());
+    return false;
+#else
     if (lstat(path.c_str(), &fd_stat) != 0)
@@ -90,2 +98,3 @@
     return true;
+#endif
   }
EOF
# fix missing sigaction/realpath in fswatch/src/fswatch.cpp
patch -ulbf fswatch/src/fswatch.cpp << EOF
@@ -36,2 +36,5 @@
 #include "libfswatch/c++/libfswatch_exception.hpp"
+#ifdef _WIN32
+#define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
+#endif

@@ -297,2 +300,3 @@
 {
+#ifndef _WIN32
   struct sigaction action;
@@ -328,2 +332,3 @@
   }
+#endif
 }
EOF
# fix libfswatch/src/libfswatch/c++/windows/win_paths.cpp
patch -ulbf libfswatch/src/libfswatch/c++/windows/win_paths.cpp << EOF
@@ -16,3 +16,7 @@
 #include "win_paths.hpp"
+#ifdef  __CYGWIN__
 #include <sys/cygwin.h>
+#else
+#include <windows.h>
+#endif
 #include "../libfswatch_exception.hpp"
@@ -28,2 +32,3 @@
     {
+#ifdef  __CYGWIN__
       void * raw_path = cygwin_create_path(CCP_POSIX_TO_WIN_W, path.c_str());
@@ -36,2 +41,11 @@
       return win_path;
+#else
+      int pathlen = (int)path.length() + 1;
+      int buflen = MultiByteToWideChar(CP_ACP, 0, path.c_str(), pathlen, 0, 0);
+      wchar_t* buf = new wchar_t[buflen];
+      MultiByteToWideChar(CP_ACP, 0, path.c_str(), pathlen, buf, buflen);
+      std::wstring result(buf);
+      delete[] buf;
+      return result;
+#endif
     }
@@ -40,2 +54,3 @@
     {
+#ifdef  __CYGWIN__
       void * raw_path = cygwin_create_path(CCP_WIN_W_TO_POSIX, path.c_str());
@@ -48,2 +63,11 @@
       return posix_path;
+#else
+      int pathlen = (int)path.length() + 1;
+      int buflen = WideCharToMultiByte(CP_ACP, 0, path.c_str(), pathlen, 0, 0, 0, 0);
+      char* buf = new char[buflen];
+      WideCharToMultiByte(CP_ACP, 0, path.c_str(), pathlen, buf, buflen, 0, 0);
+      std::string result(buf);
+      delete[] buf;
+      return result;
+#endif
     }
EOF
# fix missing file
touch README.illumos
# remove detection of realpath/regcomp/select
mv libfswatch/configure.ac libfswatch/configure.ac.bak &&
grep -v "realpath\|regcomp\|select" libfswatch/configure.ac.bak > libfswatch/configure.ac
# remove detection of realpath
mv configure.ac configure.ac.bak2 &&
grep -v "realpath" configure.ac.bak2 > configure.ac
# remove detection of realpath
mv configure.ac configure.ac.bak3 &&
grep -v "The select function cannot be found." configure.ac.bak3 > configure.ac
# fix for building windows_monitor
mv libfswatch/src/libfswatch/Makefile.am libfswatch/src/libfswatch/Makefile.am.bak &&
sed -e "s/USE_CYGWIN/USE_WINDOWS/" libfswatch/src/libfswatch/Makefile.am.bak > libfswatch/src/libfswatch/Makefile.am
echo configure &&
( autoreconf -f -i -I m4 -I $MINGWPREFIX/share/aclocal || (
 touch README libfswatch/README libfswatch/README config/ltmain.sh config.h.in &&
 automake -a -f -c &&
 autoreconf -f -i -I m4 -I $MINGWPREFIX/share/aclocal
)) &&
./configure CFLAGS="-DHAVE_WINDOWS" CXXFLAGS="-DHAVE_WINDOWS" &&
 # fix building DLLs
 mv libtool libtool.bak &&
 sed -e "s/\(allow_undefined=\)yes/\1no/" libtool.bak > libtool &&
 echo build-install &&
 make install-strip &&
 echo Success
emcrisostomo commented 6 years ago

Hi @brechtsanders ,

Thank you so much for your contribution. Besides not being my primary platform, you've probably unblocked two independent lines of work: providing a MinGW-compatible version of fswatch by dropping the CygWin requirement, and resurrecting the realpath problem.

brechtsanders commented 6 years ago

Glad I could help. You may want to think about the stuff related to links though. My fix ignores links, but Windows does have links. However it doesn't have S_ISLNK() or lstat().

sergeevabc commented 5 years ago

No binary for Windows? Oh.

jordwalke commented 5 years ago

Thank you so much for sharing what you did to get this working. Can this be upstreamed?

brechtsanders commented 5 years ago

Absolutely!

ulrikstrid commented 5 years ago

@brechtsanders Thank you so much for this!

I tried this and it builds just fine, but I can't seem to get any output from the final binary. Not even --help or --version gives any output, doesn't even crash. Is this something you have seen as well? I have not tried the library yet I'm building version 1.13.0 if that matters, I could try with 1.12.0 if that should make any difference?

brechtsanders commented 5 years ago

@ulrikstrid I have successfully built and ran versions 1.13.0 and 1.14.0. Note that the dependancies must also work wor the application to run. In my latest build I see dependancies on the following DLLs:

In my case libiconv and libintl come from libiconv and gettext which I also built myself (including all of their dependancies). To know why your application doesn't do anything run it through gdb. Chances are gdb will tell you that it can't load some DLL...

ulrikstrid commented 5 years ago

I've also built libiconv and gettext. ~I see that I have this libintl-7.dll instead of a libintl-8.dll could that be it?~. I upgraded to latest gettext and now have the libintl-8.dlland it still doesn't work. I manged to get it to work in CI so there is some difference between my machine and CI it seems.

Thank you for taking the time to help me out @brechtsanders

brechtsanders commented 5 years ago

Have you tried running with GDB? It will tell you why it's exiting.