Skip to content

Commit

Permalink
(Part 1) - Add an optional dependency on libboost-iostreams
Browse files Browse the repository at this point in the history
The main refactoring taking place in this PR is to port the P4-14 and
P4-16 lexers and parsers to use the C++ modes of Flex and Bison. In C++
mode, Flex generates a lexer that reads from a `std::istream` object
instead of a file descriptor. That produces a bit of an impedance
mismatch, because typically before we parse anything we run it through
the C preprocessor via `popen()`, and `popen()` uses C `FILE*`-based I/O
rather than iostreams.

The C++-11 standard library does not include a `FILE*` wrapper that
produces an `std::istream`. If we don't want to write and maintain one
ourselves (and I'd argue we don't) that leaves us with three options:

1. Stop using `popen()` and implement the subset of C preprocessor
   features we need directly.

2. Read the entire file in and wrap it in a `std::stringstream` or
   similar. This obviously isn't as efficient as it could be.

3. Use Boost's IOStreams library to do the job more efficiently.

In the large term, my view is that p4lang#1 is the best choice, but in the
short run p4lang#3 seems like a win with no real downsides other than adding
another dependency. (It's only an additional dependency on Ubuntu, which
splits Boost into a number of small packages. On macOS there's actually
no change.)

In the interest of getting this PR landed ASAP, I've actually
implemented both p4lang#2 and p4lang#3, so the Boost IOStreams dependency is
optional. I would vastly prefer to make it mandatory, though.
  • Loading branch information
sethfowler committed May 4, 2017
1 parent a65f22f commit 6790aa0
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ ENV P4C_DEPS automake \
flex \
g++ \
libboost-dev \
libboost-iostreams1.58-dev \
libgc-dev \
libgmp-dev \
libtool \
Expand All @@ -26,6 +27,7 @@ ENV P4C_DEPS automake \
python-scapy \
tcpdump
ENV P4C_RUNTIME_DEPS cpp \
libboost-iostreams1.58.0 \
libgc1c2 \
libgmp10 \
libgmpxx4ldbl \
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ included with `p4c` are documented here:
Most dependencies can be installed using `apt-get install`:
`sudo apt-get install g++ git automake libtool libgc-dev bison flex libgmp-dev libboost-dev pkg-config python python-scapy python-ipaddr tcpdump`
`sudo apt-get install g++ git automake libtool libgc-dev bison flex libgmp-dev libboost-dev libboost-iostreams-dev pkg-config python python-scapy python-ipaddr tcpdump`
For documentation building:
`sudo apt-get install -y doxygen graphviz texlive-full`
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ AC_CHECK_LIB([gc], [GC_malloc], [], [AC_MSG_ERROR([Missing GC library])])
AC_CHECK_LIB([rt], [clock_gettime], [], [])
AC_CHECK_LIB([gmp], [__gmpz_init], [], [AC_MSG_ERROR([GNU MP not found])])
AC_CHECK_LIB([gmpxx], [__gmpz_init], [], [AC_MSG_ERROR([GNU MP not found])])
AX_CXX_CHECK_LIB([boost_iostreams], [boost::iostreams::file_descriptor], [], [])

