Practical Bazel: Depending on a System-Provided C/C++ Library
Practical Bazel bazel c c++
Published: 2021-09-22
Practical Bazel: Depending on a System-Provided C/C++ Library

Let’s say you are using Bazel to build a C program which links against a system-provided version of libcurl, the multiprotocol file transfer library. What is the best way to link your program against this library within Bazel? This blog post provides an answer to that question.

The first option that probably comes to mind is to use cc_binary and friend’s linkopts attribute, as in:

1
2
3
4
5
6
# BUILD file for my_program
cc_binary(
    name = "my_program",
    srcs = [...],
    linkopts = ["-lcurl"],
)

This works fine, but it does not properly integrate with cc_binary’s linkstatic attribute which is intended to allow a binary to choose whether to link against either the shared or static version of a library. However, if we use cc_import to import libcurl and use a dependency, we can make linkstatic work as intended.

The main trick is to figure out how to reference the system-provided library. This can be done with a little trick using an external repository using new_local_repository(), as follows:

1
2
3
4
5
6
# WORKSPACE
new_local_repository(
    name = "libcurl",
    path = "/usr",
    build_file = "//third_party/libcurl:libcurl.BUILD"
)
1
2
3
4
5
6
7
# //third_party/libcurl:libcurl.BUILD
cc_import(
    name = "libcurl",
    shared_library = "lib/x86_64-linux-gnu/libcurl.so",
    static_library = "lib/x86_64-linux-gnu/libcurl.a",
    visibility = ["//visibility:public"],
)
1
2
3
4
5
6
# BUILD file for my_program
cc_binary(
    name = "my_program",
    srcs = [...],
    deps = ["@libcurl"],
)

Recursive dependencies (e.g. in order to link lib1 you must link to lib2, in order to link to lib2 you must also link to lib3) can be represented as deps on the cc_import() stanza for liba, as in:

1
2
3
4
5
6
# //third_party/lib1:lib1.BUILD
cc_import(
    name = "lib1",
    deps = ["@lib2"],
    ...
)
1
2
3
4
5
6
# //third_party/lib2:lib2.BUILD
cc_import(
    name = "lib2",
    deps = ["@lib3"],
    ...
)
1
2
3
4
5
# //third_party/lib3:lib3.BUILD
cc_import(
    name = "lib3",
    ...
)

I recommend using cc_import() and Bazel target dependencies over linkopts whenever possible.