Using binary packages directly - go

I'm writing a library in Go. I'm planning to distribute it, and with a main requirement of 'without source codes'.
For testing, I have created two workspaces like following,
WS1
bin/
pkg/linux_amd64/lib.a
src/lib/src.go
WS2
bin/
pkg/
src/main/main.go
My first workspace (WS1) is the actual dummy library, which has some utility functions. Second workspace (WS2) has main function which uses the package (lib.a) from WS1.
Everything was working good until I remove the sources from WS1. If I remove the directory /lib/src.go in WS1, I'm getting the following error during go build,
main.go:5:2: cannot find package "lib" in any of:
/usr/local/go/src/pkg/lib (from $GOROOT) ../Testing/ws1/src/lib
(from $GOPATH)
The above message indicates us that we should keep the source files as well. Precompiled binary packages alone cannot be used directly.
Based on few suggestions online, we may keep some dummy sources with timestamp value lesser than binary packages' timestamp. But, this doesn't seems to be a feasible solution for us. What happens if timestamp of the dummy sources got updated unfortunately?
I have seen similar issue discussed here,
https://github.com/golang/go/issues/2775
My Questions:
Distributing the sources is the only possibility in Golang?
Why Go is not providing a provision for using '.a' files directly?
If keeping the source is mandatory for Go, why this small thing is
not mentioned anywhere in Go? (or) Am I missing something here?
Thanks in advance for your help guys!

The Go compiler just needs the .a files. If you ship them anybody will be able to use your package without the source code.
BUT your users will have to invoke the compiler (e.g. 6g, not the go tool) manually. If you ship a myfoo.a file and a dummy source myfoo.go containing just package myfoo and the timestamp of myfoo.a is newer than that of myfoo.go (and you put everything in place) you may use the go tool.
Update: Newer version of the go tool detect deleted files and require all files (possibly empty) with the proper filenames and older timestamps in the src folder.
Managing a timestamp should not be a dealbreaker.
Don't get fooled that the go tool is Go: It is a dead convenient tool to build, test, get, whatever your Go code, but it is neither the language nor the compiler nor the linker.
BTW: There is really no point in not distributing the sources.

The binary-only packages will be available in go1.7 (August 2016) - https://tip.golang.org/doc/go1.7
This release adds experimental, minimal support for building programs using binary-only packages, packages distributed in binary form without the corresponding source code. This feature is needed in some commercial settings but is not intended to be fully integrated into the rest of the toolchain. For example, tools that assume access to complete source code will not work with such packages, and there are no plans to support such packages in the “go get” command.
The proposal is at https://github.com/golang/proposal/blob/master/design/2775-binary-only-packages.md , https://tip.golang.org/pkg/go/build/#hdr-Binary_Only_Packages has more information about the new feature.

The binary-only packages is supported in go 1.7 now.
You can only provide .a files and fake go files without source code to distribute it now.
Here is a detailed example and a script of Go1.7 binary package generator.
myframework/frameImplement.go
package myframework
import "fmt"
func Hello(name string) string {
return fmt.Sprintf("Hello, %s!", name)
}
main/main.go
package main
import (
"fmt"
"golang-binary-package-generator/myframework"
)
func main() {
fmt.Println(" start program ")
fmt.Println(" print program :", myframework.Hello("print something now"))
}
If I want to hide my framework's source code, just build it with go build -i -o $GOPATH/pkg/framework.a, then modify your source code to
//go:binary-only-package
package framework
//you can add function prototype here for go doc etc, but no necessary.
, which you can use my binary package generator(script) to help you.

The decision to drop the feature:
cmd/go: drop support for binary-only packages

Related

Golang: Can't use syscall.EpollCreate

