Stringer tool complains about wrong archive header - go

I am trying to use go generate/stringer (golang.org/x/tools/cmd/stringer) to generate String() methods on enums. I have problems, which I believe, are because of slightly different format of .a packages on different systems. I have this file:
package main
import (
"math/rand"
)
//go:generate stringer -type=Foo
type Foo int;
const (
FooPrime Foo = iota
FooBis
)
func main() {
//Just use rand anywhere, otherwise we get a compiler error
rand.Seed(1)
}
Now if I run go generate example.go on my machine everything is all right: foo_string.go is created. However, on a test machine I get:
stringer: checking package: example.go:4:2: could not import math/rand (reading export data: /usr/lib64/go/pkg/linux_amd64/math/rand.a: go archive is missing __.PKGDEF)
Now, after some digging in the code I think that I get this error, because on my machine rand.a has the following header:
!<arch>
__.PKGDEF 0 0 0 644 2051
`
while on test machine it has the following header:
!<arch>
__.PKGDEF/ 0 399 399 100644 2051
`
I think that the crucial difference is slash after PKGDEFF. gcimporter refuses to process .a file, if it doesn't have __.PKGDEF header.
To check this, I edited manually gcimporter/exportdata.go and changed one of the line from this:
if name != "__.PKGDEF"
to this:
if name != "__.PKGDEF" && name != "__.PKGDEF\"
After this change (and compiling and installing everything) I was able to run go generate on example.go.
My questions are: why do I get this problem and how do I get rid of it (other then manually editing external library)?

What I can see from the spec for openSUSE's packaging they are disabling reinstallation of the standard library at updates. __.PKGDEF is a Go specific informational section, and some linker OpenSUSE has used has simply produced incompatible output.
There's nothing you can do except install a healthy Go from the official source.

Related

Every "go" command leads to a panic from a certain main.go

I've noticed that every go command has stopped working, due to a panic from a main.go in a particular module:
> go env
panic: required key FOO missing value
goroutine 1 [running]:
github.com/kelseyhightower/envconfig.MustProcess(...)
/Users/kurtpeek/go/pkg/mod/github.com/kelseyhightower/envconfig#v1.4.0/envconfig.go:233
main.main()
/Users/kurtpeek/go/pkg/mod/github.com/myorg/mymodule/go#v0.0.0-20210129234103-92f90e2df5c0/main.go:13 +0x314
where the 'offending' main go is similar to
package main
import (
"github.com/kelseyhightower/envconfig"
"github.pie.apple.com/someorg/somemodule/config"
)
func main() {
cfg := &config.Config{}
envconfig.MustProcess("", cfg)
}
I have no idea why a go env command should fail for this reason?
Your module is called github.com/myorg/mymodule/go, which means that the installed binary is called "go" (after the last path segment). This binary likely shadows the go tool depending on how your PATH is configured.
I suggest you change the module path to avoid this problem.
You might try to reinstall go as it seems that somehow the binary for go env command is replaced by a binary you were potentially trying to compile, possible reason could be you built the program in the directory containing the go tools. I recommend reinstalling go

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 do you add an include directory to Go/LiteIDE?

I'm attempting to use LiteIDE to run the program:
// cudatest
package cudatest
import (
"fmt"
"github.com/barnex/cuda5/cu"
)
func main() {
fmt.Println("Hello, your GPU is:", cu.Device(0).Name())
}
All I get is:
c:/go/bin/go.exe build -i [C:/godev]
# github.com/barnex/cuda5/cu
c:\GoDev\src\github.com\barnex\cuda5\cu\context.go:5:18: fatal error: cuda.h: No such file or directory
//#include <cuda.h>
^
compilation terminated.
Error: process exited with code 2.
I have the latest CUDA SDK from NVIDIA installed. What do I need to do in order to make the Go compiler see it?
It looks like your C compiler doesn't know what directory has the cuda header file. You can tell go to give the C compiler extra options using the CGO_CPPFLAGS environment variable. You probably want to set it to something like
CGO_CPPFLAGS="-isystem /path/to/dir/with/cuda/header/in/it"
See https://golang.org/cmd/cgo/

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