Search code examples
gobazel

Bazel go_binary c-shared link mode: Where is the header?


I'm trying to use Bazel (v1.0.0) rules_go to build header + library as I would with go build -buildmode=c-archive. I have the following rule set up in my BUILD.bzl file:

go_binary(
   name="go_cpp_bridge",
   srcs = ["cpp_bridge.go"],
   cgo = True,
   gc_linkopts=["-buildmode=c-shared"],
   linkmode = "c-archive",
   visibility = ["//visibility:public"],
 )

The current code of cpp_bridge.go is just a hello world to see if it works:

package main

import "C"

//export Add
func Add(a, b int) int { return a + b }

func main(){}

Bazel does generate a library file, but I'm missing the associated header file in the bazel-bin output. Testing with go build yields both header file and library. How do I get Bazel to give me the same.


Solution

  • When linkmode = "c-shared" and linkmode = "c-archive" are defined, there are a few additional targets that are defined by adding a suffix to the end of the go_binary name. So for example, you can build go_cpp_bridge.c_hdrs to get the header file. You can build go_cpp_bridge.cc for a cc_library that can be linked with other C/C++ targets. The header is named after the go_binary rule (so go_cpp_bridge.h).

    To extend your example, here's a working build file:

    load("@io_bazel_rules_go//go:def.bzl", "go_binary")
    
    go_binary(
        name = "go_cpp_bridge",
        srcs = ["cpp_bridge.go"],
        cgo = True,
        linkmode = "c-archive",
    )
    
    cc_binary(
        name = "main",
        srcs = ["main.c"],
        deps = [":go_cpp_bridge.cc"],
    )
    

    And a C program that links against Go:

    #include <stdio.h>
    #include "go_cpp_bridge.h"
    
    int main() {
      printf("%lld\n", Add(21, 21));
      return 0;
    }
    

    This isn't documented because it's not a great interface. Since this was implemented, Bazel has added better ways to write C/C++ compatible rules, but rules_go doesn't support that yet. #2176 is the tracking issue for that.