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.

Reply via email to