12

Looking for a good example of autoconf and automake rules for building a project that uses protocol buffers, best way to add protoc to the build process?

Aaron
  • 1,141
  • 1
  • 11
  • 21

2 Answers2

17

configure.ac

As far as the protobuf library goes, it uses pkg-config, so it's probably best to refer to it using PKG_CHECK_MODULES macro:

PKG_CHECK_MODULES(PROTOBUF, protobuf >= 2.4.0)
AC_SUBST(PROTOBUF_LIBS)
AC_SUBST(PROTOBUF_CFLAGS)
AC_SUBST(PROTOBUF_VERSION)

And check for protoc command in the path. Here's a very basic check that it's in the path:

AC_CHECK_PROG([PROTOC], [protoc], [protoc])
AS_IF([test "x${PROTOC}" == "x"],
    [AC_MSG_ERROR([ProtoBuf compiler "protoc" not found.])])

Alternatively, allow the user to specify a different protoc with either --with-protoc=/path/to/protoc or using environment variable PROTOC:

# ProtoBuf compiler.
# First, specify with --with-protoc=/path/of/protoc.
# Or, specify with env variable PROTOC.
# If neither of the above, find it in the path.
#AC_MSG_CHECKING([for ProtoBuf compiler protoc])
AC_ARG_WITH([protoc],
    [AS_HELP_STRING([--with-protoc=/path/of/protoc],
        [Location of the protocol buffers compiler protoc. Defaults to looking on path.])],
    [PROTOC="$withval"],
    [ AS_IF([test "x${PROTOC}" == "x"],
        [AC_PATH_PROG([PROTOC], [protoc], [no])])
    ]
)
#AC_MSG_RESULT([${PROTOC}])
AS_IF([test "${PROTOC}" == "no"], [AC_MSG_ERROR([ProtoBuf compiler "protoc" not found.])])

Makefile.am

Add a rule to build the proto files:

%.pb.cc %.pb.h: %.proto
    $(PROTOC) --proto_path=$(srcdir) --cpp_out=$(builddir) $^

Specify protobuf source files with dist_noinst_DATA. This is necessary to ensure they get bundled in a source distribution .tar.gz file made with make dist.

dist_noinst_DATA = whatever.proto

(Note: for newer versions of autoconf/automake, it may be necessary to use @builddir@ instead of $(builddir).)

Specify generated files with nodist_ prefix and $(builddir) path:

nodist_myprog_SOURCES = $(builddir)/whatever.pb.cc $(builddir)/whatever.pb.h

And to clean them with make clean:

MOSTLYCLEANFILES = whatever.pb.cc whatever.pb.h

Use BUILT_SOURCES to handle dependency for built header files:

BUILT_SOURCES = whatever.pb.h

Your compiler flags may need to refer to the build directory to find the header file (to work in VPATH builds):

AM_CPPFLAGS += -I$(builddir)
Craig McQueen
  • 41,871
  • 30
  • 130
  • 181
  • 1
    The `AC_SUBST(PROTOBUF_*)` are not needed if `autoconf >= 0.24` as explained in [section 3.2 of Autotools myths](https://autotools.io/pkgconfig/pkg_check_modules.html) – RubenLaguna Feb 11 '15 at 12:08
  • Very nice, thank you! `nodist_myprog_SOURCES` needs to use `@builddir@/whatever.pb.cc` now. – os_ Jan 02 '18 at 00:23
7

This seems to work:

configure.ac:

AC_ARG_WITH([protobuf-libdir],
    [AS_HELP_STRING([--with-protobuf-libdir=LIB_DIR],
        [location of the protocol buffers libraries, defaults to /usr/lib])],
    [PROTOBUF_LIBDIR="$withval"],
    [PROTOBUF_LIBDIR='/usr/lib'])
AC_SUBST([PROTOBUF_LIBDIR])

LDFLAGS="$LDFLAGS -L$PROTOBUF_LIBDIR"

AC_CHECK_LIB([protobuf], [main], [], [AC_MSG_ERROR([cannot find protobuf library])])

AC_ARG_WITH([protoc],
    [AS_HELP_STRING([--with-protoc=PATH],
        [location of the protoc protocol buffer compiler binary, defaults to protoc])],
    [PROTOC="$withval"],
    [PROTOC='protoc'])
AC_SUBST([PROTOC])

Makefile.am:

%.pb.cc %.pb.h: %.proto
    $(PROTOC) --proto_path=$(dir $^) --cpp_out=$(dir $^) $^

And then add the .pb.cc files to SOURCES.

Aaron
  • 1,141
  • 1
  • 11
  • 21
  • Does that `Makefile.am` rule work with VPATH builds (e.g. `mkdir build; cd build; ../configure; make`)? The output files should probably go in `$builddir` rather than in `$srcdir`. – Craig McQueen Aug 21 '13 at 01:33
  • 1
    With `$(dir $^)` in the `Makefile.am` rule, I get an error `Makefile.am:11: dir $^: non-POSIX variable name; Makefile.am:11: (probably a GNU make extension)`. – Craig McQueen Aug 21 '13 at 02:15