Skip to content

Commit

Permalink
Open source Watchman C++ client library
Browse files Browse the repository at this point in the history
Summary:
Move the Watchman C++ client library out of HHVM and into the Watchman distribution proper and tidy up for open-sourcing.

The open-source build of Watchman should only include the client library by default only if Folly is available. Configure will hard fail if `--enable-cppclient` is used and folly is not present.

The open-source build of Watchman has now gained a hard dependency on libtool. This could kind of be softened but the dependency would still be present when running `autogen.sh` and this will probably spit out a bunch of whiney error messages with such a setup.

Reviewed By: wez

Differential Revision: D4292974

fbshipit-source-id: 589b5b25bb9487117e7a2b03d86c2e58b74d062f
  • Loading branch information
jbower-fb authored and facebook-github-bot committed Feb 1, 2017
1 parent ae2adb8 commit 3782208
Show file tree
Hide file tree
Showing 20 changed files with 1,380 additions and 8 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Expand Up @@ -71,4 +71,12 @@ Watchman.vcxproj
*.sdf
*.sln
*.suo
m4/
.libs/
*.lo
*.la
tests/integration/cppclient.t
libtool
ltmain.sh
cppclient/watchmanclient.pc
/website/.jekyll-metadata
8 changes: 8 additions & 0 deletions .hgignore
Expand Up @@ -45,3 +45,11 @@ website/src/watchman/docs
website/src/watchman/*.js
website/core/metadata.js
npm-debug.log
m4/
.libs/
*.lo
*.la
tests/integration/cppclient.t
cppclient/watchmanclient.pc
libtool
ltmain.sh
33 changes: 33 additions & 0 deletions Makefile.am
@@ -1,3 +1,5 @@
ACLOCAL_AMFLAGS=-I m4

bin_PROGRAMS = watchman
# ensure that we have a reasonable default for the python install
DESTDIR ?= /
Expand Down Expand Up @@ -139,6 +141,37 @@ TESTS = \
tests/string.t \
tests/log.t \
tests/wildmatch.t

if ENABLE_CPPCLIENT
lib_LTLIBRARIES = libwatchmanclient.la
libwatchmanclient_ladir = $(includedir)/watchman/
libwatchmanclient_la_HEADERS = \
cppclient/WatchmanClient.h \
cppclient/WatchmanConnection.h

TESTS += tests/integration/cppclient.t

# No IRONMANCFLAGS as this is incompatible with Folly
libwatchmanclient_la_SOURCES = \
cppclient/WatchmanClient.cpp \
cppclient/WatchmanConnection.cpp \
cppclient/WatchmanResponseError.cpp
libwatchmanclient_la_CPPFLAGS = $(FOLLY_CFLAGS)
libwatchmanclient_la_LDFLAGS = -version-info 0:0:0 $(FOLLY_LDFLAGS)
CPPCLIENT_LIB=libwatchmanclient.la

# No IRONMANCFLAGS as this is incompatible with Folly
tests_integration_cppclient_t_CPPFLAGS = $(FOLLY_CFLAGS) -I cppclient/
tests_integration_cppclient_t_LDADD = $(CPPCLIENT_LIB) $(FOLLY_LIBS)
tests_integration_cppclient_t_LDFLAGS = $(FOLLY_LDFLAGS)
tests_integration_cppclient_t_SOURCES = \
tests/integration/cppclient.cpp

# install pkg-config metadata file
pkgconfigdir = $(libdir)/pkgconfig
nodist_pkgconfig_DATA = cppclient/watchmanclient.pc
endif

noinst_PROGRAMS = $(TESTS)

export ARCHFLAGS=@ARCHFLAGS@
Expand Down
20 changes: 19 additions & 1 deletion autogen.sh
@@ -1,12 +1,30 @@
#!/bin/sh
#!/bin/bash -e
# vim:ts=2:sw=2:et:
if test -d autom4te.cache ; then
rm -rf autom4te.cache
fi
if test -d config.status ; then
rm -f config.status
fi

for p in libtoolize glibtoolize FAIL; do
test "$p" = FAIL && { echo "your system lacks libtoolize" 1>&2; exit 1; } || :
( $p --version ) > /dev/null 2>&1 && { eval "libtoolize() { env $p; }"; break; } || :
done
libtoolize --no-warn -i -f

aclocal
autoheader
automake --add-missing --foreign

# This checks to make sure PKG_CHECK_MODULES is available to autoconf. This
# should be the case provided pkg-config is installed AND the above commands
# have been run to prep the source tree with local set-up.
CHECK_PKG_CONFIG_M4='m4_ifdef([PKG_CHECK_MODULES], [errprint([ok])])'
if [ "x$(autoconf <(echo "$CHECK_PKG_CONFIG_M4") 2>&1)" != "xok" ] ; then
echo 'pkg-config appears to be missing (not available to autoconf tools)'
echo 'please install the pkg-config package for your system.'
exit 1
fi

autoconf
37 changes: 34 additions & 3 deletions configure.ac
@@ -1,4 +1,5 @@
AC_INIT([watchman], [4.8.0], [], [watchman])
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES(yes)])
Expand All @@ -24,11 +25,38 @@ AX_CXX_COMPILE_STDCXX_11([noext],[mandatory])
AC_PROG_CPP
AC_C_BIGENDIAN
AC_C_INLINE
AC_PROG_RANLIB

LT_INIT

AM_PROG_CC_C_O
AM_PROG_AS

AC_ARG_ENABLE([cppclient],
AS_HELP_STRING([--disable-cppclient], [Disable build of C++ client library]))

AC_ARG_WITH([folly],
AS_HELP_STRING([--with-folly=<path to folly>], [Where to find folly]))

AS_IF([test "x$with_folly" != "x"], [
folly_config_dir=$with_folly/lib/pkgconfig/
AS_IF([test -f "$folly_config_dir/libfolly.pc"],
[export PKG_CONFIG_PATH=$folly_config_dir:$PKG_CONFIG_PATH],
[AC_MSG_ERROR([cannot find folly config $folly_config_dir/libfolly.pc])]
)
])


dnl
dnl Decide whether to build the C++ client library
dnl
PKG_CHECK_MODULES([FOLLY], [libfolly], [folly=yes], [folly=no])
AS_IF([test "x$enable_cppclient" = "xyes" && test "x$folly" = "xno"],
[AC_MSG_ERROR([cppclient requested but libfolly not present])])
AS_IF([test "x$enable_cppclient" != "xno" && test "x$folly" = "xno"],
[enable_cppclient=no])
AM_CONDITIONAL(ENABLE_CPPCLIENT, [test "x$enable_cppclient" != "xno"])


dnl I don't care that this is supposed to be sysconfdir; autoconf doesn't
dnl allow it to be evaluated sanely from configure, only via Makefile,
dnl which I don't care about. Just pass the right value to configure.
Expand Down Expand Up @@ -294,7 +322,11 @@ fi
AC_SUBST(IRONMANCFLAGS)

AC_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile thirdparty/jansson/jansson_config.h])
AC_CONFIG_FILES([
Makefile
thirdparty/jansson/jansson_config.h
cppclient/watchmanclient.pc
])
AC_OUTPUT

if test "$WATCHMAN_STATE_DIR" != "no"; then
Expand All @@ -320,4 +352,3 @@ Your build configuration:
EOF

dnl vim:ts=2:sw=2:

58 changes: 58 additions & 0 deletions cppclient/CLI.cpp
@@ -0,0 +1,58 @@
/* Copyright 2016-present Facebook, Inc.
* Licensed under the Apache License, Version 2.0 */

