这就是我现在正在做的事情,
.
├── helloworld--1.0.sql
├── helloworld.control
├── helloworld.go
└── Makefile
helloworld.go
:
package helloworld
/*
#cgo LDFLAGS: -rdynamic
#include "postgres.h"
#include "fmgr.h"
#include "utils/builtins.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(helloworld);
PG_FUNCTION_INFO_V1(hello_text_arg);
PG_FUNCTION_INFO_V1(hello_ereport);
Datum
hello_world(PG_FUNCTION_ARGS)
{
PG_RETURN_TEXT_P(cstring_to_text("Hello, World!"));
}
Datum
hello_text_arg(PG_FUNCTION_ARGS)
{
text *hello = cstring_to_text("Hello, ");
int32 hello_sz = VARSIZE(hello) - VARHDRSZ;
text *name = PG_GETARG_TEXT_P(0);
int32 name_sz = VARSIZE(name) - VARHDRSZ;
text *tail = cstring_to_text("!");
int32 tail_sz = VARSIZE(tail) - VARHDRSZ;
int32 out_sz = hello_sz + name_sz + tail_sz + VARHDRSZ;
text *out = (text *) palloc(out_sz);
SET_VARSIZE(out, out_sz);
memcpy(VARDATA(out), VARDATA(hello), hello_sz);
memcpy(VARDATA(out) + hello_sz, VARDATA(name), name_sz);
memcpy(VARDATA(out) + hello_sz + name_sz, VARDATA(tail), tail_sz);
PG_RETURN_TEXT_P(out);
}
Datum
hello_ereport(PG_FUNCTION_ARGS)
{
ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("null value not allowed")));
PG_RETURN_VOID();
}
*/
import "C"
Makefile
:
MODULES = helloworld
EXTENSION = helloworld
DATA = helloworld--1.0.sql
PGFILEDESC = "helloworld - example extension for postgresql"
REGRESS = helloworld
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
INCLUDEDIR = $(shell $(PG_CONFIG) --includedir-server)
include $(PGXS)
helloworld.so:
CGO_CFLAGS="-rdynamic -I$(INCLUDEDIR)" CGO_LDFLAGS="-rdynamic $(LDFLAGS)" go build -v -buildmode=c-shared -o helloworld.so .
制作时产生了以下错误:
/tmp/go-build019341122/github.com/amosbird/rpctest/helloworld/_obj/helloworld.cgo2.o: In function `hello_world':
helloworld.cgo2.c:(.text+0x48): undefined reference to `cstring_to_text'
/tmp/go-build019341122/github.com/amosbird/rpctest/helloworld/_obj/helloworld.cgo2.o: In function `hello_text_arg':
helloworld.cgo2.c:(.text+0x63): undefined reference to `cstring_to_text'
helloworld.cgo2.c:(.text+0x86): undefined reference to `pg_detoast_datum'
helloworld.cgo2.c:(.text+0xa5): undefined reference to `cstring_to_text'
helloworld.cgo2.c:(.text+0xd7): undefined reference to `palloc'
/tmp/go-build019341122/github.com/amosbird/rpctest/helloworld/_obj/helloworld.cgo2.o: In function `hello_ereport':
helloworld.cgo2.c:(.text+0x1a8): undefined reference to `errstart'
helloworld.cgo2.c:(.text+0x1bd): undefined reference to `errmsg'
helloworld.cgo2.c:(.text+0x1c9): undefined reference to `errcode'
helloworld.cgo2.c:(.text+0x1d7): undefined reference to `errfinish'
collect2: ld returned 1 exit status
make: *** [helloworld.so] Error 2
我不知道这是否有用。这里发生了很多黑魔法。
所以主要的问题是,什么是正确的Makefile,可用于在cgo中构建Postgres扩展?
这些错误的具体问题是,我可以做些什么来推迟cgo链接过程中的符号解析?
答案 0 :(得分:3)
好的,我花了一整天时间找到了可行的解决方案。
我们需要让扩展程序的主要源文件以:
开头package main // make sure to use main package
/*
#cgo CFLAGS: -I/path/to/postgres/include/server
#cgo LDFLAGS: -Wl,-unresolved-symbols=ignore-all
使用go build -o myext.so -buildmode=c-shared myext.go
生成myext.so
。
如果C方需要一些Go方法,我们应该在方法声明之上添加//export methodname
。这将生成没有包名称前缀的符号。然后我们可以在C侧外加这些符号。确保导出的Go方法驻留在main之外的包中。
package test
:
//export Merge
func Merge(cint C.int) C.int ...
package main
:
extern int Merge(int);
import "./test"
var _ = test.Somevar // dumb placeholder to fake use package test.