@@ -17,7 +17,6 @@ func TestHelp(t *testing.T) {
1717 cmd := exec .Command ("go" , "build" , "-o" , bin )
1818 cmd .Stdout = os .Stdout
1919 cmd .Stderr = os .Stderr
20- cmd .Env = append (os .Environ (), "CGO_ENABLED=0" )
2120 if err := cmd .Run (); err != nil {
2221 t .Fatalf ("build failed: %v" , err )
2322 }
@@ -36,7 +35,6 @@ multibuild-specific options:
3635 for _ , test := range []string {"-h" , "--help" } {
3736 t .Run (test , func (t * testing.T ) {
3837 cmd = exec .Command (bin , test )
39- cmd .Env = append (os .Environ (), "CGO_ENABLED=0" )
4038
4139 out , err := cmd .CombinedOutput ()
4240 if err != nil {
@@ -58,14 +56,13 @@ multibuild-specific options:
5856 }
5957}
6058
61- func TestMultibuild (t * testing.T ) {
59+ func TestMultibuildWithConfiguration (t * testing.T ) {
6260 binTmp := t .TempDir ()
6361 bin := filepath .Join (binTmp , "multibuild" )
6462
6563 cmd := exec .Command ("go" , "build" , "-o" , bin )
6664 cmd .Stdout = os .Stdout
6765 cmd .Stderr = os .Stderr
68- cmd .Env = append (os .Environ (), "CGO_ENABLED=0" )
6966 if err := cmd .Run (); err != nil {
7067 t .Fatalf ("build failed: %v" , err )
7168 }
@@ -196,3 +193,173 @@ func main() {
196193 })
197194 }
198195}
196+
197+ func TestMultibuildDifferentStyles (t * testing.T ) {
198+ type testCase struct {
199+ name string
200+ numPackages int
201+ numBinariesPerPkg int
202+ runDir string
203+ args []string
204+ expectErr bool
205+ expectedBinaries []string
206+ }
207+
208+ goos := runtime .GOOS
209+ goarch := runtime .GOARCH
210+
211+ // TODO: A little too much magic generation in this test, but unsure how else to structure it.
212+ // TODO: We presently only test building inside a single module. That's probably OK, or do we need to test more?
213+ // TODO: We don't have tests to cover multiple source files that aren't binaries, and we should.
214+ testCases := []testCase {
215+ {
216+ // tests "multibuild" with no arguments should produce binaries
217+ name : "build in source dir" ,
218+ numPackages : 1 ,
219+ numBinariesPerPkg : 1 ,
220+ runDir : "pkg1" ,
221+ args : []string {},
222+ expectErr : false ,
223+ expectedBinaries : []string {
224+ fmt .Sprintf ("pkg1-%s-%s" , goos , goarch ),
225+ },
226+ },
227+ {
228+ // tests "multibuild pkg/" should produce binaries
229+ name : "build via path/" ,
230+ numPackages : 1 ,
231+ numBinariesPerPkg : 1 ,
232+ runDir : "." ,
233+ args : []string {"./pkg1" },
234+ expectErr : false ,
235+ expectedBinaries : []string {
236+ fmt .Sprintf ("pkg1-%s-%s" , goos , goarch ),
237+ },
238+ },
239+ {
240+ // tests "multibuild pkg/main1.go" should produce binaries
241+ name : "build via single .go file" ,
242+ numPackages : 1 ,
243+ numBinariesPerPkg : 1 ,
244+ runDir : "." ,
245+ args : []string {"pkg1/main1.go" },
246+ expectErr : false ,
247+ expectedBinaries : []string {
248+ fmt .Sprintf ("pkg1-%s-%s" , goos , goarch ),
249+ },
250+ },
251+ {
252+ // tests that currently, building two binaries should fail
253+ name : "build two binaries by file" ,
254+ numPackages : 1 ,
255+ numBinariesPerPkg : 2 ,
256+ runDir : "." ,
257+ args : []string {"pkg1/main1.go" , "pkg1/main2.go" },
258+ expectErr : true ,
259+ expectedBinaries : []string {},
260+ },
261+ {
262+ // tests that currently, building two packages should fail
263+ name : "build two packages by path/" ,
264+ numPackages : 2 ,
265+ numBinariesPerPkg : 1 ,
266+ runDir : "." ,
267+ args : []string {"pkg1" , "pkg2" },
268+ expectErr : true ,
269+ expectedBinaries : []string {},
270+ },
271+ }
272+
273+ tmpRoot := t .TempDir ()
274+ bin := filepath .Join (tmpRoot , "multibuild" )
275+
276+ cmd := exec .Command ("go" , "build" , "-o" , bin )
277+ cmd .Stdout = os .Stdout
278+ cmd .Stderr = os .Stderr
279+ if err := cmd .Run (); err != nil {
280+ t .Fatalf ("build failed: %v" , err )
281+ }
282+
283+ for _ , tc := range testCases {
284+ t .Run (tc .name , func (t * testing.T ) {
285+ // Setup packages and binaries
286+ gover := runtime .Version () // "go1.24..."
287+ if gover [0 :2 ] != "go" { // check for, and skip the "go" prefix
288+ t .Fatalf ("unexpected go version: %s" , gover )
289+ }
290+ gover = gover [2 :]
291+ baseMod := fmt .Sprintf ("module %s\n \n go %s\n " , "testmod" , gover )
292+ if err := os .WriteFile (filepath .Join (tmpRoot , "go.mod" ), []byte (baseMod ), 0644 ); err != nil {
293+ t .Fatalf ("failed to write go.mod: %v" , err )
294+ }
295+
296+ for p := 1 ; p <= tc .numPackages ; p ++ {
297+ pkgDir := filepath .Join (tmpRoot , fmt .Sprintf ("pkg%d" , p ))
298+ os .RemoveAll (pkgDir )
299+
300+ if err := os .Mkdir (pkgDir , 0755 ); err != nil {
301+ t .Fatalf ("failed to mkdir: %v" , err )
302+ }
303+ for b := 1 ; b <= tc .numBinariesPerPkg ; b ++ {
304+ mainSource := fmt .Sprintf (`package main
305+ import "fmt"
306+ func main() { fmt.Println("Hello from main%d in pkg%d") }
307+ ` , b , p )
308+
309+ mainPath := filepath .Join (pkgDir , fmt .Sprintf ("main%d.go" , b ))
310+ if err := os .WriteFile (mainPath , []byte (mainSource ), 0644 ); err != nil {
311+ t .Fatalf ("failed to write %s: %v" , mainPath , err )
312+ }
313+ // Add multibuild config to the first file in each package
314+ if b == 1 {
315+ config := `//go:multibuild:include=` + goos + `/` + goarch + "\n "
316+ config += "//go:multibuild:output=${TARGET}-${GOOS}-${GOARCH}\n "
317+ buf , err := os .ReadFile (mainPath )
318+ if err != nil {
319+ t .Fatalf ("failed to read file to inject config" )
320+ }
321+ if err := os .WriteFile (mainPath , []byte (config + string (buf )), 0644 ); err != nil {
322+ t .Fatalf ("failed to write config: %v" , err )
323+ }
324+ }
325+ }
326+ }
327+
328+ var runDir string
329+ if tc .runDir == "." {
330+ runDir = tmpRoot
331+ } else {
332+ runDir = filepath .Join (tmpRoot , tc .runDir )
333+ }
334+
335+ cmd := exec .Command (bin , tc .args ... )
336+ cmd .Dir = runDir
337+ out , err := cmd .CombinedOutput ()
338+
339+ if tc .expectErr {
340+ if err == nil {
341+ t .Fatalf ("expected error, got success:\n Output:\n %s" , string (out ))
342+ }
343+ } else {
344+ if err != nil {
345+ t .Fatalf ("expected success, got error: %s\n Output:\n %s" , err , string (out ))
346+ }
347+
348+ if err != nil {
349+ t .Fatalf ("expected success, got error: %v\n Output:\n %s" , err , string (out ))
350+ }
351+ for _ , binRel := range tc .expectedBinaries {
352+ var binPath string
353+ if tc .runDir == "." {
354+ binPath = filepath .Join (tmpRoot , binRel )
355+ } else {
356+ binPath = filepath .Join (runDir , binRel )
357+ }
358+ if _ , err := os .Stat (binPath ); err != nil {
359+ t .Errorf ("expected binary %q not found" , binPath )
360+ }
361+ }
362+ }
363+ })
364+ }
365+ }
0 commit comments