22// Use of this source code is governed by a BSD-style
33// license that can be found in the LICENSE file.
44
5- // A simplistic tool to build Go binaries for multiple platforms.
65package main
76
8- //go:multibuild:output=bin/${TARGET}-${GOOS}-${GOARCH}
9-
107import (
118 "bufio"
129 "bytes"
@@ -67,111 +64,12 @@ func targetList() ([]target, error) {
6764 }), nil
6865}
6966
70- func displayUsageAndExit (self string ) {
71- fmt .Fprintf (os .Stderr , "usage: %s [-o output] [build flags] [packages]\n " , self )
72- fmt .Fprintln (os .Stderr , "multibuild is a thin wrapper around 'go build'." )
73- fmt .Fprintln (os .Stderr , "For documentation on multibuild's configuration, see https://github.com/rburchell/multibuild" )
74- fmt .Fprintln (os .Stderr , "Otherwise, run 'go help build' for command line flags." )
75- fmt .Fprintln (os .Stderr , "" )
76- fmt .Fprintln (os .Stderr , "multibuild-specific options:" )
77- fmt .Fprintln (os .Stderr , " -v: enable verbose logs during building. this will also imply `go build -v`" )
78- fmt .Fprintln (os .Stderr , " --multibuild-configuration: display the multibuild configuration parsed from the package" )
79- fmt .Fprintln (os .Stderr , " --multibuild-targets: list targets that will be built" )
80- os .Exit (0 )
81- }
82-
83- func displayConfigAndExit (opts options ) {
84- fmt .Fprintf (os .Stderr , "//go:multibuild:include=%s\n " , strings .Join (mapSlice (opts .Include , func (f filter ) string { return string (f ) }), "," ))
85- fmt .Fprintf (os .Stderr , "//go:multibuild:exclude=%s\n " , strings .Join (mapSlice (opts .Exclude , func (f filter ) string { return string (f ) }), "," ))
86- fmt .Fprintf (os .Stderr , "//go:multibuild:output=%s\n " , opts .Output )
87- os .Exit (0 )
88- }
89-
90- func displayTargetsAndExit (targets []target ) {
91- for _ , target := range targets {
92- fmt .Fprintln (os .Stderr , target )
93- }
94- os .Exit (0 )
95- }
96-
97- func main () {
98- self := filepath .Base (os .Args [0 ]) // current binary name
99- args := os .Args [1 :] // remaining args
100- expectOutput := false // seen -o, waiting for the rest
101- output := "" // -o or -o=
102- var nonflags []string // non-flag arguments
103- displayConfig := false
104- displayTargets := false
105- verbose := false
106-
107- for _ , arg := range args {
108- switch {
109- case expectOutput :
110- output = arg
111- expectOutput = false
112- case arg == "-o" :
113- expectOutput = true
114- case strings .HasPrefix (arg , "-o=" ):
115- output = strings .TrimPrefix (arg , "-o=" )
116-
117- case arg == "-h" || arg == "--help" :
118- displayUsageAndExit (self )
119- case arg == "-v" :
120- verbose = true
121- case arg == "--multibuild-configuration" :
122- displayConfig = true
123- case arg == "--multibuild-targets" :
124- displayTargets = true
125- case strings .HasPrefix (arg , "--multibuild" ):
126- fatal ("multibuild: unrecognized argument %q" , arg )
127- case ! strings .HasPrefix (arg , "-" ):
128- nonflags = append (nonflags , arg )
129- }
130- }
131-
132- var sources []string
133- packagePath := "" // the path being built
134- if output == "" {
135- switch len (nonflags ) {
136- case 0 :
137- // implicit case: multibuild on the current dir -> multibuild .
138- packagePath = "."
139- wd , err := os .Getwd ()
140- if err != nil {
141- fatal ("multibuild: failed to get cwd: %s" , err )
142- }
143- output = filepath .Base (wd )
144- case 1 :
145- t := nonflags [0 ]
146- if strings .HasSuffix (t , ".go" ) {
147- // multibuild cmd/foo.go
148- packagePath = filepath .Dir (t )
149- output = strings .TrimSuffix (filepath .Base (t ), ".go" )
150- sources = append (sources , t )
151- } else {
152- // multibuild cmd/foo
153- packagePath = t
154- output = filepath .Base (t )
155- }
156- default :
157- // For now, I'm cowardly refusing to handle this.
158- // I think we need to refactor some to handle two cases:
159- // - specifying a list of .go sources in a single ultimate package
160- // - specifying a list of packages
161- //
162- // The former is handled quite easily I think, the latter will
163- // require some additional thought and handling, as it's essentially
164- // another level of looping on top of what we have now.
165- //
166- // We will need to discover sources for each package, scan independently,
167- // and build independently.
168- fatal ("multibuild: cannot build multiple packages" )
169- }
170- }
67+ func doMultibuild (args cliArgs ) {
68+ sources := args .sources
17169
17270 if len (sources ) == 0 {
17371 var err error
174- sources , err = sourcesList (packagePath )
72+ sources , err = sourcesList (args . packagePath )
17573 if err != nil {
17674 fatal ("multibuild: failed to discover sources: %s" , err )
17775 }
@@ -191,26 +89,26 @@ func main() {
19189 fatal ("multibuild: failed to build target list: %s" , err )
19290 }
19391
194- if displayConfig {
92+ if args . displayConfig {
19593 displayConfigAndExit (opts )
19694 }
197- if displayTargets {
95+ if args . displayTargets {
19896 displayTargetsAndExit (targets )
19997 }
20098
20199 // If there's an explicit GOOS/GOARCH, pass through.
202100 // We want to stay out of the way here.
203101 // TODO: But this might be a confusing mistake to fall over if you set it in .bashrc etc..
204102 if os .Getenv ("GOOS" ) != "" || os .Getenv ("GOARCH" ) != "" {
205- runBuild (args , "" , "" )
103+ runBuild (args . goBuildArgs , "" , "" )
206104 return
207105 }
208106
209107 wg := sync.WaitGroup {}
210108 sem := make (chan struct {}, 4 ) // limit max parallel builds to save sanity...
211109
212110 formattedOutput := string (opts .Output )
213- formattedOutput = strings .ReplaceAll (formattedOutput , "${TARGET}" , output )
111+ formattedOutput = strings .ReplaceAll (formattedOutput , "${TARGET}" , args . output )
214112
215113 for _ , t := range targets {
216114 parts := strings .Split (string (t ), "/" )
@@ -225,19 +123,19 @@ func main() {
225123 }
226124
227125 buildArgs := []string {"-o" , out }
228- buildArgs = append (buildArgs , args ... )
126+ buildArgs = append (buildArgs , args .goBuildArgs . .. )
229127
230128 wg .Add (1 ) // acquire for global
231129 go func (goos , goarch string , buildArgs []string ) {
232- if verbose {
130+ if args . verbose {
233131 fmt .Fprintf (os .Stderr , "%s/%s: waiting\n " , goos , goarch )
234132 }
235133 sem <- struct {}{} // acquire for job
236- if verbose {
134+ if args . verbose {
237135 fmt .Fprintf (os .Stderr , "%s/%s: building\n " , goos , goarch )
238136 }
239137 runBuild (buildArgs , goos , goarch )
240- if verbose {
138+ if args . verbose {
241139 fmt .Fprintf (os .Stderr , "%s/%s: done\n " , goos , goarch )
242140 }
243141 <- sem // release for job
0 commit comments