Override an external package's cgo compiler and linker flags? - go

Let's say I want to use some awesome go package. I can include it by:
import "github.com/really-awesome/project/foobar"
And inside that project's foobar.go file, it defines some cgo instructions like:
#cgo windows CFLAGS: -I C:/some-path/Include
#cgo windows LDFLAGS: -L C:/some-path/Lib -lfoobar
But if I have that foobar C dependency installed somewhere else, I would really need those lines to say:
#cgo windows CFLAGS: -I C:/different-path/Include
#cgo windows LDFLAGS: -L C:/different-path/Lib -lfoobar
Is there a way to override or trump where cgo is looking for these dependencies? Right now my fix is to manually edit those two lines after running go get ./... which will fetch the github.comreally-awesome/project/foobar code.
NOTE: I'm using the MinGw compiler, though I doubt that matters.
update:
I have tried adding flags to go build to no avail:
go build -x -gcflags="-I C:/different/include -L C:/different-path/lib -lfoobar"
go build -x -ccflags="-I C:/different/include" -ldflags="-L C:/different-path/lib -lfoobar"
With the -x argument I see the printout of flags and they don't include the ones I am setting on the command line. Perhaps the #cgo CFLAGS/LDFLAGS statements at the top of the external go package squash what I am telling it to use...

You can do this by setting the CGO_CPPFLAGS and CGO_LDFLAGS environment variables.
For example, on my MacBook, Homebrew is installed in ~/.homebrew (instead of /usr/local), so when I try to go get packages with native bindings they can't find the headers and libs.
To fix that I added these two lines to my ~/.zshenv file:
export CGO_CPPFLAGS="-I $BREW_HOME/include"
export CGO_LDFLAGS="-L $BREW_HOME/lib"

This is kind of the role filled by #cgo pkgconfig: foobar. If the library had been written that way, it would pick up the correct paths from foobar's pkgconfig definition.
I realise its not a direct answer to the question, and that pkgconfig isn't exactly a native windows tool... I'd be interested to hear if any other solutions exist.

Related

Atempting to allow cgo to build on both Linux and Windows, get "build constraints exclude all Go files"