AC_CONFIG_FILES([Makefile])
AX_PYTHON_MODULE([difflib], [fatal], [python])
Expand Down
110 changes: 110 additions & 0 deletions m4/ax_cxx_check_lib.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
dnl @synopsis AX_CXX_CHECK_LIB(libname, functioname, action-if, action-if-not)
dnl
dnl The standard AC_CHECK_LIB can not test functions in namespaces.
dnl Therefore AC_CHECK_LIB(cgicc, cgicc::Cgicc::getVersion) will always
dnl fail. We need to decompose the functionname into a series of namespaces
dnl where it gets declared so that it can be used for a link test.
dnl
dnl In the first version I did allow namespace::functionname to be a
dnl reference to a void-argument global functionname (just wrapped in a
dnl namespace) like its C counterparts would be - but in reality such
dnl thing does not exist. The only global / static functions are always
dnl made const-functions which is an attribute mangled along into the
dnl library function export name.
dnl
dnl The normal usage will ask for a test of a class-member function which
dnl should be presented with a full function spec with arguments given in
dnl parentheses following the function name - if the function to test for
dnl does expect arguments then you should add default initial values in the
dnl prototype (even if they do not exist originally, these are used only
dnl locally to build a correct function call in the configure test script).
dnl
dnl In the current version if you do omit the parenthesis from the macro
dnl argument then the macro will assume that you want to check for the
dnl class name - which is really to check for default constructor being
dnl exported from the given library name.
dnl
dnl EXAMPLE:
dnl AX_CXX_CHECK_LIB(cgicc, [cgicc::HTTPCookie])
dnl AX_CXX_CHECK_LIB(cgicc, [cgicc::Cgicc::getVersion () const],
dnl AX_CXX_CHECK_LIB(boost_regex, [boost::RegEx::Position (int i = 0) const])
dnl
dnl Result:
dnl Just as the usual AX_CXX_CHECK_LIB - defines HAVE_LIBCGICC
dnl and adds the libraries to the default library path (and
dnl uses internally the normal ac_check_lib cache symbol
dnl like ac_cv_lib_cgicc_cgicc__Cgicc)
dnl
dnl Footnote: The C++ language is not good at creating stable library
dnl interfaces at the binary level - a lot of functionality is usually being
dnl given as inline functions plus there is hardly a chance to create opaque
dnl types. Therefore most C++ library tests will only do compile tests using
dnl the header files. Doing a check_lib is however good to check the link
dnl dependency before hitting it as an error in the build later.
dnl
dnl @category C++
dnl @author Guido U. Draheim
dnl @vesion 2006-12-18

AC_DEFUN([AX_CXX_CHECK_LIB],
[m4_ifval([$3], , [AH_CHECK_LIB([$1])])dnl
AS_LITERAL_IF([$1],
[AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1_$2])],
[AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1''_$2])])dnl
AC_CACHE_CHECK([for $2 in -l$1], ac_Lib,
[ac_check_lib_save_LIBS=$LIBS
LIBS="-l$1 $5 $LIBS"
case "$2"
in *::*::*\(*)
AC_LINK_IFELSE([AC_LANG_PROGRAM([
namespace `echo "$2" | sed -e "s/::.*//"`
{ class `echo "$2" | sed -e "s/.*::\\(.*\\)::.*/\\1/" -e "s/(.*//"`
{ public: int `echo "$2" | sed -e "s/.*:://" -e "/(/!s/..*/&()/"`;
};
}
],[`echo "$2" | sed -e "s/(.*//" -e "s/\\(.*\\)::\\(.*\\)/((\\1*)(0))->\\2/g"`()])],
[AS_VAR_SET(ac_Lib, yes)],
[AS_VAR_SET(ac_Lib, no)])
;; *::*::*)
AC_LINK_IFELSE([AC_LANG_PROGRAM([
namespace `echo "$2" | sed -e "s/::.*//"`
{ namespace `echo "$2" | sed -e "s/.*::\\(.*\\)::.*/\\1/"`
{ class `echo "$2" | sed -e "s/.*:://"`
{ public: `echo "$2" | sed -e "s/.*:://"` ();
};
}
}
],[new $2()])],
[AS_VAR_SET(ac_Lib, yes)],
[AS_VAR_SET(ac_Lib, no)])
;; *::*\(*)
AC_LINK_IFELSE([AC_LANG_PROGRAM([
class `echo "$2" | sed -e "s/\\(.*\\)::.*/\\1/" -e "s/(.*//"`
{ public: int `echo "$2" | sed -e "s/.*:://" -e "/(/!s/..*/&()/"`;
};
],[`echo "$2" | sed -e "s/(.*//" -e "s/\\(.*\\)::\\(.*\\)/((\\1*)(0))->\\2/g"`()])],
[AS_VAR_SET(ac_Lib, yes)],
[AS_VAR_SET(ac_Lib, no)])
;; *::*)
AC_LINK_IFELSE([AC_LANG_PROGRAM([
namespace `echo "$2" | sed -e "s/::.*//"`
{ class `echo "$2" | sed -e "s/.*:://"`
{ public: `echo "$2" | sed -e "s/.*:://"` ();
};
}
],[new $2()])],
[AS_VAR_SET(ac_Lib, yes)],
[AS_VAR_SET(ac_Lib, no)])
;; *)
AC_LINK_IFELSE([AC_LANG_CALL([], [$2])],
[AS_VAR_SET(ac_Lib, yes)],
[AS_VAR_SET(ac_Lib, no)])
;; esac
LIBS=$ac_check_lib_save_LIBS])
AS_IF([test AS_VAR_GET(ac_Lib) = yes],
[m4_default([$3], [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_LIB$1))
LIBS="-l$1 $LIBS"
])],
[$4])dnl
AS_VAR_POPDEF([ac_Lib])dnl
])# AC_CHECK_LIB

0 comments on commit 6790aa0

Please sign in to comment.