6

I'm experimenting with using libhttpserver and, by extension, libmicrohttpd from inside a Bazel build. The build process for these libraries seems to go:

./bootstrap
mkdir build
cd build
../configure
make

which is a slight variation, that I haven't seen before, on the more classic configure && make workflow.

  • Has anyone managed to make such a library work under Bazel?
  • Does anyone have a public example I can crib from?

The closest thing I've found to supporting this is @rules_foreign_cc//tools/build_defs:configure.bzl#configure_make but that seems to have no concept of the bootstrap step. Even hacking it doesn't seem to work as the bootstrap script ends up failing with:

mkdir: cannot create directory 'tmpwrk23': Read-only file system
autopoint: *** cannot create directory tmpwrk23
autopoint: *** Stop.
autoreconf: autopoint failed with exit status: 1

I'm about ready to just reach for a genrule() but that seems very error prone...

BCS
  • 75,627
  • 68
  • 187
  • 294
  • 1
    It looks like the `bootstrap` scripts are the same thing that is more conventionally named `autogen.sh`. These are not particularly unusual, but it is atypical of GNU software that running them should be a part of a normal build. There are in fact issues with that which are quite independent of Bazel. A distribution tarball of one of these packages should come with the `configure` script and other artifacts produced by `bootstrap` already present, and generally, these should *not* be rebuilt locally. – John Bollinger Feb 04 '20 at 13:02
  • But it has become fashionable these days to exclude the `configure` script, *etc* from revision control, on the basis that they are generated files (which they are). This is unfortunate, because the process of building the build system is much more sensitive to (Autotools) software versions than is the process of building the actual project. The Autotools themselves aren't even required for building a project from a proper distribution tarball of an Autotools project. – John Bollinger Feb 04 '20 at 13:08
  • 1
    Of course, none of that actually answers the question, but I hope it provides some insight. I'm uncertain how applicable it would be to Bazel, but if you can't download a real distribution tarball from somewhere then one possible solution would be to build one outside Bazel (`./bootstrap; ./configure; make dist`), then use the resulting distribution tarball, without `./bootstrap`, for any number of subsequent actual builds. – John Bollinger Feb 04 '20 at 13:12
  • @JohnBollinger that is useful. And it suggests's one option if I want to to stick with pulling from versions control rather than a tarball: run just the bootstrap as a `genrule`, combine that result with the `new_git_repository` and then use `configure_make` on the result. Likely a bit brittle if the set of outputs from bootstrap change, but it's something to think about. – BCS Feb 04 '20 at 19:22

1 Answers1

6

I went down the same path as you and was able to get libhttpserver compiling with bazel using the rules_foreign_cc project after coming across the 6/23/20 update on this blog post. I added code below, but in general rules_foreign_cc has a make rule, which you can set override make_commands and call ./bootstrap.

WORKSPACE:

...
http_archive(
   name = "rules_foreign_cc",
   strip_prefix = "rules_foreign_cc-master",
   url = "https://github.com/bazelbuild/rules_foreign_cc/archive/master.zip",
)
load("@rules_foreign_cc//:workspace_definitions.bzl", "rules_foreign_cc_dependencies")
rules_foreign_cc_dependencies(register_default_tools = True)

all_content = """filegroup(name = "all", srcs = glob(["**"]), visibility = ["//visibility:public"])"""

http_archive(
  name = "rules_cc",
  urls = ["https://github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip"],
  strip_prefix = "rules_cc-262ebec3c2296296526740db4aefce68c80de7fa",
)

http_archive(
    name = "libgnutls",
    build_file_content = all_content,
    strip_prefix = "gnutls-3.6.15",
    urls = ["https://www.gnupg.org/ftp/gcrypt/gnutls/v3.6/gnutls-3.6.15.tar.xz"],
)    

http_archive(
    name = "libhttpserver",
    build_file_content = all_content,
    strip_prefix = "libhttpserver-master",
    urls = ["https://github.com/etr/libhttpserver/archive/master.zip"],
)

http_archive(
    name = "libmicrohttpd",
    build_file_content = all_content,
    strip_prefix = "libmicrohttpd-0.9.71",
    urls = ["https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-0.9.71.tar.gz"],
)

BUILD:

load("@rules_foreign_cc//tools/build_defs:configure.bzl", "configure_make")
load("@rules_foreign_cc//tools/build_defs:make.bzl", "make")
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")

package(default_visibility = ["//visibility:public"])

configure_make(
    name = "libgnutls",
    lib_source = "@libgnutls//:all",
    configure_options = ["--with-included-unistring"],
    out_include_dir = "include/gnutls",
    shared_libraries = ["libgnutls.so"],
)

configure_make(
    name = "libmicrohttpd",
    lib_source = "@libmicrohttpd//:all",
    deps = [":libgnutls"],
)

make(
    name = "libhttpserver",
    lib_source = "@libhttpserver//:all",
    make_commands = [
        "./bootstrap",
        "mkdir build_dir",
        "cd build_dir",
        "../configure --prefix=${INSTALLDIR}",
        "make",
        "make install",
    ],
    deps = [":libmicrohttpd", ":libgnutls"],
)

cc_binary(
    name = "hello-world",
    srcs = ["hello_world.cc"],
    deps = [
        ":libhttpserver"
    ],
)

hello_world.cc (example on libhttpserver github page, run "curl -XGET -v http://localhost:8080/hello" to test)

#include <iostream>
#include <httpserver.hpp>

using namespace std;
using namespace httpserver;

class hello_world_resource : public http_resource {
public:
    const std::shared_ptr<http_response> render(const http_request&) {
        return std::shared_ptr<http_response>(new string_response("Hello, World!"));
    }
};

int main(int argc, char** argv) {
    cout << "hello!" << std::endl;
    webserver web_server = create_webserver(8080);

    hello_world_resource resource;
    web_server.register_resource("/hello", &resource);
    web_server.start(true);

    return 0;
}
megabits
  • 145
  • 1
  • 8
  • Nice! ... Is that published anywhere? E.g. GitHub? – BCS Sep 24 '20 at 05:23
  • 2
    Added here: https://github.com/megamegabits/libhttpserver-bazel-example. Thanks for asking, it looks like the code above as-is fails to compile without the added dependency on absl you'll see in the github version. Not sure why right now, but will take a look later. – megabits Sep 24 '20 at 19:44