jkr
jkr

Reputation: 19300

Wrapping C++ with Go build

I am trying to wrap C++ code (LabStreamingLayer) in Go.

Update: @dragonx explained how to use go build without swig. But I am still running into a linker issue. The build depends on LSL/liblsl/bin/liblsl.dylib. How do I tell go build to use that file? I tried go build -ldflags "-L ../liblsl/bin -l lsl" app.go with no success.

The Go documentation says that go build will invoke Swig with the c++ option for files with the .swigcxx extension, but go build complains that there are no buildable Go source files in the directory.

Here are the steps I took to arrive at that error:

  1. Clone the labstreaminglayer repo.
  2. Rename the file liblsl_cpp.i to liblsl.swigcxx (I thought this would tell go build that the file should be used with swig).
  3. cd into LSL/liblsl-Generic and run go build. Go complains that there are no buildable Go source files in this directory.

After that failed, I tried using Swig. I ran swig -c++ -go -cgo -intgosize 64 liblsl_cpp.i, which created a .go file. I then ran go build in that directory, but it raised the error:

ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1

I am not familiar with C++, so I am not sure how to resolve the linker issue. I do know that this C++ code requires the file LSL/liblsl/bin/liblsl64.dylib. I assume that is the file that must be linked?

How can I wrap this C++ code in Go?

Here is the file structure:

LSL
├── liblsl
│   ├── bin
│   ├── distros
│   ├── examples
│   ├── external
│   ├── include
│   ├── project
│   ├── src
│   └── testing
└── liblsl-Generic
    ├── AUTOGENERATE\ HOWTO.txt
    ├── examples
    ├── liblsl.swigcxx
    ├── liblsl_c.i
    ├── liblsl_cpp.i
    ├── liblsl_wrap.cxx  # created by Swig
    └── liblsl.go        # created by Swig

Upvotes: 3

Views: 1747

Answers (2)

  1. Unzip liblsl release tarball and clone liblsl-Generic to a folder under Go home directory
  2. Fix liblsl_cpp.i so that it points to the correct header file path
  3. Run swig -go -c++ -cgo -intgosize 32 -package liblsl liblsl_cpp.i
  4. Add // #cgo LDFLAGS: -Wl,-rpath,/usr/local/lib -llsl64 (assuming liblsl64.dylib is at /usr/local/lib) after package liblsl on the preceding line before the next comment in your liblsl.go
  5. Run go install

That will make it, liblsl.a will be under Go home dir's pkg folder and you will be able to import it from Go programs.

Upvotes: -1

dragonx
dragonx

Reputation: 15143

I ran into this a few months ago, took longer to figure out than I would have liked, but I don't remember exactly what I did to fix it, but I think it was along these lines:

  1. Don't call swig manually, it actually makes things a bit more difficult. Clean out the files generate by swig.
  2. Create a file a.go in libsl-Generic with the contents:

    package libsls-Generic
    
  3. In theory you have some other file, say app.go that will use libsls-Generic. Write app.go and import libsls-Generic appropriately.
  4. Use go build app.go. This should build the dependency as well.

I eventually figured out how to get go to incorporate the files manually generated by swig, but I forget the details now. I do remember that when generating files manually with swig, I would have to manually delete certain files when rebuilding. When running with just go, the build step was much simpler.

Upvotes: 2

Related Questions