Reputation: 287
I want to distribute packages in binary form without including the source code.
my demo project directory structure is like this:
demo
├── greet
│ ├── greet.go
│ └── hi
│ └── hi.go
├── hello
│ └── hello.go
└── main.go
main.go:
package main
import (
"fmt"
"demo/greet"
"demo/hello"
)
func main(){
fmt.Println("greet:")
greet.Greet()
fmt.Println("hello:")
hello.Hello()
}
greet.go
package greet
import (
"demo/greet/hi"
"fmt"
)
func Greet(){
fmt.Println("Greet Call Hi")
hi.Hi()
}
hi.go
package hi
import "fmt"
func Hi(){
fmt.Println("Hi")
}
hello.go
package hello
import (
"fmt"
"demo/greet"
)
func Hello(){
fmt.Println("hello call greet")
greet.Greet()
}
And I do this:
[user@localhost greet]$ go install -a ./...
It generated greet.a and greet/hi.a in $GOPATH/pkg/linux_amd64/demo. Then I edit hi.go and greet.go.
[user@localhost greet]$ cat greet.go
//go:binary-only-package
package greet
[user@localhost greet]$ cat hi/hi.go
//go:binary-only-package
package hi
Then I run main.go, I get errors:
[user@localhost greet]$ cat hi/hi.go
# command-line-arguments
cannot find package demo/greet/hi (using -importcfg)
/home/user/go/pkg/tool/linux_amd64/link: cannot open file : open : no such file or directory
greet is the package I want to distribute. If I delete package hi, main.go can run well.
demo
├── greet
│ └── greet.go
├── hello
│ └── hello.go
└── main.go
install:
[user@localhost greet]$ go install .
[user@localhost greet]$ vim greet.go
//go:binary-only-package
package greet
[user@localhost greet]$ cd ..
[user@localhost demo]$ go run main.go
greet:
Greet ...
hello:
hello call greet
Greet ...
[user@localhost demo]$
//go:binary-only-package
method can work well)Please help or try to give some ideas how to solve this. Thanks in advance.
Upvotes: 3
Views: 5346
Reputation: 1324248
Note (2019): binary-only packages won't be supported much longer.
As the Go 1.12 (February 2019) release notes states (following CL 152918):
Binary-only packages
Go 1.12 is the last release that will support binary-only packages.
This is detailed in Go issue 28152:
Binary-only packages are increasingly hard to support safely.
There is no guarantee that the compilation of the binary-only package used the same versions of the dependencies that the final link does (and it would probably be too onerous to insist on that).
As a result, the binary-only package may have been compiled using escape analysis results or inline function bodies for dependencies that are no longer accurate.
The result can be silent memory corruption.My memory is that we added binary-only packages originally so that a professor could hand out binary solution sets so that a student who didn't finish lab 2 could still move on to lab 3.
I don't know why else anyone uses them anymore, but they're probably going to break more and more as the compiler gets more sophisticated.
Upvotes: 4
Reputation: 4605
"go run" will compile and run the given main package. So it will check the timestamps of your source files and recompile them if it sees they are newer than the previously compiled libraries (.a files).
It will skip this step for binary only packages. So in this case it will check for any given package that there is just a single source file with the text //go:binary-only-package. That is how the feature is specified. When it sees that, it will use the .a files only.
When you have a subpackage with a source file in it, it seems that files in there end up counting as part of the enclosing root package and the requirement of having just a single source file is broken. So then "go run" will fail. I suspect that is why it doesn't work. And that is why deleting the hi subpackage causes it to work.
The intended use case for binary-only is that you compile your package, and then when you make it available to others you do not include any source files, just the .a files. But for this to work you need to be able to tell other peoples' compilers that your package is just the .a files. For that you need to include just the one source file with the text //go:binary-only-package. And you've basically shown here that for a package that has subpackages, the whole thing must have just a single such source file, there can be only one, you cannot have more of them in the subpackage folders. So just provide the one. That is how the feature works. You provide the .a files and just that one source file to others.
Upvotes: 0