I am working on a smallish Go application that uses Cgo. I'm working on it on a Linux VM, and Linux is the main target environment. However, I have a need to also create a Windows executable. Normally, cross-compiling Go is trivial, but Cgo adds some complications. I've noticed at least two issues, but I'll only ask about the first problem here.
My application only has a single source file that requires Cgo, and the only difference between the Windows and Linux build is the lib path.
This is what I have so far for the beginning of the Cgo header. After this are some include file references:
/*
#cgo CFLAGS: -g -Wall -I${SRCDIR}/../include/v6.21.0
#cgo linux LDFLAGS: -L${SRCDIR}/../lib/linux/v6.21.0 -lvibesimple -lcurl -lssl -lvibecrypto -lvibeictk -lvibeserver
#cgo windows LDFLAGS: -L${SRCDIR}/../lib/windows/v6.21.0 -lvibesimple -lcurl -lssl -lvibecrypto -lvibeictk -lvibeserver
When I build this on Linux, or with GOOS=linux, it works fine.
When I build this for Windows, I get this:
$ GOOS=windows go build -o target/dist/windows-amd64
package voltagems
imports voltagems/app
imports voltagems/handlers
imports voltagems/voltagefuncs: build constraints exclude all Go files in /home/<uid>/git/voltagego/voltagefuncs
I know that I can create files ending in "_linux.go" or "_windows.go", but that would be painful. That would mean duplicating the entire source file, and having to maintain both copies.

Include libsodium using cgo in go project fails

I am trying to include the libsodium into my Go project. For that, I've copied the repo inside my project
// #cgo CFLAGS: -I/mypath/libsodium/src/libsodium/include/sodium
// #include <stdlib.h>
// #include "crypto_sign_ed25519.h"
import "C"
When trying to build the project I get the following error:
/tmp/go-build/cgo-gcc-prolog:53: undefined reference to `crypto_sign_ed25519_pk_to_curve25519'
collect2: error: ld returned 1 exit status
The file can be found but the error is there.
I've also tried to reference the '.c' file as well as to copy the crypto_sign_ed25519.h into the src folder but it does not work.
My question is do I have to add LDFLAGS and therefore generate a .so file from the library or that is not needed and there is another possible way of doing it?
UPDATE: I've achieved to make it running by installing the library on my local ubuntu:
$ ./configure
$ make && make check
$ sudo make install
and adding
// #cgo LDFLAGS: -L/usr/local/lib -lsodium
But how can I do it without adding the local path?
You indeed need to link the library, the headers themselves are only the interface to the library and don't link the actual libsodium code to your binary.
Assuming libsodium ships a pkg-config file (it seems to be the case), you can use something like
// #cgo pkg-config: libsodium
// #include "crypto_sign_ed25519.h"
See https://golang.org/cmd/cgo/ for more information about pkg-config support.
To see what cflags/libs you'd be getting (so what cgo will use), run:
pkg-config --cflags --libs libsodium
After manually installing a library on Linux, you have to type ldconfig so that the linker becomes aware of it.
Also, in order to get libsodium prototypes, you should simply include <sodium.h> not <sodium/crypto_sign_ed25519.h> (not meant to be included directly), and call sodium_init() before any other function so that internal data structures are properly initialized.
See how this is done in existing bindings for Go: https://github.com/jamesruan/sodium/blob/master/core.go
You may want to use these bindings instead of reinventing your own. If they are missing some of the functions you need, their maintainers will probably be happy to accept your pull requests.
The two main Go bindings for libsodium that I am aware of are sodium and libsodium-go.

Preprocessor flag to detect CGO build?

In a c file that's beside my go file and is compiled together via CGO, I'd like to check via preprocessor whether it's being compiled via go or not. I'd like to do this because, for example, I'd like to protect #include _cgo_export.h with #ifdef flags, since such header exists solely during compilation and I don't want my editor to warn about its absence.
From the documentation just do:
// #cgo CFLAGS: -DWHATEVER_YOU_WANT_TO_INDICATE_CGO=1
import "C"
(or just -D FOO if you don't want a value) or set CGO_CFLAGS in the environment.
You can see what is happening behind the scenes with go build -x.
For me it shows -D GOOS_freebsd -D GOARCH_amd64 while compiling the cgo generated _cgo_defun.c file, but only for that file and not to my own *.c files. So I don't think there are any usable predefined preprocessor flags (and the documentation also doesn't mention any).

How to link to libraries using gcc

I installed some encryption software called libntru.
The header files are installed in /usr/include/libntru and the file I would like to include from this directory is ntru.h. The compiled library is installed to /usr/lib/libntru.so.
In my makefile, I use gcc's -L and -l flags to link to the library as such -L/usr/lib -lntru, however in my project, I get a compiler error at the line #include <ntru.h>.
How can I link to this library? Thanks in advance for any help.
Check on the instructions with the software; there's at least a chance you're supposed to write one of:
#include <libntru/ntru.h>
#include "libntru/ntru.h"
If that's the case, you won't need to specify anything on the command line to find the headers (no -I option). If you're supposed to write just:
#include <ntru.h>
#include "ntru.h"
Then you need to add -I/usr/include/libntru to the command line.
Note that you probably don't need -L/usr/lib on the command line; the compiler will normally look there anyway, but you will need the -lntru option to specify the library itself, of course.

Using gomake/gotest for a package with external dependencies

I have the following package Makefile:
include ${GOROOT}/src/Make.inc
TARG=gorilla.googlecode.com/hg/gorilla/mux
GOFILES=\
doc.go\
mux.go\
DEPS=\
gorilla.googlecode.com/hg/gorilla/context
include ${GOROOT}/src/Make.pkg
I changed TARG and DEPS today to point to the Google code repository as shown above, following this advice.
The problem is: I can goinstall the package and it will install the dependency, but I cannot use gotest or gomake anymore; I get the following error (using Go r59):
moraes#yukon:~/dev/repos/gorilla/gorilla/mux$ gotest
rm -f _test/gorilla.googlecode.com/hg/gorilla/mux.a
make -C gorilla.googlecode.com/hg/gorilla/context install
make: *** gorilla.googlecode.com/hg/gorilla/context: No such file or directory. Stop.
make: *** [gorilla.googlecode.com/hg/gorilla/context.make] Error 2
gotest: "/home/moraes/dev/repos/go/go.r59/bin/gomake testpackage GOTESTFILES=mux_test.go" failed: exit status 2
I tried goinstalling the dependency first (goinstall gorilla.googlecode.com/hg/gorilla/context), and it installs correctly in $GOROOT/pkg but the same error occurs with gotest/gomake.
I think I'm missing something pretty basic. How should I proceed to use gomake/gotest with the Makefile above? Is this supposed to work at all, or should I use a different one for development?
goinstall doesn't use the Makefile at all. Instead, it will parse dependencies directly from your .go files.
To specify dependencies, annotate your import lines with a "normalised" reference to the dependency. eg.
import (
gorilla_context "gorilla.googlecode.com/hg/gorilla/context"
...
gomake doesn't automatically resolve dependencies though, so you'll have to manually install them.
Similarly, for installing cgo source with goinstall, you can specify CFLAGS and LDFLAGS in comment directives. eg.
/*
#cgo CFLAGS: -I/usr/local/include
#cgo LDFLAGS: -L/usr/local/lib -lzmq
#include <zmq.h>
*/
import "C"
I think the Makefile is trying to find the file gorilla.googlecode.com/hg/gorilla/context in the current directory. Also, why would you want to specify it in a make file as opposed to importing it from within the Source?

Resources