/*
This is a test utility for WatchmanConnection. This works a bit like the
watchman CLI.
Build with something like:
$ LDFLAGS=$(pkg-config watchmanclient --libs) \
CPPFLAGS=$(pkg-config watchmanclient --cflags) \
make CLI
WatchmanConnection is automatically tested via the cppclient test more
thoroughly.
*/

#include <watchman/WatchmanConnection.h>

#include <iostream>

#include <folly/init/Init.h>
#include <folly/io/async/ScopedEventBaseThread.h>
#include <folly/json.h>

using namespace folly;
using namespace watchman;

int main(int argc, char** argv) {
folly::init(&argc, &argv);

folly::ScopedEventBaseThread sebt;
auto eb = sebt.getEventBase();

folly::dynamic cmd = folly::dynamic::array;
for (int i = 1; i < argc; i++) {
cmd.push_back(std::string(argv[i]));
}

WatchmanConnection c(eb);
c.connect()
.then([&](folly::dynamic version) {
std::cout << "Connected to watchman: " << version << std::endl;
std::cout << "Going to run " << cmd << std::endl;
return c.run(cmd);
})
.then([](folly::dynamic result) { LOG(INFO) << "Result: " << result; })
.onError([](const folly::exception_wrapper& ex) {
std::cerr << "Failed: " << ex.what() << std::endl;
})
.wait();

c.run(folly::dynamic::array("watch-list"))
.then([](folly::dynamic res) { std::cout << res << std::endl; })
.wait();
c.close();

return 0;
}
23 changes: 23 additions & 0 deletions cppclient/TARGETS
@@ -0,0 +1,23 @@
cpp_library(
name='cppclient',
headers=['WatchmanClient.h', 'WatchmanConnection.h'],
srcs=[
'WatchmanConnection.cpp',
'WatchmanResponseError.cpp',
'WatchmanClient.cpp',
],
deps=[
'@/folly:folly',
'@/folly/io/async:async',
'@/folly:subprocess',
'@/folly/futures:futures',
'@/folly/experimental/bser:bser',
]
)

buck_cxx_library(
name='headers',
exported_headers=['WatchmanClient.h', 'WatchmanConnection.h'],
header_namespace='',
visibility=['PUBLIC'],
)

0 comments on commit 3782208

Please sign in to comment.