什么是链接Postgres服务器端C函数的适当库
我正在尝试使用Ubuntu 14.04在Postgres 9.5的平台上编译一些C扩展。
在我的例子中,我想编写我的C代码并首先将其编译为独立的可执行文件(如下面的Makefile中所示)。 这是因为我还使用NumPy API并编写将Postgres ArrayType
数组转换为NumPy PyArray
对象的函数,然后使用一些NumPy数组函数。 获取正确的细节,正确释放NpyIter
对象等等是非常棘手的,所以我绝对需要编译,运行,观察错误和测试所有内容, 然后在最终部分中为最终部分构建库的详细信息,我说CREATE EXTENSION
Postgres中的CREATE EXTENSION
。
编译时,我得到了几个未定义的引用问题,例如:
tmp.c:(.text+0x2d6): undefined reference to `get_typlenbyvalalign' tmp.c:(.text+0x346): undefined reference to `deconstruct_array' tmp.c:(.text+0x41f): undefined reference to `DatumGetFloat8' tmp.c:(.text+0x4ae): undefined reference to `pfree' tmp.c:(.text+0x4ba): undefined reference to `pfree'
这些是来自Postgres C API的服务器端函数,但是有很多谷歌搜索和许多pgxs
我无法弄清楚如何获取我无法链接的后端Postgres库的名称或路径。
几乎所有搜索都提到了libpq
,但是这些函数没有在客户端API库中定义,所以我正在寻找其他东西。
作为参考,这是我目前正在使用的Makefile。 包括来自pg_config --libdir
的库目录也必须是不正确的,因为它不会导致未定义的引用错误的任何更改。
INCLUDEDIRS := -I. INCLUDEDIRS += -I/usr/include/python2.7 INCLUDEDIRS += -I/home/username/anaconda/lib/python2.7/site-packages/numpy/core/include INCLUDEDIRS += -I$(shell pg_config --includedir-server) INCLUDEDIRS += -I$(shell pg_config --includedir) LIBS := -L$(shell pg_config --libdir) LIBS += -lpython2.7 tmp: tmp.c Makefile gcc tmp.c -o tmp $(INCLUDEDIRS) $(LIBS)
输出pg_config --libdir
是:
user@computer:~/programming$ pg_config --libdir /usr/lib/x86_64-linux-gnu
在那个库目录中我也发现了libpgcommon
,当我将它添加到Makefile时,一些未定义的引用会消失,但不是全部。 这些仍然存在:
tmp.c:(.text+0x2d6): undefined reference to `get_typlenbyvalalign' tmp.c:(.text+0x346): undefined reference to `deconstruct_array' tmp.c:(.text+0x41f): undefined reference to `DatumGetFloat8'
所以通过链接pfree
找到了libpgcommon
,但没有别的。
在postgres.h
进一步挖掘我可以看到DatumGetFloat8
宏的定义位置(第662行):
#ifdef USE_FLOAT8_BYVAL extern float8 DatumGetFloat8(Datum X); #else #define DatumGetFloat8(X) (* ((float8 *) DatumGetPointer(X))) #endif
因此,Postgres必须以某种方式安装,使用USE_FLOAT8_BYVAL
标志。 那是标准吗? 您是否期望从普通的Postgres安装使用包Repos来安装像Ubuntu这样的流行操作系统?
鉴于此, DatumGetFloat8
的extern
源代码或库是什么? 例如,在Google上搜索“postgres DatumGetFloat8”几乎没有说明这一点。 我能找到的最好的是来自2011年的消息线程 (不确定是否正确):
缺少对DatumGetFloat8的引用意味着服务器已构建
使用float8传递值,并使用float8传递来构建pljava
参考。
( pljava
位对我来说无关紧要)。
PostgreSQL扩展是一个共享库,而不是一个独立的可执行文件,所以你必须在Makefile中使用-shared -fpic -o tmp.so
不要与-lpq
或-lpgcommon
链接。
然后gcc
不会抱怨未定义的引用 – 当共享库加载到PostgreSQL中时,使用SQL命令LOAD
或者调用使用该库定义的PostgreSQL C函数时,将使用可执行文件postgres
解析这些引用。
当然,在构建PostgreSQL服务器时,你必须使用相同的-D
USE_FLOAT8_BYVAL
作为定义,以便例如在两者中设置或取消设置USE_FLOAT8_BYVAL
。 否则,您的扩展程序可能无法加载或以有趣的方式崩溃。
(因为你问:按值传递float8
没有什么不好;如果你的架构支持它,它实际上更有效。如果定义了USE_FLOAT8_BYVAL
则在postgres
定义和导出USE_FLOAT8_BYVAL
。)
为了使这一切变得简单,最好使用PostgreSQL扩展构建基础结构PGXS 。 这将为您解决所有这些问题。
您所要做的就是创建一个合适的Makefile
,在您的情况下它可能就像创建一样简单
MODULES = tmp PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS)
然后运行make
和make install
,你就可以开始了!
由于您的问题是测试和调试使用NumPy API的代码,因此您应该模块化PostgreSQL扩展,以便您可以更轻松地执行此操作。 例如,您可以编写numpy.c
,其中包含访问该API的所有代码,以及包含PostgreSQL扩展代码并在numpy.c
调用函数的numpy.c
然后,您可以编写特殊的测试代码并将其与numpy.o
链接以测试您的NumPy函数。
如果你正在写Postgres 扩展 (你说CREATE EXTENSION foo
的那种),你不需要太担心所有INCLUDEDIR
等东西。 它比你想象的容易! 我写了几个非常简单的Postgres扩展,尽管每年只做几次C,但实际上它很容易。 你的Makefile
可以是6行长,如下所示:
MODULES = myextensionname EXTENSION = myextensionname DATA = myextensionname--1.0.sql PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS)
您还应该有一个myextensionname.control
文件,如下所示:
comment = 'Something about your extension' default_version = '1.0' module_pathname = '$libdir/myextensionname' relocatable = true
你需要一个myextensionname.c
如下所示:
#include #include #include #include // whatever other things you need to include here PG_MODULE_MAGIC; // your code here
然后编写一个myextensionname--1.0.sql
文件,当有人说CREATE EXTENSION
时运行myextensionname--1.0.sql
文件,这就是你创建类型/函数/你需要的任何其他东西(在SQL中)。
如果你想要一些非常容易复制的例子,这是我的两个项目:
https://github.com/pjungwir/aggs_for_arrays
https://github.com/pjungwir/inetrange
如果您想要更高级的扩展示例,请查看本地Postgres结帐的contrib
目录。
关于你的具体问题:
因此,Postgres必须以某种方式安装,使用USE_FLOAT8_BYVAL标志。
如果您使用类似上面的Makefile
,则无需担心,因为您的扩展将使用相同的标志进行编译,因此它将以与安装的Postgres相同的方式处理DatumGetFloat8
(无论是作为函数还是宏)。 我想你会发现USE_FLOAT_BYVAL
只是冰山一角,所以你应该使用include $(PGXS)
来匹配所有东西,而不是设置单独的标志。
编辑:我刚刚看到你的评论,你想编写一个独立的二进制文件用于测试目的。 我认为在进行扩展后我会这样做,这样你就可以更熟悉这个过程了。 此外,您可以查看我自己的项目和contrib
扩展,以获取其他人如何处理测试的示例。