Cross compile net/http for distribution - go

I have build the following code in a docker container with the following architecture:
cat /proc/version
Linux version 3.16.7-tinycore64 (root#064f0e1ce709) (gcc version 4.7.2 (Debian 4.7.2-5) ) #1 SMP Tue Dec 16 23:03:39 UTC 2014
package main
import "fmt"
func main() {
fmt.Println("Hello")
}
The binary distributed, runs with no problem on a busybox container, with the same architecture without installing golang.
The problem
When I do the same for the following code:
package main
import (
"fmt"
"net/http"
)
const (
port = ":80"
)
var calls = 0
func HelloWorld(w http.ResponseWriter, r *http.Request) {
calls++
fmt.Fprintf(w, "Hello, world! You have called me %d times.\n", calls)
}
func init() {
fmt.Printf("Started server at http://localhost%v.\n", port)
http.HandleFunc("/", HelloWorld)
http.ListenAndServe(port, nil)
}
func main() {}
Then I get:
ash: ./hello_world: not found
I might be missing some dependencies - like "net/http"?
But I thought the go build would build all into the binaries.
This is for both go build & go install.
Any idea?

The answer is most probably the one described in this article.
Some critical parts of the standard library use CGO [...] if you cross-compile Go to Darwin or Linux your programs won’t use the system DNS resolver. They also can’t use the native host certificate store. They also can’t look up the user’s home directory, either.
And CGO links against some standard system interfaces by default, dynamically.
The article suggests using gonative to fix the problem. If that's not your cup of tea, some people suggest using:
go build -ldflags "-linkmode external -extldflags -static"
Also read: https://groups.google.com/d/topic/golang-nuts/H-NTwhQVp-8/discussion

I think you need to disable cgo and build with netgo flag :
The net package requires cgo by default because the host operating
system must in general mediate network call setup. On some systems,
though, it is possible to use the network without cgo, and useful to
do so, for instance to avoid dynamic linking. The new build tag netgo
(off by default) allows the construction of a net package in pure Go
on those systems where it is possible.
The netgo tag requires version 1.2 and above.

Related

Golang: using Windows 10 API / UWP / System.WindowsRuntime?

Using syscall in Go how can I call the UWP APIs within Windows 10? I have seen and tried many win32 examples, but when I tried using System.WindowsRuntime.dll it was a no-go; specifically, I received:
panic: Failed to load System.WindowsRuntime.dll: The specified module could not be found.
(this was at runtime, the binary built fine)
I tried building both with a standard go build as well as
go build -ldflags="-H windows"
example code:
var(
windowsRuntime = syscall.NewLazyDLL("System.WindowsRuntime.dll")
getDiskFreeSpace = windowsRuntime.NewProc("GetDiskFreeSpace")
)
Note: Other variants tried:
windowsRuntime = syscall.NewLazyDLL("System.Runtime.WindowsRuntime.dll")
&
windowsRuntime = syscall.NewLazyDLL("WindowsRuntime.dll")
Anyone been able to get this running or have any advice on the matter?
As always, greatly appreciated!!
Create a file like this:
//go:generate mkwinsyscall -output zfree.go free.go
//sys getDiskFreeSpace(pathName string, sectorsPerCluster *int, bytesPerSector *int, freeClusters *int, numberOfClusters *int) (err error) = GetDiskFreeSpaceA
package main
func main() {
var bytesPerSector, freeClusters, numberOfClusters, sectorsPerCluster int
getDiskFreeSpace(
`C:\`,
&sectorsPerCluster,
&bytesPerSector,
&freeClusters,
&numberOfClusters,
)
println("bytesPerSector", bytesPerSector)
println("freeClusters", freeClusters)
println("numberOfClusters", numberOfClusters)
println("sectorsPerCluster", sectorsPerCluster)
}
Then build:
go generate
go mod init free
go mod tidy
go build
Result:
bytesPerSector 512
freeClusters 12511186
numberOfClusters 25434879
sectorsPerCluster 8
https://github.com/golang/sys/tree/master/windows/mkwinsyscall
I have no idea where you found "System.WindowsRuntime.dll" because as far as I can tell, it doesn't exist (unless you manually made a DLL named that).
As for System.Runtime.WindowsRuntime.dll: it's part of .NET Framework, not Windows, and it is a managed DLL. You cannot load such DLLs using syscall.NewLazyDLL. What's more, that DLL doesn't really contain any Windows APIs - just glue for .NET to be able to work with them.
You're probably looking for functions like RoGetActivationFactory in combase.dll.

How to detect $GOHOSTOS and $GOHOSTARCH at runtime?

How do I detect the value of $GOHOSTOS and $GOHOSTARCH at runtime on any system a go binary is running? Please note that I want to detect these values even if there is no go compiler installation on a host.
$GOHOSTOS and $GOHOSTARCH ( serve default values for GOOS and GOARCH respectively) are used while building of go programs and do not influence the execution of the run-time system.
GOOS and GOARCH are recorded at compile time and made available by constants runtime.GOOS and runtime.GOARCH.
You may want to check these constants.
Short version, you can't.
Long version, you can create a build script that embeds the info in your code, for example:
- main.go:
package main
import (
"fmt"
"runtime"
)
var (
hostOS string
hostArch string
)
func main() {
fmt.Println("runtime values:", runtime.GOOS, runtime.GOARCH)
fmt.Println("build time values:", hostOS, hostArch)
}
- build.sh
#!/bin/sh
# replace main. with whatever package you're using
go build -ldflags "-X main.hostOS=$(go env GOHOSTOS) -X main.hostArch=$(go env GOHOSTARCH)" $*
- output:
$ env GOARCH=386 ./build.sh
$ ./tmp
runtime values: linux 386
build time values: linux amd64

Import issue with docker's libcontainer

When using the docker's libcontainer (specifically the network part), I get an undefined error while building using go build on my project.
import (
"encoding/json"
...
"github.com/docker/libcontainer/network"
)
func SetIP(a Address) (err error) {
...
err = network.SetInterfaceIp(a.Link, a.IP)
....
}
The error itself:
./addresses.go:170: undefined: network.SetInterfaceIp
I've checked inside the library itself and I can find this so called function.
I was building on OSX, which cannot be done when using libcontainer. After using a debian VM the whole project was built correctly.
Kudos to #JimB and #Not_a_Golfer for the hints.

Building and linking dynamically from a go binary

My problem is the following:
I have a go binary on a machine
From that binary I need to compile an external .go file
Once compiled, I need to link the compiled go file into the current binary so I can use the just-compiled go code.
Do you think that's possible ?
I did a few researches and it does not seem to be possible, but I might have overlooked something.
Thanks :)
The first go binary would contain something like
func main() {
// Here I need to compile an external go file (or package) which contains
// The definition of runFoo()
// Once the file/package is compiled and linked I need to call the compiled code
runFoo()
// Continue the execution process normally here
}
The ability to create shared libraries will be in Go 1.5 in August 2015¹.
From "The State of Go" talk by Andrew Gerrand:
Shared libraries
Go 1.5 can produce Go shared libraries that can be consumed by Go
programs.
Build the standard library as shared libraries:
$ go install -buildmode=shared std
Build a "Hello, world" program that links against the shared
libraries:
$ go build -linkshared hello.go
$ ls -l hello
-rwxr-xr-x 1 adg adg 13926 May 26 02:13 hello
Go 1.5 can also build Go programs as C archive files (for static
linking) or shared libraries (for dynamic linking) that can be
consumed by C programs.
[See:] golang.org/s/execmodes
¹ Note, gccgo already had limited support for this for some time, Go 1.5 will be the first time this is supported by the regular go build tools.
Update: It is now possible to do this in mainline Go, see Go Execution Modes
From the Go 1.5 release notes:
For the amd64 architecture only, the compiler has a new option,
-dynlink, that assists dynamic linking by supporting references to Go symbols defined in external shared libraries.
Old Answer (useful discussion of other options):
It is not currently possible to create dynamically linked libraries* in main line Go. There has been some talk about this, so you may see support in the future. However, there is a 3rd party go project called goandroid that needed the same functionality you need, so they maintain patches that should allow you to patch the official Go code base to support the dynamic linked support you are requesting.
If you want to use a the standard Go run-time, I would recommend the one of the following.
Invoke your Go program from your other program, and communicate using:
Pipes to communicate
A UNIX domain socket
An mmaped region of shared memory.
That is, create a file on /dev/shm and have both programs mmap it.
The Go mmap library: https://github.com/edsrzf/mmap-go
Each consecutive option will take more effort to setup, be more platform specific, but potentially be more powerful than the previous one.
*Note: That is, DLLs in the Windows world, and .so files in the UNIX/Linux world.
I think go plugins could be also related to this question, they are supported from go version 1.8. It allows you to dynamically link go binaries implementing required interfaces at runtime.
For example your code has a dependency for a logging backend, but you'd like to support several of them and resolve it at runtime, elasticsearch and splunk could fit here.
You might need to have 2 files: es.go and splunk.go which should both contain a struct of type LoggingBackend implementing a method Write(log string).
To create plugins you need to use buildmode plugin during compilation:
go build -buildmode=plugin -o es.so es.go
go build -buildmode=plugin -o splunk.so splunk.go
After that you could pass the needed plugin via command line arguments and load it:
package main
import "plugin"
import "flag"
type LoggingBackend interface {
Write(log string)
}
var (
backend = flag.String("backend", "elasticsearch", "Default logging backend is elasticsearch")
)
func main() {
flag.Parse()
var mode string
switch backend {
case "elasticsearch":
mode = "./es.so"
case "splunk":
mode = "./splunk.so"
default:
fmt.Println("Didn't recognise your backend")
os.Exit(1)
plug, _ := plugin.Open(mod)
loggingBackend, _ := plug.Lookup("LoggingBackend")
logWriter, _ := loggingBackend.(LoggingBackend)
logWriter.Write("Hello world")
}
This is very possible, you can even compile it as a native shared library
go build -buildmode=c-shared goc.go
# file goc
goc: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV),
dynamically linked,
BuildID[sha1]=f841e63ee8e916d7848ac8ee50d9980642b3ad86,
not stripped
nm -D --defined-only ./goc | grep "T"
0004ebe8 T _cgoexp_f88ec80374ab_PrintInt
000a6178 T _cgo_panic
0004e954 T _cgo_sys_thread_start
000a48c8 T _cgo_topofstack
0004e88c T _cgo_wait_runtime_init_done
000a61a4 T crosscall2
0004ebc8 T crosscall_arm1
0004e7b0 T fatalf
00102648 T _fini
0004e544 T _init
0004e76c T PrintInt
0004ebe4 T __stack_chk_fail_local
0004eb5c T x_cgo_free
0004ea60 T x_cgo_init
0004eb24 T x_cgo_malloc
0004e8e0 T x_cgo_notify_runtime_init_done
0004eb14 T x_cgo_setenv
0004e820 T x_cgo_sys_thread_create
0004eb64 T x_cgo_thread_start
0004eb20 T x_cgo_unsetenv
like so (tested on go 1.5.1 linux/arm)
goc.go:
package main
import (
"C"
"fmt"
)
//export PrintInt
func PrintInt(x int) {
fmt.Println(x)
}
// http://stackoverflow.com/questions/32215509/using-go-code-in-an-existing-c-project
// go build -buildmode=c-archive goc.go
// go build -buildmode=c-shared goc.go
// https://groups.google.com/forum/#!topic/golang-nuts/1oELh6joLQg
// Trying it on windows/amd64, looks like it isn't supported yet. Is this planned for the 1.5 release?
// It will not be in the 1.5 release.
// It would be nice if somebody worked on it for 1.6.
// https://golang.org/s/execmodes
// http://stackoverflow.com/questions/19431296/building-and-linking-dynamically-from-a-go-binary
// go build -linkshared hello.g
// go install -buildmode=shared std
func main() {
fmt.Println("Hello world")
}
Feature promiced since 1.5 :)
http://talks.golang.org/2015/state-of-go-may.slide#23

How can I compile a Go program?

I got Go to compile:
0 known bugs; 0 unexpected bugs
and typed in the "hello world":
package main
import "fmt"
func main() {
fmt.Printf("Hello, 世界\n")
}
Then I tried to compile it, but it wouldn't go:
$ 8c gotest2
gotest2:1 not a function
gotest2:1 syntax error, last name: main
This is going on on Ubuntu Linux on Pentium. Go installed and passed its tests. So where did I go wrong? Can someone tell me where to go from here?
I also tried this program:
package main
import fmt "fmt" // Package implementing formatted I/O.
func main() {
fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n");
}
But this was also no go (must stop making go puns):
$ 8c gotest3.go
gotest3.go:1 not a function
gotest3.go:1 syntax error, last name: main
For Go 1.0+ the correct build command is now: go build
You're using 8c, which is the c compiler. 8g will compile go, and 8l will link.
(Update for Go1.0.x)
The section "Compile packages and dependencies" now list go build as the way to compile in go.
You still call 8g behind the scene, and the parameters you could pass to 8g are now passed with -gcflags.
-gcflags 'arg list'
arguments to pass on each 5g, 6g, or 8g compiler invocation
use go run to run the go program. Here is the output.
$ cat testgo.go
package main
import "fmt"
func main() {
fmt.Printf("Hello, 世界\n")
}
$go run testgo.go
Hello, 世界
To compile Go code, use the following commands:
go tool compile gotest3.go # To create an object file.
go tool link -o gotest3 gotest3.o # To compile from the object file.
chmod +x gotest3 # To apply executable flag.
./gotest3 # To run the binary.

Resources