Hello.
I’m getting rather confused by Go modules and cross-compilation. I think that I have fundamentally misunderstood some module-related concept in the way that I’ve structured my project. Scenario: My project consists of some individual executables that share some common code. The project is (or should be) a coherent, self-contained whole: the executables don’t make much sense individually, and I want to work on / version the supporting code and executables together. In GOPATH times I had something like: <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-1>$ find . -type f <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-2>./src/cmd/foo/main.go <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-3>./src/cmd/bar/main.go <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-4>./src/qux/qux.go <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-5> <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-6>$ cat src/qux/qux.go <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-7>package qux <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-8> <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-9>const Qux = `qux` <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-10> <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-11>$ src/cmd/foo/main.go # bar/main.go is essentially the same <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-12>package main <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-13> <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-14>import "qux" <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-15> <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-16>func main() { <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-17> println(`foo: ` + qux.Qux) <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb1-18>} and the following works as expected, following my understanding that cross-compilation just means setting GOOS and/or GOARCH: <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb2-1>$ uname -sm <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb2-2>Darwin x86_64 <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb2-3> <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb2-4>$ GOPATH=$PWD go install ./... <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb2-5>$ GOOS=linux GOARCH=arm GOPATH=$PWD go install ./... <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb2-6> <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb2-7>$ find bin -type f <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb2-8>bin/linux_arm/foo <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb2-9>bin/linux_arm/bar <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb2-10>bin/foo <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb2-11>bin/bar I’ve tried to migrate this to modules. At a logical level, these binaries plus support code are one unit: if Go doesn’t require me to spread them across separate modules then I’d rather not. First I removed the src directory, then added a go.mod: <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb3-1>$ find . -type f <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb3-2>./cmd/foo/main.go <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb3-3>./cmd/bar/main.go <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb3-4>./qux/qux.go <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb3-5> <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb3-6>$ go mod init foo.com/foobar This baffles me: $ go build foo.com/foobar can't load package: package foo.com/foobar: cannot find module providing package foo.com/foobar $ head -1 go.mod module foo.com/foobar $ go list -m foo.com/foobar # but this finds it perfectly well? although this seems to work: <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb5-1>$ GOBIN=/some/path go install ./... <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb5-2>$ find /some/path -type f <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb5-3>/some/path/foo <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb5-4>/some/path/bar But: now I want to cross-compile: <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb6-1>$ GOOS=linux GOBIN=/some/path go install ./... <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb6-2>go install: cannot install cross-compiled binaries when GOBIN is set <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb6-3>go install: cannot install cross-compiled binaries when GOBIN is set (Why not? If I set GOBIN then I’m saying “please put the binaries over there”. I know that I don’t want them appearing on my Mac’s $PATH: that’s what I’m setting GOBIN. I want to cross-compile some binaries and have them appear in some suitable output directory, so that I can then put them into some disk image or whatever. In any case, if this runs in CI then, cross-compilation or not, I don’t want them appear on the CI box’s PATH at all.) The Internet says that I should use go build instead of go install, and use -o to write the results somewhere: <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb7-1>$ GOOS=linux go build -o /some/path ./... <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb7-2>go build: cannot write multiple packages to non-directory /some/path This seems to work, but I’ve never had to create the output directory before, and it doesn't do the handy creation of per-OS/ARCH subdirectories for me: <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb8-1>$ mkdir /tmp/bin <file:///Users/geoffj/work/git/lai-man/aaarrrggghh.html#cb8-2>$ GOOS=linux go build -o /some/path ./... So: 1. I don’t understand why go build foo.com/foobar fails to find the module if it doesn’t contain some top-level .go file, but go list -m finds it perfectly fine. 2. [How] can I have a module X that provides packages X/Y and X/Z, with no source files in the top-level package X? Or am I not supposed to do this under Go modules? 3. Go modules appear to break my assumption that “I just set GOOS and/or GOARCH to cross-compile, and everything else just works”. The is (was?) one of the biggest benefits of Go for me. I need to cross-compile for Linux (ARM, AArch64 and AMD64) and Windows (AMD64) all the time. 4. Cross-compiled go install to some non-global output directory worked fine in GOPATH days: creating $GOPATH/bin/$GOOS-$GOARCH/*, which seemed perfectly sensible to me. I don’t understand why it’s broken under modules, particularly when I set GOBIN, which I take to mean “Put the binaries here please: I know what I’m doing; please don’t argue”. Or at least have some sort of -yes-really flag to stop the toolchain arguing. At the moment I can see two solutions: 1. Split up my project into individual modules for the shared code (or even every package therein), and each executable. Since none of those components, in this context, makes sense individually, this seems like the tail wagging the dog. 2. Revert to using GOPATH and hope that it never gets removed. History teaches me that this is unwise. but I can’t help thinking that I’m doing something fundamentally wrong. I’ve read the docs, help pages, Wiki et cetera, and found nothing that has helped me. Can someone please put me right? Many thanks, Geoff. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/e454fd42-ffd2-45b4-af1c-c68c21ab4615%40googlegroups.com.