diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml
index 0ae0e90d..7a7526af 100644
--- a/.github/workflows/cmake.yml
+++ b/.github/workflows/cmake.yml
@@ -12,11 +12,10 @@ env:
jobs:
build:
- # The CMake configure and build commands are platform agnostic and should work equally
- # well on Windows or Mac. You can convert this to a matrix build if you need
- # cross-platform coverage.
- # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
- runs-on: ubuntu-latest
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [macos-latest, ubuntu-latest]
steps:
- uses: actions/checkout@v2
@@ -35,3 +34,55 @@ jobs:
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest -C ${{env.BUILD_TYPE}}
+
+ build_windows:
+ runs-on: windows-latest
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Cache vcpkg
+ uses: actions/cache@v2
+ env:
+ cache-name: cache-vcpkg-d8b9ae5
+ with:
+ path: ${{ github.workspace }}/vcpkg
+ key: ${{ runner.os }}-vcpkg-${{ env.cache-name }}
+ restore-keys: ${{ runner.os }}-vcpkg-${{ env.cache-name }}
+
+ - name: clone and bootstrap vcpkg
+ run: |
+ IF NOT EXIST "vcpkg" (
+ git clone --depth=360 https://github.com/microsoft/vcpkg
+ cd "vcpkg"
+ git reset --hard d8b9ae5
+ .\bootstrap-vcpkg.bat
+ )
+ shell: cmd
+
+ - name: Install dependencies with vcpkg
+ run: |
+ cd "%GITHUB_WORKSPACE%\vcpkg"
+ IF NOT EXIST "buildtrees\pthreads" (
+ .\vcpkg --version
+ .\vcpkg install --triplet "%RUNNER_ARCH%-%RUNNER_OS%" pthreads gettext
+ )
+ shell: cmd
+
+ - name: Configure CMake
+ # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
+ # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
+ run: |
+ cmake -B "%GITHUB_WORKSPACE%\build" -DCMAKE_BUILD_TYPE="%BUILD_TYPE%" -DVCPKG_TARGET_TRIPLET="%RUNNER_ARCH%-%RUNNER_OS%" -DCMAKE_TOOLCHAIN_FILE="vcpkg\scripts\buildsystems\vcpkg.cmake"
+ shell: cmd
+
+ - name: Build
+ # Build your program with the given configuration
+ run: cmake --build "%GITHUB_WORKSPACE%\build" --config "%BUILD_TYPE%"
+ shell: cmd
+
+ - name: Test
+ working-directory: ${{github.workspace}}/build
+ # Execute tests defined by the CMake configuration.
+ # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
+ run: ctest -C "%BUILD_TYPE%"
+ shell: cmd
diff --git a/.gitignore b/.gitignore
index 31f93245..9df993c7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,7 @@ fswatch_test
.libs
*.lo
*.o
-cmake-build-debug/
+*build*/
dist/
# Documentation
@@ -134,3 +134,4 @@ docker/debian-testing/Dockerfile
# Output files
man/fswatch.7
+*_export.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 80fd9041..29a7e60e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,13 +14,13 @@
# this program. If not, see .
#
cmake_minimum_required(VERSION 3.8)
-project(fswatch VERSION 1.16.0 LANGUAGES C CXX)
+project(fs_watch VERSION 1.17.0 LANGUAGES C CXX)
#@formatter:off
-set(PACKAGE "${PROJECT_NAME}")
+set(PACKAGE "fswatch")
set(PACKAGE_NAME "${PACKAGE}")
set(PACKAGE_VERSION "${PROJECT_VERSION}-develop")
-set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
+set(PACKAGE_STRING "${PACKAGE} ${PACKAGE_VERSION}")
set(PACKAGE_AUTHOR "enrico.m.crisostomo@gmail.com")
set(PACKAGE_BUGREPORT "${PACKAGE_AUTHOR}")
set(PACKAGE_TARNAME "${PACKAGE}")
@@ -29,9 +29,18 @@ set(LOCALEDIR "${CMAKE_INSTALL_PREFIX}/share/locale" CACHE FILEPATH "loc
#@formatter:on
set(CMAKE_CXX_STANDARD 11)
+if (MSVC)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
+endif (MSVC)
+
+# control where the static and shared libraries are built so that on windows
+# we don't need to tinker with the path to run the executable
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
# Add option to choose between shared and static libraries
-option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
+option(BUILD_SHARED_LIBS "Build shared libraries" ON)
# include modules
include(FindGettext)
@@ -44,7 +53,10 @@ include(CheckCXXSymbolExists)
check_include_file_cxx(getopt.h HAVE_GETOPT_H)
if (HAVE_GETOPT_H)
- check_cxx_symbol_exists(getopt_long getopt.h HAVE_GETOPT_LONG)
+ check_cxx_symbol_exists(getopt_long "getopt.h" HAVE_GETOPT_LONG)
+else ()
+ set(HAVE_GETOPT_H 1)
+ set(HAVE_GETOPT_LONG 1)
endif (HAVE_GETOPT_H)
# If both gettext and libintl are found, define the USE_NLS variable to
@@ -60,17 +72,24 @@ if (USE_NLS)
set(LINGUAS en en@quot en@boldquot it es)
foreach (language ${LINGUAS})
- configure_file(${PROJECT_SOURCE_DIR}/po/${language}.po ${PROJECT_BINARY_DIR}/${language}.po COPYONLY)
+ configure_file("${PROJECT_SOURCE_DIR}/po/${language}.po" "${PROJECT_BINARY_DIR}/${language}.po" COPYONLY)
endforeach ()
- gettext_process_pot_file(po/${PACKAGE}.pot ALL INSTALL_DESTINATION share/locale LANGUAGES ${LINGUAS})
-endif ()
+ gettext_process_pot_file("po/${PACKAGE}.pot" ALL INSTALL_DESTINATION "${LOCALEDIR}" LANGUAGES ${LINGUAS})
+endif (USE_NLS)
# checks
check_cxx_symbol_exists(atexit cstdlib HAVE_ATEXIT)
check_cxx_symbol_exists(setlocale clocale HAVE_SETLOCALE)
check_cxx_symbol_exists(strtod cstdlib HAVE_STRTOD)
-add_subdirectory(libfswatch)
-add_subdirectory(fswatch/src)
-add_subdirectory(test/src)
+option(BUILD_FSWATCH "Build ${PROJECT_NAME}" ON)
+option(BUILD_TESTS "Build ${PROJECT_NAME} tests" ON)
+
+add_subdirectory("libfswatch")
+if (BUILD_FSWATCH)
+ add_subdirectory("fswatch/src")
+endif (BUILD_FSWATCH)
+if (BUILD_TESTS)
+ add_subdirectory("test/src")
+endif (BUILD_TESTS)
diff --git a/README.windows b/README.windows
index 4877073b..c9664a42 100644
--- a/README.windows
+++ b/README.windows
@@ -6,8 +6,9 @@ Introduction
This file describes the steps required to build fswatch on Windows. fswatch was
born as a POSIX application and the Windows monitor has been developed trying to
-reduce the dependencies on the Windows API at a minimum. To fulfill this goal,
-a dependency to Cygwin has been introduced.
+reduce the dependencies on the Windows API at a minimum.
+
+There are two variants to fulfill this goal: Cygwin and Microsoft Visual Studio.
Windows has historically provided multiple versions of the same API for single
byte and multibyte character sets. We have decided to only support the
@@ -15,6 +16,37 @@ multibyte API: the Windows monitor will thus not build on Windows system
supporting only the single-byte APIs. In this case, the only available monitor
on the Windows OS will be the poll monitor.
+Microsoft Visual Studio (MSVC)
+==============================
+
+The MSVC variant is configured through CMake and is fully native on Windows.
+
+The three dependencies to get it working are:
+
+ 0. CMake: https://cmake.org
+ 1. pthreads: https://sourceforge.net/projects/pthreads4w
+ 2. gettext: https://mlocati.github.io/articles/gettext-iconv-windows.html
+
+The pthreads and gettext dependencies are most easily acquirable through use
+of a package manager, like Microsoft's open-source cross-platform vcpkg
+
+ git clone --depth=1 "https://github.com/microsoft/vcpkg"
+ cd "vcpkg"
+ :: Replace "[dir]" in later command with this dir
+ .\bootstrap-vcpkg.bat
+ .\vcpkg install --triplet "x64-windows" "pthreads" "gettext"
+
+Then the project can be configured and compiled & built with:
+
+ cd
+ cmake -B "build" \
+ -DCMAKE_BUILD_TYPE="Debug" \
+ -DVCPKG_TARGET_TRIPLET="x64-windows" \
+ -DCMAKE_TOOLCHAIN_FILE="[dir]\vcpkg\scripts\buildsystems\vcpkg.cmake"
+ cmake --build "build" --config "Debug"
+
+[everything that follows is only applicable to Cygwin]
+
Cygwin
======
diff --git a/cmake/FindPthreads.cmake b/cmake/FindPthreads.cmake
new file mode 100644
index 00000000..b471ded9
--- /dev/null
+++ b/cmake/FindPthreads.cmake
@@ -0,0 +1,99 @@
+# From: https://github.com/healpy/cfitsio/blob/d02e7ce/FindPthreads.cmake
+# - Find the Pthreads library
+# This module searches for the Pthreads library (including the
+# pthreads-win32 port).
+#
+# This module defines these variables:
+#
+# PTHREADS_FOUND
+# True if the Pthreads library was found
+# PTHREADS_LIBRARY
+# The location of the Pthreads library
+# PTHREADS_INCLUDE_DIR
+# The include path of the Pthreads library
+# PTHREADS_DEFINITIONS
+# Preprocessor definitions to define
+#
+# This module responds to the PTHREADS_EXCEPTION_SCHEME
+# variable on Win32 to allow the user to control the
+# library linked against. The Pthreads-win32 port
+# provides the ability to link against a version of the
+# library with exception handling. IT IS NOT RECOMMENDED
+# THAT YOU USE THIS because most POSIX thread implementations
+# do not support stack unwinding.
+#
+# PTHREADS_EXCEPTION_SCHEME
+# C = no exceptions (default)
+# (NOTE: This is the default scheme on most POSIX thread
+# implementations and what you should probably be using)
+# CE = C++ Exception Handling
+# SE = Structure Exception Handling (MSVC only)
+#
+
+#
+# Define a default exception scheme to link against
+# and validate user choice.
+#
+IF(NOT DEFINED PTHREADS_EXCEPTION_SCHEME)
+ # Assign default if needed
+ SET(PTHREADS_EXCEPTION_SCHEME "C")
+ELSE(NOT DEFINED PTHREADS_EXCEPTION_SCHEME)
+ # Validate
+ IF(NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "C" AND
+ NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "CE" AND
+ NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "SE")
+
+ MESSAGE(FATAL_ERROR "See documentation for FindPthreads.cmake, only C, CE, and SE modes are allowed")
+
+ ENDIF(NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "C" AND
+ NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "CE" AND
+ NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "SE")
+
+ IF(NOT MSVC AND PTHREADS_EXCEPTION_SCHEME STREQUAL "SE")
+ MESSAGE(FATAL_ERROR "Structured Exception Handling is only allowed for MSVC")
+ ENDIF(NOT MSVC AND PTHREADS_EXCEPTION_SCHEME STREQUAL "SE")
+
+ENDIF(NOT DEFINED PTHREADS_EXCEPTION_SCHEME)
+
+#
+# Find the header file
+#
+FIND_PATH(PTHREADS_INCLUDE_DIR pthread.h)
+
+#
+# Find the library
+#
+SET(names)
+IF(MSVC)
+ SET(names
+ pthreadV${PTHREADS_EXCEPTION_SCHEME}2
+ pthread
+ )
+ELSEIF(MINGW)
+ SET(names
+ pthreadG${PTHREADS_EXCEPTION_SCHEME}2
+ pthread
+ )
+ELSE(MSVC) # Unix / Cygwin / Apple
+ SET(names pthread)
+ENDIF(MSVC)
+
+FIND_LIBRARY(PTHREADS_LIBRARY ${names}
+ DOC "The Portable Threads Library")
+
+IF(PTHREADS_INCLUDE_DIR AND PTHREADS_LIBRARY)
+ SET(PTHREADS_FOUND true)
+ SET(PTHREADS_DEFINITIONS -DHAVE_PTHREAD_H)
+ SET(PTHREADS_INCLUDE_DIRS ${PTHREADS_INCLUDE_DIR})
+ SET(PTHREADS_LIBRARIES ${PTHREADS_LIBRARY})
+ENDIF(PTHREADS_INCLUDE_DIR AND PTHREADS_LIBRARY)
+
+IF(PTHREADS_FOUND)
+ IF(NOT PTHREADS_FIND_QUIETLY)
+ MESSAGE(STATUS "Found Pthreads: ${PTHREADS_LIBRARY}")
+ ENDIF(NOT PTHREADS_FIND_QUIETLY)
+ELSE(PTHREADS_FOUND)
+ IF(PTHREADS_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find the Pthreads Library")
+ ENDIF(PTHREADS_FIND_REQUIRED)
+ENDIF(PTHREADS_FOUND)
diff --git a/fswatch/src/CMakeLists.txt b/fswatch/src/CMakeLists.txt
index 73550ff9..2771cf9b 100644
--- a/fswatch/src/CMakeLists.txt
+++ b/fswatch/src/CMakeLists.txt
@@ -13,22 +13,41 @@
# You should have received a copy of the GNU General Public License along with
# this program. If not, see .
#
-set(FSWATCH_SRC_FILES
- fswatch.cpp
- fswatch.hpp
- gettext.h)
+set(EXEC_NAME "fswatch_bin")
+set(Header_Files "${PACKAGE}.hpp" "gettext.h")
+source_group("${PACKAGE} Header Files" FILES "${Header_Files}")
-add_executable(fswatch ${FSWATCH_SRC_FILES})
+set(Source_Files "${PACKAGE}.cpp")
+source_group("${PACKAGE} Source Files" FILES "${Source_Files}")
-# check for gettext and libintl
-if (USE_NLS)
- if (Intl_LIBRARIES)
- target_link_libraries(fswatch PRIVATE ${Intl_LIBRARIES})
- endif ()
-endif ()
+add_executable("${EXEC_NAME}" "${Header_Files}" "${Source_Files}")
+
+set_target_properties(
+ "${EXEC_NAME}"
+ PROPERTIES
+ LINKER_LANGUAGE
+ CXX
+)
+
+if (MSVC)
+ add_subdirectory("./windows")
+ target_link_libraries("${EXEC_NAME}" PRIVATE "getopt")
+endif (MSVC)
-target_include_directories(fswatch PUBLIC ../.. .)
-target_include_directories(fswatch PRIVATE ${PROJECT_BINARY_DIR})
-target_link_libraries(fswatch PUBLIC libfswatch)
+target_link_libraries("${EXEC_NAME}" PUBLIC "libfswatch")
-install(TARGETS fswatch DESTINATION bin)
+if (DEFINED VCPKG_LIBRARY_LINKAGE)
+ if (VCPKG_LIBRARY_LINKAGE STREQUAL "static")
+ set(BUILD_IS_STATIC "ON")
+ endif (VCPKG_LIBRARY_LINKAGE STREQUAL "static")
+elseif (BUILD_SHARED_LIBS)
+ set(BUILD_IS_STATIC "OFF")
+endif ()
+
+if (BUILD_IS_STATIC STREQUAL "ON")
+ set(bin_install_dir "${CURRENT_PACKAGES_DIR}")
+else ()
+ install(FILES ${Header_Files} DESTINATION "include")
+ set(bin_install_dir "bin")
+endif ()
+install(TARGETS "${EXEC_NAME}" DESTINATION "${bin_install_dir}")
diff --git a/fswatch/src/fswatch.cpp b/fswatch/src/fswatch.cpp
index ef962a78..3572bcc6 100644
--- a/fswatch/src/fswatch.cpp
+++ b/fswatch/src/fswatch.cpp
@@ -27,14 +27,14 @@
#include
#include
#include