I am trying to port a program from C to Go, so using a lot of stuff from the syscall package is required.
I am trying to use https://pkg.go.dev/syscall#EpollCreate, but VSCode refuses to autocomplete it for me or recognize that it is a defined function. FWIW, I get autocomplete for many other things in the syscall package.
My project is using Go 1.14. I am unsure how to tell what version of Go things were introduced in, so I am wondering if that is my problem.
I tried creating a dummy project that uses Go 1.17 and still no luck.
I am writing the code on a Mac, but it will eventually be compiled for ARM Linux, if that matters.
So is this a Go problem or a VSCode problem? Both? Neither?
Sample dummy project:
go.mod:
module epoll-noodle
go 1.14
main.go:
package main
import (
"syscall"
)
func main() {
syscall.EpollCreate(4)
}
It turns out that if you are developing for a platform that differs from your own, some things may be unsupported (like EpollCreate in this case, as #JimB said). The Go extension does let you change your env vars though, so you can work around this in VSCode. In your extensions settings, put something like:
{
"go.toolsEnvVars": {"GOOS" : "linux"}
}
and your project will be built for that OS.
The settings file can be found in the .vscode folder in the root of your project. If there isn't one, you can go to the Go extension in VSCode and fiddle with some settings (for the workspace, not the user) and it will create one for you. Then edit as necessary.
See also: https://github.com/microsoft/vscode-go/issues/632

How to annotate symbols that they are shared among other projects?

Suppose I have a Go project which act as shared library in another Go project. How do I markup Go symbols (consts, structs, vars) that they are used outside this project?
I guess the underlying problem is that I have a hard time knowing which code uses said symbols.
Please note: This is not about semantic versioning, of which I am very well aware and which I use. I know Semver can help to identify breaking changes.
Instead, this is about finding out if I actually break one of my own projects (compared to: This symbol should be unexported or used outside the package). I am thinking of some sort of annotation which don't exist in Go.
As an aside, IntelliJ doesn't know either and marks those symbols as "Unnecessarily exported". Maybe an IntelliJ-centric solution could suffice.
To illustrate my problem:
package sharedlib
import "time"
// MyFavoriteTimeFormat is a blablabla...
const MyFavoriteTimeFormat = Time.RFC3339
package dependingproject
import "github.com/thething/sharedlib"
import "time"
func convertToString(timestamp time.Time) string {
return timestamp.Format(sharedlib.MyFavoriteTimeFormat)
}
When I happily rename MyFavoriteTimeFormate and release it, the code will break in the depending project when it updates the dependency.
Don't export anything until some other package needs it. If another package needs something, then do export, and then you'll know that if something is exported, it is because it is used outside of the package. And do not do breaking changes on exported identifiers. If you really must, then increment major version. Using go modules, that won't break existing other packages, they will continue to use the old version.
If your module is broken down into multiple packages (because it is "big"), and you wish to export something solely for the other packages of your module, then use the internal package concept, so it will still be "unexported" (unimportable) to other modules. For details, see Can I develop a go package in multiple source directories?

go module didn't download cgo soft links of dynamic library correctly

The environment is ubuntu 16.04 64bit, go version go1.12 linux/amd64
I am trying to switch my golang project from gopath to gomodule. One of the packages my project imported is using cgo to call ffmpeg, the package have several dynamic ffmpeg libraries, for example, libavcodec.so, libavcodec.so.57, libavcodec.so.57.107.100, the first two files is soft link file
The problem is when I go build my golang project, go module only download libavcodec.so.57.107.100, it didn't download the two soft link file
I tried to go get the package, and successfully get all the libraries including soft link file
I expect go module download all c dynamic libraries files including soft link files, but I didn't get the soft link files
Update: I submitted a issue in github, and seemed that this is intentional, see issue #32050
Go (in modules mode as well as in GOPATH mode) is concerned only with Go source code and will download only Go packages (which might contain C code) but it never installs shared libraries on your system or does other installation work (like creating symlinks).
There is no way you can convince or force the go tool to do what you think it should do.
Install the required shared object files and the necessary symlinks in any other means you find convenient n your system.

Why can't I add a main to my library in golang?

I'm having trouble achieving what should be an easy task. I understand the GitHub model for code organization (ie a library repo and an app repo that consumes the library). I think it's fantastic. But I find often that I want mylib to come bundled with a simple executable in a single main.go file. The main.go should be package main and should import mylib. In other words, it should be an exact documentation of how to build an app that consumes this library.
My point is, since it is often enough convenient to provide a simple command line interface that wraps your library, there should be an easy way to do this without having to make another repo, and golang should help.
I'd like something like the following:
$GOPATH/src/github.com/me/mylib
mylib.go
mylib_also.go
main.go
where mylib is the library (package mylib) and main.go is package main and on running go install it generates bin/mylib and pkg/mylib.a.
Either main.go should import "github.com/me/mylib" (if I do that now, I get cyclical import error) or go would understand what's happening since this feature should be built in and the one main.go in the repo generates the exec. Probably requiring the import (and dropping the cyclical error) is the better way.
Right now, I have to do
$GOPATH/src/github.com/me/mylib
mylib/
mylib.go
main.go
So I have to import github.com/me/mylib/mylib which is ridiculous.
In sum, go install should allow the special case of a package and a main which imports the package and provides a simple cli that demonstrates the packages API. The GitHub model promotes two repos, but it should be easy to do simple clis in one!
You can't have multiple packages per folder. Go operates on a package-level, not a file level.
Convention in this case—a binary that consumes your library—is to create a cmd folder with your package main - i.e. as per https://github.com/bradfitz/camlistore/tree/master/cmd or https://github.com/boltdb/bolt
In your case this would be:
$GOPATH/src/github.com/me/mylib
mylib/
mylib.go
README.md
cmd/
your-lib-tool/
main.go
If you just want a convenient, little wrapper, just some command line interface to your lib for demonstration purpose and it is okay if the main program is not built on go get (and not during simple go build and go install) but you are okay by running it via go run main.go or building it manually e.g. with 6g: Just use a build tag (see http://golang.org/pkg/go/build/#hdr-Build_Constraints) in main.go:
// +build ignore
and you won't need a different folder or repo.

Tracing source to binary

I'm trying to understand the way a particular package fits into a project I'm working on. I believe only a portion of this package actually makes it into the binary of the project, and I need to find out exactly which parts. Library functions from this package are called from many other places (i.e. several other packages depend on it).
I plan to build the project and distribute it. Is the only way to determine which source->binary files I'll distribute by looking at all of the headers in my dependent packages? Or is there a more clever way to approach this?
Thanks in advance,
You haven't given us much information to go on, but here's a method that will work: remove parts of the package and see if the project will still compile.
Use nm to unpack a static lib. This will list all the files and methods included in the lib.
You could also try using strings.
This displays strings that are defined in the binary.
Look through your source and see if the strings you define are in the library.
Something like gprof could also be used to see which methods are called by your executable.

Resources