diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 157cd94d653ab..08d64130df436 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -827,6 +827,10 @@ The directives are: possibly version in the dynamic library, and the optional "" names the specific library where the symbol should be found. + On AIX, the library pattern is slightly different. It must be + "lib.a/obj.o" with obj.o the member of this library exporting + this symbol. + In the , # or @ can be used to introduce a symbol version. Examples: diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 3b302a5124bd0..bd68ebffff0a2 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -114,6 +114,14 @@ func (p *noder) pragcgo(pos syntax.Pos, text string) { case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]): case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]): f[3] = strings.Trim(f[3], `"`) + if objabi.GOOS == "aix" && f[3] != "" { + // On Aix, library pattern must be "lib.a/object.o" + n := strings.Split(f[3], "/") + if len(n) != 2 || !strings.HasSuffix(n[0], ".a") || !strings.HasSuffix(n[1], ".o") { + p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`}) + return + } + } default: p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`}) return diff --git a/src/cmd/compile/internal/gc/lex_test.go b/src/cmd/compile/internal/gc/lex_test.go index fecf570fa1615..e05726c9f35fa 100644 --- a/src/cmd/compile/internal/gc/lex_test.go +++ b/src/cmd/compile/internal/gc/lex_test.go @@ -7,6 +7,7 @@ package gc import ( "cmd/compile/internal/syntax" "reflect" + "runtime" "testing" ) @@ -49,10 +50,12 @@ func TestPragmaFields(t *testing.T) { } func TestPragcgo(t *testing.T) { - var tests = []struct { + type testStruct struct { in string want []string - }{ + } + + var tests = []testStruct{ {`go:cgo_export_dynamic local`, []string{`cgo_export_dynamic`, `local`}}, {`go:cgo_export_dynamic local remote`, []string{`cgo_export_dynamic`, `local`, `remote`}}, {`go:cgo_export_dynamic local' remote'`, []string{`cgo_export_dynamic`, `local'`, `remote'`}}, @@ -61,8 +64,6 @@ func TestPragcgo(t *testing.T) { {`go:cgo_export_static local' remote'`, []string{`cgo_export_static`, `local'`, `remote'`}}, {`go:cgo_import_dynamic local`, []string{`cgo_import_dynamic`, `local`}}, {`go:cgo_import_dynamic local remote`, []string{`cgo_import_dynamic`, `local`, `remote`}}, - {`go:cgo_import_dynamic local remote "library"`, []string{`cgo_import_dynamic`, `local`, `remote`, `library`}}, - {`go:cgo_import_dynamic local' remote' "lib rary"`, []string{`cgo_import_dynamic`, `local'`, `remote'`, `lib rary`}}, {`go:cgo_import_static local`, []string{`cgo_import_static`, `local`}}, {`go:cgo_import_static local'`, []string{`cgo_import_static`, `local'`}}, {`go:cgo_dynamic_linker "/path/"`, []string{`cgo_dynamic_linker`, `/path/`}}, @@ -71,17 +72,50 @@ func TestPragcgo(t *testing.T) { {`go:cgo_ldflag "a rg"`, []string{`cgo_ldflag`, `a rg`}}, } + if runtime.GOOS != "aix" { + tests = append(tests, []testStruct{ + {`go:cgo_import_dynamic local remote "library"`, []string{`cgo_import_dynamic`, `local`, `remote`, `library`}}, + {`go:cgo_import_dynamic local' remote' "lib rary"`, []string{`cgo_import_dynamic`, `local'`, `remote'`, `lib rary`}}, + }...) + } else { + // cgo_import_dynamic with a library is slightly different on AIX + // as the library field must follow the pattern [libc.a/object.o]. + tests = append(tests, []testStruct{ + {`go:cgo_import_dynamic local remote "lib.a/obj.o"`, []string{`cgo_import_dynamic`, `local`, `remote`, `lib.a/obj.o`}}, + // This test must fail. + {`go:cgo_import_dynamic local' remote' "library"`, []string{`: usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`}}, + }...) + + } + var p noder var nopos syntax.Pos for _, tt := range tests { - p.pragcgobuf = nil - p.pragcgo(nopos, tt.in) - got := p.pragcgobuf - want := [][]string{tt.want} - if !reflect.DeepEqual(got, want) { - t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, want) - continue + p.err = make(chan syntax.Error) + gotch := make(chan [][]string) + go func() { + p.pragcgobuf = nil + p.pragcgo(nopos, tt.in) + if p.pragcgobuf != nil { + gotch <- p.pragcgobuf + } + }() + + select { + case e := <-p.err: + want := tt.want[0] + if e.Error() != want { + t.Errorf("pragcgo(%q) = %q; want %q", tt.in, e, want) + continue + } + case got := <-gotch: + want := [][]string{tt.want} + if !reflect.DeepEqual(got, want) { + t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, want) + continue + } } + } }