I want to implement dll forwarding(or dll proxy)
In mingw, I can use cpp source with .def file, like gcc -shared -o test.dll functions.def test.cpp
But I don't know how to implement it in golang
I know what to do to solve this problem.
use the extldflags
First Way:
compile the .def file to .exp file
dlltool --def functions.def --output-exp evildll.exp
compile main.go
main.go
package main
import "C"
func main() {
// Need a main function to make CGO compile package as C shared library
}
use command go build -buildmode=c-shared -o exportgo.dll -ldflags="-extldflags=-Wl,C:/Users/Akkuman/Desktop/go-dll-proxy/evildll.exp"
then you can get the dll
Second Way
use command go build -buildmode=c-shared -o exportgo.dll -ldflags="-extldflags=-Wl,C:/Users/Akkuman/Desktop/go-dll-proxy/functions.def"
then you can get the dll, but with a additional export function
Related
In my project, I am using callbacks for bi-directional calls from C into go and vice versa using CGO. I resolved the issue of circular dependencies by compiling the C part into a library, then compiling the go part into a library, then a final linker pass puts it all together. This is working fine when not using go modules. Go source files are listed on the command line explicitly. I have been told that as of go 1.12 "this is not the right way to do it".
As the project has grown, I now want to use go modules. Unfortunately, this changes the behaviour of the go compiler. It now wants to resolve external dependencies and implicitly includes them in the output file. Due to the circular dependency, it now always ends up with an undefined reference or multiple definitions. How to resolve circular dependencies when using cgo and go modules "the right way"?
This is a minimal example to illustrate the problem. Remove the file-name "hello.go" from the call to go in the Makefile to see how it falls apart.
This is the error message:
hello.c:3: multiple definition of `c_hello'; $WORK/b001/_cgo_hello.o:/tmp/go-build/hello.c:3: first defined here
Makefile:
libchello.a: Makefile hello.c
gcc -fPIC -c -o chello.o hello.c
ar r libchello.a chello.o
libgohello.a: Makefile hello.go libchello.a
env CGO_LDFLAGS=libchello.a go build -buildmode=c-archive -o libgohello.a hello.go
main: Makefile main.c libgohello.a libchello.a
gcc -o main main.c libchello.a libgohello.a -pthread
.PHONY: clean
clean:
rm -f main *.a *.o
echo "extern void go_hello();" > libgohello.h
hello.go:
package main
/*
extern void c_hello();
*/
import "C"
import "time"
import "fmt"
//export go_hello
func go_hello() {
fmt.Printf("Hello from go\n")
time.Sleep(1 * time.Second)
C.c_hello()
}
func main() {}
libgohello.h:
extern void go_hello();
hello.c:
#include "libgohello.h"
#include <stdio.h>
void c_hello() {
printf("Hello from c\n");
go_hello();
}
main.c:
void c_hello();
int main() {
c_hello();
}
go.mod:
module hehoe.de/cgocircular
If you look at the verbose output from the go build command, you will see that when compiling the directory as a complete go package, the main.c file is being included as part of the C code used in hello.go.
From the documentation:
When the Go tool sees that one or more Go files use the special import "C", it will look for other non-Go files in the directory and compile them as part of the Go package
The easiest solution here is to separate the main C and Go packages, so that they don't interfere with each other's build process. Testing this out, removing the main.c file will build libchello.a and libgohello.a, and then adding it back in will complete the build of main.
When use arm-linux-gnueabi-gcc for cross compile. GOOS only support linux and do not support android.
CGO_ENABLED=1 CGO_CFLAGS CC=arm-linux-gnueabi-gcc GOOS=linux GOARCH=arm go build -o hello .
# After build generated hello file
file hello
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, BuildID[sha1]=038c80350b7a0c9e72b10021c66c31c2dbb4df2c, for GNU/Linux 3.2.0, not stripped
As you can see the output file hello with dynamically linked, interpreter /lib/ld-linux.so.3. It can not run in android platform.
./hello
/system/bin/sh: ./hello: No such file or directory
In Android the interpreter should be /system/bin/linker. My question is how to specific dynamic linker with cgo?
As i searched in there. the gcc has params like gcc -o test test.c -Wall -Wl,--dynamic-linker=/system/bin/linker.
you can enable cgo and send these flags to cgo from the comment above import "C" statement:
package main
/*
#cgo LDFLAGS: --dynamic-linker=/lib/ld-linux.so.3
*/
import "C"
func main() {
}
Tell me if this work
Finally i used NDK build for android.
Is it possible?
I have the following Go function I'd like to call from a C program:
// package name: test
package main
import "C"
//export Start
func Start() {
println("Hello world")
}
func main() {
}
I'm using the following command to build the archive
go build -buildmode=c-archive -o test.a main.go
Using gcc I can get this C program working:
#include <stdio.h>
#include "test.h"
int main() {
Start();
return 0;
}
I'm using the following command to build the executable:
gcc main.c sdlgotest.a -o main -lpthread
This all works fine for amd64, but I'd like to use this archive in a aarch64 targed development environment (using libtransistor)
libtransistor build system uses LLVM but it has it's own set of standard includes (libc, etc.) and it doesn't use glibc.
So when I'm trying to get libtransistor to link my archive I get the following errors:
/usr/lib/llvm-5.0/bin/ld.lld: error: undefined symbol: stderr
>>> referenced by gcc_libinit.c:29
>>> 000006.o:(x_cgo_sys_thread_create) in archive ./sdlgotest.a
/usr/lib/llvm-5.0/bin/ld.lld: error: undefined symbol: stderr
>>> referenced by gcc_libinit.c:29
>>> 000006.o:(x_cgo_sys_thread_create) in archive ./sdlgotest.a
libtransistor by the way is compiling the code with flags like this:
-nostdlib -nostdlibinc -isystem /opt/libtransistor/include/
So I guess the problem is that the linker can't resolve those glibc symbols.
Is there a way to compile the Go runtime without those glibc symbols so I can use the archive like I intend to? (without relying on GCC toolchain or glibc)
From the docs:
The default C and C++ compilers may be changed by the CC and CXX environment variables, respectively; those environment variables may include command line options.
So I'd try something like
$ CC=clang go build -buildmode=c-archive -o test.a main.go
and see what happens.
Run go env and see the list of env parameters set to go. You can change certain parameters based on what you need.
Following are some of the samples that I have used to build a shared dll from go program.
GOARCH=386 GOOS=windows CGO_ENABLED=1 GOPATH=`pwd` CC=i686-w64-mingw32-gcc go build -o go-shared-lib.dll -buildmode=c-shared go-shared-libs
GOARCH=amd64 GOOS=windows CGO_ENABLED=1 GOPATH=`pwd` CC=x86_64-w64-mingw32-gcc go build -o go-shared-lib.dll -buildmode=c-shared go-shared-libs
I'm trying to cross compile (from Arch Linux to Windows) a go binary with the openal library statically linked.
I use MinGW to cross compile to Windows and to MinGW package I have install and intend to use to link the static libary is mingw-w64-openal.
My build command looks like this:
CC='i686-w64-mingw32-gcc -fno-stack-protector -D_FORTIFY_SOURCE=0 -lssp' GOOS=windows CGO_ENABLED=1 GOARCH=386 go build --ldflags '--extldflags "-static"' -v -o bin/game.exe -tags='deploy' game.go
The .go files (linked below) that is using the library has the following cgo code to lookup the static library for MinGW to use:
#cgo windows LDFLAGS: /usr/i686-w64-mingw32/lib/libOpenAL32.dll.a
I get no errors during compilation but when I try run the binary file on windows I get the typical The program can't start because OpenAL32.dll is missing error. I want a completely portable executable so redistributing the .dll with the executable won't do.
The go openal package that I've modified to compile to windows:
https://github.com/golang/mobile/blob/master/exp/audio/al/al_notandroid.go
https://github.com/golang/mobile/blob/master/exp/audio/al/alc_notandroid.go
My Go package includes a .c file that uses a library which needs certain CFLAGS set. On the command line to "go install" I can specify CGO_CFLAGS with the needed flags, and everything works. However, I would like to make it so that someone can "go get" my package and build it without passing any extra command line arguments.
Does the Go packaging system provide a place where I could put some config like this, to specify some arguments that are always needed when go installing a package?
(I'm aware of doing #cgo CFLAGS: directives in Go source files, but recall that in my package I have a .c source file so need the CGO_CFLAGS setting to the overall build process)
cgo extracts your #cgo CFLAGS: to an environment variable during build (pass "-x" flag to go build). If you go install -x you see that it honors your cflags/ldflags specified in your Go library. In other words, it should work to just specify them in your Go files.
In order to use any of your C functions you still have to mix some cgo into your .go files, in those files just declare your flags, for example:
test.go:
package main
import "fmt"
/*
#cgo CFLAGS: -DTEST
#include <stdio.h>
extern void ACFunction();
*/
import "C"
//export AGoFunction
func AGoFunction() {
fmt.Println("AGoFunction()")
}
func main() {
C.ACFunction()
}
test.c:
#include "_cgo_export.h"
void ACFunction() {
#ifdef TEST
printf("ACFunction()\n");
#endif
AGoFunction();
}
Putting these in the same directory will make go build pickup the flags defined in test.go and apply them when building test.c.