1
2
3
4
5 package cshared_test
6
7 import (
8 "bytes"
9 "debug/elf"
10 "debug/pe"
11 "encoding/binary"
12 "flag"
13 "fmt"
14 "log"
15 "os"
16 "os/exec"
17 "path/filepath"
18 "runtime"
19 "strings"
20 "sync"
21 "testing"
22 "unicode"
23 )
24
25
26 var cc []string
27
28
29 var exeSuffix string
30
31 var GOOS, GOARCH, GOROOT string
32 var installdir, androiddir string
33 var libSuffix, libgoname string
34
35 func TestMain(m *testing.M) {
36 os.Exit(testMain(m))
37 }
38
39 func testMain(m *testing.M) int {
40 log.SetFlags(log.Lshortfile)
41 flag.Parse()
42 if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
43 fmt.Printf("SKIP - short mode and $GO_BUILDER_NAME not set\n")
44 os.Exit(0)
45 }
46
47 GOOS = goEnv("GOOS")
48 GOARCH = goEnv("GOARCH")
49 GOROOT = goEnv("GOROOT")
50
51 if _, err := os.Stat(GOROOT); os.IsNotExist(err) {
52 log.Fatalf("Unable able to find GOROOT at '%s'", GOROOT)
53 }
54
55 androiddir = fmt.Sprintf("/data/local/tmp/testcshared-%d", os.Getpid())
56 if runtime.GOOS != GOOS && GOOS == "android" {
57 args := append(adbCmd(), "exec-out", "mkdir", "-p", androiddir)
58 cmd := exec.Command(args[0], args[1:]...)
59 out, err := cmd.CombinedOutput()
60 if err != nil {
61 log.Fatalf("setupAndroid failed: %v\n%s\n", err, out)
62 }
63 defer cleanupAndroid()
64 }
65
66 cc = []string{goEnv("CC")}
67
68 out := goEnv("GOGCCFLAGS")
69 quote := '\000'
70 start := 0
71 lastSpace := true
72 backslash := false
73 s := string(out)
74 for i, c := range s {
75 if quote == '\000' && unicode.IsSpace(c) {
76 if !lastSpace {
77 cc = append(cc, s[start:i])
78 lastSpace = true
79 }
80 } else {
81 if lastSpace {
82 start = i
83 lastSpace = false
84 }
85 if quote == '\000' && !backslash && (c == '"' || c == '\'') {
86 quote = c
87 backslash = false
88 } else if !backslash && quote == c {
89 quote = '\000'
90 } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
91 backslash = true
92 } else {
93 backslash = false
94 }
95 }
96 }
97 if !lastSpace {
98 cc = append(cc, s[start:])
99 }
100
101 switch GOOS {
102 case "darwin", "ios":
103
104
105 cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
106 case "android":
107 cc = append(cc, "-pie")
108 }
109 libgodir := GOOS + "_" + GOARCH
110 switch GOOS {
111 case "darwin", "ios":
112 if GOARCH == "arm64" {
113 libgodir += "_shared"
114 }
115 case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris", "illumos":
116 libgodir += "_shared"
117 }
118 cc = append(cc, "-I", filepath.Join("pkg", libgodir))
119
120
121 cc = cc[:len(cc):len(cc)]
122
123 if GOOS == "windows" {
124 exeSuffix = ".exe"
125 }
126
127
128
129
130 GOPATH, err := os.MkdirTemp("", "cshared_test")
131 if err != nil {
132 log.Panic(err)
133 }
134 defer os.RemoveAll(GOPATH)
135 os.Setenv("GOPATH", GOPATH)
136
137 modRoot := filepath.Join(GOPATH, "src", "testcshared")
138 if err := overlayDir(modRoot, "testdata"); err != nil {
139 log.Panic(err)
140 }
141 if err := os.Chdir(modRoot); err != nil {
142 log.Panic(err)
143 }
144 os.Setenv("PWD", modRoot)
145 if err := os.WriteFile("go.mod", []byte("module testcshared\n"), 0666); err != nil {
146 log.Panic(err)
147 }
148
149
150
151 output, err := exec.Command("go", "list",
152 "-buildmode=c-shared",
153 "-installsuffix", "testcshared",
154 "-f", "{{.Target}}",
155 "./libgo").CombinedOutput()
156 if err != nil {
157 log.Panicf("go list failed: %v\n%s", err, output)
158 }
159 target := string(bytes.TrimSpace(output))
160 libgoname = filepath.Base(target)
161 installdir = filepath.Dir(target)
162 libSuffix = strings.TrimPrefix(filepath.Ext(target), ".")
163
164 return m.Run()
165 }
166
167 func goEnv(key string) string {
168 out, err := exec.Command("go", "env", key).Output()
169 if err != nil {
170 log.Printf("go env %s failed:\n%s", key, err)
171 log.Panicf("%s", err.(*exec.ExitError).Stderr)
172 }
173 return strings.TrimSpace(string(out))
174 }
175
176 func cmdToRun(name string) string {
177 return "./" + name + exeSuffix
178 }
179
180 func adbCmd() []string {
181 cmd := []string{"adb"}
182 if flags := os.Getenv("GOANDROID_ADB_FLAGS"); flags != "" {
183 cmd = append(cmd, strings.Split(flags, " ")...)
184 }
185 return cmd
186 }
187
188 func adbPush(t *testing.T, filename string) {
189 if runtime.GOOS == GOOS || GOOS != "android" {
190 return
191 }
192 args := append(adbCmd(), "push", filename, fmt.Sprintf("%s/%s", androiddir, filename))
193 cmd := exec.Command(args[0], args[1:]...)
194 if out, err := cmd.CombinedOutput(); err != nil {
195 t.Fatalf("adb command failed: %v\n%s\n", err, out)
196 }
197 }
198
199 func adbRun(t *testing.T, env []string, adbargs ...string) string {
200 if GOOS != "android" {
201 t.Fatalf("trying to run adb command when operating system is not android.")
202 }
203 args := append(adbCmd(), "exec-out")
204
205 for _, e := range env {
206 if strings.Contains(e, "LD_LIBRARY_PATH=") {
207 adbargs = append([]string{e}, adbargs...)
208 break
209 }
210 }
211 shellcmd := fmt.Sprintf("cd %s; %s", androiddir, strings.Join(adbargs, " "))
212 args = append(args, shellcmd)
213 cmd := exec.Command(args[0], args[1:]...)
214 out, err := cmd.CombinedOutput()
215 if err != nil {
216 t.Fatalf("adb command failed: %v\n%s\n", err, out)
217 }
218 return strings.Replace(string(out), "\r", "", -1)
219 }
220
221 func run(t *testing.T, extraEnv []string, args ...string) string {
222 t.Helper()
223 cmd := exec.Command(args[0], args[1:]...)
224 if len(extraEnv) > 0 {
225 cmd.Env = append(os.Environ(), extraEnv...)
226 }
227
228 if GOOS != "windows" {
229
230
231
232
233
234 cmd.ExtraFiles = make([]*os.File, 28)
235 }
236
237 out, err := cmd.CombinedOutput()
238 if err != nil {
239 t.Fatalf("command failed: %v\n%v\n%s\n", args, err, out)
240 } else {
241 t.Logf("run: %v", args)
242 }
243 return string(out)
244 }
245
246 func runExe(t *testing.T, extraEnv []string, args ...string) string {
247 t.Helper()
248 if runtime.GOOS != GOOS && GOOS == "android" {
249 return adbRun(t, append(os.Environ(), extraEnv...), args...)
250 }
251 return run(t, extraEnv, args...)
252 }
253
254 func runCC(t *testing.T, args ...string) string {
255 t.Helper()
256
257
258 return run(t, nil, append(append([]string(nil), cc...), args...)...)
259 }
260
261 func createHeaders() error {
262
263
264
265 objDir, err := os.MkdirTemp("", "testcshared_obj")
266 if err != nil {
267 return err
268 }
269 defer os.RemoveAll(objDir)
270
271
272
273
274
275 args := []string{"go", "tool", "cgo",
276 "-objdir", objDir,
277 "-exportheader", "p.h",
278 filepath.Join(".", "p", "p.go")}
279 cmd := exec.Command(args[0], args[1:]...)
280 out, err := cmd.CombinedOutput()
281 if err != nil {
282 return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
283 }
284
285
286 args = []string{"go", "install", "-buildmode=c-shared",
287 "-installsuffix", "testcshared", "./libgo"}
288 cmd = exec.Command(args[0], args[1:]...)
289 out, err = cmd.CombinedOutput()
290 if err != nil {
291 return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
292 }
293
294 args = []string{"go", "build", "-buildmode=c-shared",
295 "-installsuffix", "testcshared",
296 "-o", libgoname,
297 filepath.Join(".", "libgo", "libgo.go")}
298 if GOOS == "windows" && strings.HasSuffix(args[6], ".a") {
299 args[6] = strings.TrimSuffix(args[6], ".a") + ".dll"
300 }
301 cmd = exec.Command(args[0], args[1:]...)
302 out, err = cmd.CombinedOutput()
303 if err != nil {
304 return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
305 }
306 if GOOS == "windows" {
307
308
309
310 err = os.WriteFile("libgo.def",
311 []byte("LIBRARY libgo.dll\nEXPORTS\n\tDidInitRun\n\tDidMainRun\n\tDivu\n\tFromPkg\n\t_cgo_dummy_export\n"),
312 0644)
313 if err != nil {
314 return fmt.Errorf("unable to write def file: %v", err)
315 }
316 out, err = exec.Command(cc[0], append(cc[1:], "-print-prog-name=dlltool")...).CombinedOutput()
317 if err != nil {
318 return fmt.Errorf("unable to find dlltool path: %v\n%s\n", err, out)
319 }
320 args := []string{strings.TrimSpace(string(out)), "-D", args[6], "-l", libgoname, "-d", "libgo.def"}
321
322
323
324 dlltoolContents, err := os.ReadFile(args[0])
325 if err != nil {
326 return fmt.Errorf("unable to read dlltool: %v\n", err)
327 }
328 if bytes.HasPrefix(dlltoolContents, []byte("#!/bin/sh")) && bytes.Contains(dlltoolContents, []byte("llvm-dlltool")) {
329 base, name := filepath.Split(args[0])
330 args[0] = filepath.Join(base, "llvm-dlltool")
331 var machine string
332 switch prefix, _, _ := strings.Cut(name, "-"); prefix {
333 case "i686":
334 machine = "i386"
335 case "x86_64":
336 machine = "i386:x86-64"
337 case "armv7":
338 machine = "arm"
339 case "aarch64":
340 machine = "arm64"
341 }
342 if len(machine) > 0 {
343 args = append(args, "-m", machine)
344 }
345 }
346
347 out, err = exec.Command(args[0], args[1:]...).CombinedOutput()
348 if err != nil {
349 return fmt.Errorf("unable to run dlltool to create import library: %v\n%s\n", err, out)
350 }
351 }
352
353 if runtime.GOOS != GOOS && GOOS == "android" {
354 args = append(adbCmd(), "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname))
355 cmd = exec.Command(args[0], args[1:]...)
356 out, err = cmd.CombinedOutput()
357 if err != nil {
358 return fmt.Errorf("adb command failed: %v\n%s\n", err, out)
359 }
360 }
361
362 return nil
363 }
364
365 var (
366 headersOnce sync.Once
367 headersErr error
368 )
369
370 func createHeadersOnce(t *testing.T) {
371 headersOnce.Do(func() {
372 headersErr = createHeaders()
373 })
374 if headersErr != nil {
375 t.Fatal(headersErr)
376 }
377 }
378
379 func cleanupAndroid() {
380 if GOOS != "android" {
381 return
382 }
383 args := append(adbCmd(), "exec-out", "rm", "-rf", androiddir)
384 cmd := exec.Command(args[0], args[1:]...)
385 out, err := cmd.CombinedOutput()
386 if err != nil {
387 log.Panicf("cleanupAndroid failed: %v\n%s\n", err, out)
388 }
389 }
390
391
392 func TestExportedSymbols(t *testing.T) {
393 t.Parallel()
394
395 cmd := "testp0"
396 bin := cmdToRun(cmd)
397
398 createHeadersOnce(t)
399
400 runCC(t, "-I", installdir, "-o", cmd, "main0.c", libgoname)
401 adbPush(t, cmd)
402
403 defer os.Remove(bin)
404
405 out := runExe(t, []string{"LD_LIBRARY_PATH=."}, bin)
406 if strings.TrimSpace(out) != "PASS" {
407 t.Error(out)
408 }
409 }
410
411 func checkNumberOfExportedFunctionsWindows(t *testing.T, exportAllSymbols bool) {
412 const prog = `
413 package main
414
415 import "C"
416
417 //export GoFunc
418 func GoFunc() {
419 println(42)
420 }
421
422 //export GoFunc2
423 func GoFunc2() {
424 println(24)
425 }
426
427 func main() {
428 }
429 `
430
431 tmpdir := t.TempDir()
432
433 srcfile := filepath.Join(tmpdir, "test.go")
434 objfile := filepath.Join(tmpdir, "test.dll")
435 if err := os.WriteFile(srcfile, []byte(prog), 0666); err != nil {
436 t.Fatal(err)
437 }
438 argv := []string{"build", "-buildmode=c-shared"}
439 if exportAllSymbols {
440 argv = append(argv, "-ldflags", "-extldflags=-Wl,--export-all-symbols")
441 }
442 argv = append(argv, "-o", objfile, srcfile)
443 out, err := exec.Command("go", argv...).CombinedOutput()
444 if err != nil {
445 t.Fatalf("build failure: %s\n%s\n", err, string(out))
446 }
447
448 f, err := pe.Open(objfile)
449 if err != nil {
450 t.Fatalf("pe.Open failed: %v", err)
451 }
452 defer f.Close()
453 section := f.Section(".edata")
454 if section == nil {
455 t.Skip(".edata section is not present")
456 }
457
458
459 type IMAGE_EXPORT_DIRECTORY struct {
460 _ [2]uint32
461 _ [2]uint16
462 _ [2]uint32
463 NumberOfFunctions uint32
464 NumberOfNames uint32
465 _ [3]uint32
466 }
467 var e IMAGE_EXPORT_DIRECTORY
468 if err := binary.Read(section.Open(), binary.LittleEndian, &e); err != nil {
469 t.Fatalf("binary.Read failed: %v", err)
470 }
471
472
473 expectedNumber := uint32(3)
474
475 if exportAllSymbols {
476 if e.NumberOfFunctions <= expectedNumber {
477 t.Fatalf("missing exported functions: %v", e.NumberOfFunctions)
478 }
479 if e.NumberOfNames <= expectedNumber {
480 t.Fatalf("missing exported names: %v", e.NumberOfNames)
481 }
482 } else {
483 if e.NumberOfFunctions != expectedNumber {
484 t.Fatalf("got %d exported functions; want %d", e.NumberOfFunctions, expectedNumber)
485 }
486 if e.NumberOfNames != expectedNumber {
487 t.Fatalf("got %d exported names; want %d", e.NumberOfNames, expectedNumber)
488 }
489 }
490 }
491
492 func TestNumberOfExportedFunctions(t *testing.T) {
493 if GOOS != "windows" {
494 t.Skip("skipping windows only test")
495 }
496 t.Parallel()
497
498 t.Run("OnlyExported", func(t *testing.T) {
499 checkNumberOfExportedFunctionsWindows(t, false)
500 })
501 t.Run("All", func(t *testing.T) {
502 checkNumberOfExportedFunctionsWindows(t, true)
503 })
504 }
505
506
507 func TestExportedSymbolsWithDynamicLoad(t *testing.T) {
508 t.Parallel()
509
510 if GOOS == "windows" {
511 t.Logf("Skipping on %s", GOOS)
512 return
513 }
514
515 cmd := "testp1"
516 bin := cmdToRun(cmd)
517
518 createHeadersOnce(t)
519
520 if GOOS != "freebsd" {
521 runCC(t, "-o", cmd, "main1.c", "-ldl")
522 } else {
523 runCC(t, "-o", cmd, "main1.c")
524 }
525 adbPush(t, cmd)
526
527 defer os.Remove(bin)
528
529 out := runExe(t, nil, bin, "./"+libgoname)
530 if strings.TrimSpace(out) != "PASS" {
531 t.Error(out)
532 }
533 }
534
535
536 func TestUnexportedSymbols(t *testing.T) {
537 t.Parallel()
538
539 if GOOS == "windows" {
540 t.Logf("Skipping on %s", GOOS)
541 return
542 }
543
544 cmd := "testp2"
545 bin := cmdToRun(cmd)
546 libname := "libgo2." + libSuffix
547
548 run(t,
549 nil,
550 "go", "build",
551 "-buildmode=c-shared",
552 "-installsuffix", "testcshared",
553 "-o", libname, "./libgo2",
554 )
555 adbPush(t, libname)
556
557 linkFlags := "-Wl,--no-as-needed"
558 if GOOS == "darwin" || GOOS == "ios" {
559 linkFlags = ""
560 }
561
562 runCC(t, "-o", cmd, "main2.c", linkFlags, libname)
563 adbPush(t, cmd)
564
565 defer os.Remove(libname)
566 defer os.Remove(bin)
567
568 out := runExe(t, []string{"LD_LIBRARY_PATH=."}, bin)
569
570 if strings.TrimSpace(out) != "PASS" {
571 t.Error(out)
572 }
573 }
574
575
576 func TestMainExportedOnAndroid(t *testing.T) {
577 t.Parallel()
578
579 switch GOOS {
580 case "android":
581 break
582 default:
583 t.Logf("Skipping on %s", GOOS)
584 return
585 }
586
587 cmd := "testp3"
588 bin := cmdToRun(cmd)
589
590 createHeadersOnce(t)
591
592 runCC(t, "-o", cmd, "main3.c", "-ldl")
593 adbPush(t, cmd)
594
595 defer os.Remove(bin)
596
597 out := runExe(t, nil, bin, "./"+libgoname)
598 if strings.TrimSpace(out) != "PASS" {
599 t.Error(out)
600 }
601 }
602
603 func testSignalHandlers(t *testing.T, pkgname, cfile, cmd string) {
604 libname := pkgname + "." + libSuffix
605 run(t,
606 nil,
607 "go", "build",
608 "-buildmode=c-shared",
609 "-installsuffix", "testcshared",
610 "-o", libname, pkgname,
611 )
612 adbPush(t, libname)
613 if GOOS != "freebsd" {
614 runCC(t, "-pthread", "-o", cmd, cfile, "-ldl")
615 } else {
616 runCC(t, "-pthread", "-o", cmd, cfile)
617 }
618 adbPush(t, cmd)
619
620 bin := cmdToRun(cmd)
621
622 defer os.Remove(libname)
623 defer os.Remove(bin)
624 defer os.Remove(pkgname + ".h")
625
626 out := runExe(t, nil, bin, "./"+libname)
627 if strings.TrimSpace(out) != "PASS" {
628 t.Error(run(t, nil, bin, libname, "verbose"))
629 }
630 }
631
632
633 func TestSignalHandlers(t *testing.T) {
634 t.Parallel()
635 if GOOS == "windows" {
636 t.Logf("Skipping on %s", GOOS)
637 return
638 }
639 testSignalHandlers(t, "./libgo4", "main4.c", "testp4")
640 }
641
642
643 func TestSignalHandlersWithNotify(t *testing.T) {
644 t.Parallel()
645 if GOOS == "windows" {
646 t.Logf("Skipping on %s", GOOS)
647 return
648 }
649 testSignalHandlers(t, "./libgo5", "main5.c", "testp5")
650 }
651
652 func TestPIE(t *testing.T) {
653 t.Parallel()
654
655 switch GOOS {
656 case "linux", "android":
657 break
658 default:
659 t.Logf("Skipping on %s", GOOS)
660 return
661 }
662
663 createHeadersOnce(t)
664
665 f, err := elf.Open(libgoname)
666 if err != nil {
667 t.Fatalf("elf.Open failed: %v", err)
668 }
669 defer f.Close()
670
671 ds := f.SectionByType(elf.SHT_DYNAMIC)
672 if ds == nil {
673 t.Fatalf("no SHT_DYNAMIC section")
674 }
675 d, err := ds.Data()
676 if err != nil {
677 t.Fatalf("can't read SHT_DYNAMIC contents: %v", err)
678 }
679 for len(d) > 0 {
680 var tag elf.DynTag
681 switch f.Class {
682 case elf.ELFCLASS32:
683 tag = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
684 d = d[8:]
685 case elf.ELFCLASS64:
686 tag = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
687 d = d[16:]
688 }
689 if tag == elf.DT_TEXTREL {
690 t.Fatalf("%s has DT_TEXTREL flag", libgoname)
691 }
692 }
693 }
694
695
696 func TestCachedInstall(t *testing.T) {
697 tmpdir, err := os.MkdirTemp("", "cshared")
698 if err != nil {
699 t.Fatal(err)
700 }
701 defer os.RemoveAll(tmpdir)
702
703 copyFile(t, filepath.Join(tmpdir, "src", "testcshared", "go.mod"), "go.mod")
704 copyFile(t, filepath.Join(tmpdir, "src", "testcshared", "libgo", "libgo.go"), filepath.Join("libgo", "libgo.go"))
705 copyFile(t, filepath.Join(tmpdir, "src", "testcshared", "p", "p.go"), filepath.Join("p", "p.go"))
706
707 env := append(os.Environ(), "GOPATH="+tmpdir, "GOBIN="+filepath.Join(tmpdir, "bin"))
708
709 buildcmd := []string{"go", "install", "-x", "-buildmode=c-shared", "-installsuffix", "testcshared", "./libgo"}
710
711 cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
712 cmd.Dir = filepath.Join(tmpdir, "src", "testcshared")
713 cmd.Env = env
714 t.Log(buildcmd)
715 out, err := cmd.CombinedOutput()
716 t.Logf("%s", out)
717 if err != nil {
718 t.Fatal(err)
719 }
720
721 var libgoh, ph string
722
723 walker := func(path string, info os.FileInfo, err error) error {
724 if err != nil {
725 t.Fatal(err)
726 }
727 var ps *string
728 switch filepath.Base(path) {
729 case "libgo.h":
730 ps = &libgoh
731 case "p.h":
732 ps = &ph
733 }
734 if ps != nil {
735 if *ps != "" {
736 t.Fatalf("%s found again", *ps)
737 }
738 *ps = path
739 }
740 return nil
741 }
742
743 if err := filepath.Walk(tmpdir, walker); err != nil {
744 t.Fatal(err)
745 }
746
747 if libgoh == "" {
748 t.Fatal("libgo.h not installed")
749 }
750
751 if err := os.Remove(libgoh); err != nil {
752 t.Fatal(err)
753 }
754
755 cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
756 cmd.Dir = filepath.Join(tmpdir, "src", "testcshared")
757 cmd.Env = env
758 t.Log(buildcmd)
759 out, err = cmd.CombinedOutput()
760 t.Logf("%s", out)
761 if err != nil {
762 t.Fatal(err)
763 }
764
765 if _, err := os.Stat(libgoh); err != nil {
766 t.Errorf("libgo.h not installed in second run: %v", err)
767 }
768 }
769
770
771 func copyFile(t *testing.T, dst, src string) {
772 t.Helper()
773 data, err := os.ReadFile(src)
774 if err != nil {
775 t.Fatal(err)
776 }
777 if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil {
778 t.Fatal(err)
779 }
780 if err := os.WriteFile(dst, data, 0666); err != nil {
781 t.Fatal(err)
782 }
783 }
784
785 func TestGo2C2Go(t *testing.T) {
786 switch GOOS {
787 case "darwin", "ios", "windows":
788
789
790 t.Skipf("linking c-shared into Go programs not supported on %s; issue 29061, 49457", GOOS)
791 case "android":
792 t.Skip("test fails on android; issue 29087")
793 }
794
795 t.Parallel()
796
797 tmpdir, err := os.MkdirTemp("", "cshared-TestGo2C2Go")
798 if err != nil {
799 t.Fatal(err)
800 }
801 defer os.RemoveAll(tmpdir)
802
803 lib := filepath.Join(tmpdir, "libtestgo2c2go."+libSuffix)
804 var env []string
805 if GOOS == "windows" && strings.HasSuffix(lib, ".a") {
806 env = append(env, "CGO_LDFLAGS=-Wl,--out-implib,"+lib, "CGO_LDFLAGS_ALLOW=.*")
807 lib = strings.TrimSuffix(lib, ".a") + ".dll"
808 }
809 run(t, env, "go", "build", "-buildmode=c-shared", "-o", lib, "./go2c2go/go")
810
811 cgoCflags := os.Getenv("CGO_CFLAGS")
812 if cgoCflags != "" {
813 cgoCflags += " "
814 }
815 cgoCflags += "-I" + tmpdir
816
817 cgoLdflags := os.Getenv("CGO_LDFLAGS")
818 if cgoLdflags != "" {
819 cgoLdflags += " "
820 }
821 cgoLdflags += "-L" + tmpdir + " -ltestgo2c2go"
822
823 goenv := []string{"CGO_CFLAGS=" + cgoCflags, "CGO_LDFLAGS=" + cgoLdflags}
824
825 ldLibPath := os.Getenv("LD_LIBRARY_PATH")
826 if ldLibPath != "" {
827 ldLibPath += ":"
828 }
829 ldLibPath += tmpdir
830
831 runenv := []string{"LD_LIBRARY_PATH=" + ldLibPath}
832
833 bin := filepath.Join(tmpdir, "m1") + exeSuffix
834 run(t, goenv, "go", "build", "-o", bin, "./go2c2go/m1")
835 runExe(t, runenv, bin)
836
837 bin = filepath.Join(tmpdir, "m2") + exeSuffix
838 run(t, goenv, "go", "build", "-o", bin, "./go2c2go/m2")
839 runExe(t, runenv, bin)
840 }
841
View as plain text