Search code examples
cgoshared-librariesbazelcgo

Build and run Go using cgo using bazel


There is simple cgo project available on this page. It relies on pre-built c shared library and it works great when using go build, with minor changes to make it buildable.

I wanted to use Bazel for the same thing.

Used source code is same as on this github link, without using hello.c file. With all said, final code looked like below.

/*
 * person.c
 * Copyright (C) 2019 Tim Hughes
 *
 * Distributed under terms of the MIT license.
 */

#include <stdlib.h>
#include "person.h"

APerson *get_person(const char *name, const char *long_name)
{

    APerson *fmt = malloc(sizeof(APerson));
    fmt->name = name;
    fmt->long_name = long_name;

    return fmt;
};
/*
 * person.h
 * Copyright (C) 2019 Tim Hughes
 *
 * Distributed under terms of the MIT license.
 */

#ifndef PERSON_H
#define PERSON_H

typedef struct APerson
{
    const char *name;
    const char *long_name;
} APerson;

APerson *get_person(const char *name, const char *long_name);

#endif /* !PERSON_H */

package main

/*
#cgo CFLAGS: -g -Wall
#cgo LDFLAGS: -L. -lperson
#include "person.h"
*/
import "C"

import (
    "github.com/kubernetes/klog"
)

type (
    Person C.struct_APerson
)

func GetPerson(name string, long_name string) *Person {
    return (*Person)(C.get_person(C.CString(name), C.CString(long_name)))
}

func main() {
    klog.Info("it is running")
    var f *Person
    f = GetPerson("tim", "tim hughes")
    klog.Infof("Hello Go world: My name is %s, %s.\n", C.GoString(f.name), C.GoString(f.long_name))
}

Bazel build file is below.

load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")

go_library(
    name = "listing_lib",
    srcs = [
        "person.c",
        "person.h",
        "runner.go",
    ],
    cgo = True,
    clinkopts = ["-Lpersons/listing -lperson"],
    copts = ["-g -Wall"],
    importpath = "github.com/example/project/persons/listing",
    visibility = ["//visibility:private"],
    deps = ["@com_github_kubernetes_klog//:klog"],
)

go_binary(
    name = "listing",
    embed = [":listing_lib"],
    visibility = ["//visibility:public"],
)

Still when building by running bazelisk build //persons/listing, error happens and it is general linker error.

/usr/bin/ld.gold: error: cannot find -lperson
collect2: error: ld returned 1 exit status
compilepkg: error running subcommand /usr/bin/gcc: exit status 1

I need few things to clear out.

  • are c libraries built automatically? My assumption is that those are not.
  • if not, then why -L. is not working if built lib is same folder as go file? Assumption is that bazel does not see library in source folder, but is looking in wrong location.
  • is it possible to use cc_library rule to build shared library that can be used in cgo? if so, how to connect those?

Solution

  • are c libraries built automatically? My assumption is that those are not.

    Why? Tests from the offical repo shows, that it is done automatically

    is it possible to use cc_library rule to build shared library that can be used in cgo? if so, how to connect those?

    See example from here