简体   繁体   English

使用自定义库安装 postgresql 扩展的正确方法

[英]Correct way of installing postgresql extension with custom library

TL;DR TL;博士

One has to compile their custom library as shared library:必须将他们的自定义库编译为共享库:

gcc -c -fPIC warp_client.c -o warp_client.o
gcc -shared warp_client.o libwarp-client.so 

Include the shared library and additional dependencies of that shared library in the Postgresql Makefile with the flags SHLIB_LINK and PG_LDFLAGS(Here the bachelor_fdw.c is the extension to compile):使用标志 SHLIB_LINK 和 PG_LDFLAGS 将共享库和该共享库的附加依赖项包含在 Postgresql Makefile 中(这里的 Bachelor_fdw.c 是要编译的扩展名):

EXTENSION = bachelor_fdw
MODULE_big = bachelor_fdw
DATA = bachelor_fdw--0.1.sql
OBJS = bachelor_fdw.o

PG_LIBS = -lpq
SHLIB_LINK = -lwarp_client -lucp
PG_LDFLAGS += -L/usr/lib/warpdrive/ -L/usr/lib/ucx/

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)

Include the directories of the shared libraries into the environment variable LD_LIBRARY_PATH of Postgresql.将共享库的目录包含在 Postgresql 的环境变量 LD_LIBRARY_PATH 中。 For that, one has to add a line to the file 'environment' in the main Postgresql directory and restart Postgresql.为此,必须在 Postgresql 主目录中的文件“环境”中添加一行并重新启动 Postgresql。 Here is mine:这是我的:

$ cat /etc/postgresql/12/main/environment
# environment variables for postgres processes
# This file has the same syntax as postgresql.conf:
#  VARIABLE = simple_value
#  VARIABLE2 = 'any value!'
# I. e. you need to enclose any value which does not only consist of letters,
# numbers, and '-', '_', '.' in single quotes. Shell commands are not
# evaluated.
LD_LIBRARY_PATH='/usr/include/:/usr/include/ucx/:/usr/lib/:/usr/lib/ucx/'

I am trying to create a foreign data wrapper, which uses a custom library from me.我正在尝试创建一个外部数据包装器,它使用我的自定义库。 The fdw compiles and installs fine, but when using it, symbols to my library are undefined. fdw 可以正常编译和安装,但是在使用它时,我的库中的符号是未定义的。 What is the proper way of using custom c code as library in a postgresql extension and what am i doing wrong?在 postgresql 扩展中使用自定义 c 代码作为库的正确方法是什么,我做错了什么? Here are the steps i took:以下是我采取的步骤:

  1. Compile my library (warp_client.c) with flag -fPIC into an object file.将带有标志 -fPIC 的库 (warp_client.c) 编译到目标文件中。

gcc -c -fPIC warp_client.c -o static/warp_client.o

  1. Create static library from the object file.从目标文件创建静态库。

ar -rcs out/libwarp_client.a static/warp_client.o

  1. Copy libwarp_client.a and warp_client.h into the postgresql extension project root.将 libwarp_client.a 和 warp_client.h 复制到 postgresql 扩展项目根目录中。
  2. Compile postgresql extension with the following makefile.使用以下 makefile 编译 postgresql 扩展。
EXTENSION = bachelor_fdw
MODULE_big = bachelor_fdw
DATA = bachelor_fdw--0.1.sql libwarp_client.a
OBJS = bachelor_fdw.o
HEADERS = warp_client.h

ifdef DEBUG
$(info $(shell echo "debug ist an"))
endif

PG_LIBS = -lpq

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)

make USE_PGXS=1 install

  1. Try to create the extension.尝试创建扩展。 The extension makes a call to a library function in it's _PG_INI() function.该扩展在其 _PG_INI() 函数中调用库函数。 Error comes up:出现错误:

CREATE EXTENSION IF NOT EXISTS bachelor_fdw;

psql:only_create.sql:3: ERROR:  could not load library "/usr/lib/postgresql/12/lib/bachelor_fdw.so": /usr/lib/postgresql/12/lib/bachelor_fdw.so: undefined symbol: warpclient_getData

The warp_client.h has the function headers and warp_client.c has the functions. warp_client.h 有函数头,warp_client.c 有函数。 warp_client.c includes "warp_client.h", bachelor_fdw.c (the extension) includes "warp_client.h". warp_client.c 包括“warp_client.h”,bachelor_fdw.c(扩展名)包括“warp_client.h”。

warp_client.h: warp_client.h:

#ifndef TEST_FIELD_UCP_WARP_CLIENT_H
#define TEST_FIELD_UCP_WARP_CLIENT_H

#include <ucp/api/ucp.h>

int warpclient_queryServer(char *server_addr_local, int port, int useINet6, char *query);

void *warpclient_getData();

int warpclient_cleanup();

#endif //TEST_FIELD_UCP_WARP_CLIENT_H

Any more desired info?还有更多想要的信息吗? I would be really glad for any help.我会很高兴有任何帮助。

EDIT 1编辑 1

I use the functions from warp_client.h inside of bachelor_fdw.c.我使用来自单身汉 fdw.c 中的 warp_client.h 的函数。 Do i still need to export them?我还需要导出它们吗? I thought only functions, which get called from the postgresql server needs to be exported.我认为只有从 postgresql 服务器调用的函数需要导出。

Here is part of bachelor_fdw.c:以下是单身汉 fdw.c 的一部分:


#include <warp_client.h>
#include "postgres.h"
#include "foreign/fdwapi.h"
#include "foreign/foreign.h"
#include "nodes/nodes.h"
#include "optimizer/pathnode.h"
#include "optimizer/planmain.h"
...

PG_MODULE_MAGIC;

/*
 * SQL functions
 */
PG_FUNCTION_INFO_V1(bachelor_fdw_handler);
PG_FUNCTION_INFO_V1(bachelor_fdw_validator);

/*
 *  Extension initialization functions
 */
extern void _PG_init(void);
extern void _PG_fini(void);

/*
 * FDW callback routines
 */
static void bachelorBeginForeignScan(ForeignScanState *node, int eflags);
static TupleTableSlot *bachelorIterateForeignScan(ForeignScanState *node);
static void bachelorReScanForeignScan(ForeignScanState *node);
static void bachelorEndForeignScan(ForeignScanState *node);
static void bachelorGetForeignRelSize(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid);
static void bachelorGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid);
static ForeignScan* bachelorGetForeignPlan(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan);


void _PG_init(void){
    int ret = 0;
    void *data;
    ret = warpclient_queryServer(NULL, -1, 0, "SELECT TEST FROM TEST;");
    elog_debug("Testquery for server. Return code (%d)...\n", ret);
    while(NULL != (data = warpclient_getData())){
        elog_debug("Data received as fdw: %s\n", data);
    }
    elog_debug("Finished receiving data.\n");

    /* Call cleanup */
    ret = warpclient_cleanup();
    elog_debug("Warpclient cleanup (%d)...\n", ret);
}

And here is part of warp_client.c:这是warp_client.c的一部分:

#include "warp_client.h"

...

int warpclient_cleanup(){
    int ret = 0;

    //free buffers
    free(recvbuffer->buffer);
    free(recvbuffer);

    /* Close the endpoint to the server */
    debugmsg("Close endpoint.\n");
    ep_close();

    /* releasing UCX ressources */
    ucp_worker_destroy(ucp_worker);
    ucp_cleanup(ucp_context);

    return ret;
}

int warpclient_queryServer(char *server_addr_local, int port, int useINet6, char *query){
    /*
     * Initialize important connection variables
     */
    debugmsg("Initializing connection variables...\n");
    if(NULL != server_addr_local) server_addr = server_addr_local;
    if((port >= 0) && (port <= UINT16_MAX)) server_port = port;
    if(useINet6) ai_family = AF_INET6;

    int ret;

    /* Initialize the UCX required objects worker and context*/
    debugmsg("Initializing context and worker...\n");
    ret = init_context_and_worker();
    if (ret != 0) {
        fprintf(stderr, "Initializing worker or context failed! Exiting..\n");
        return -2;
    }

    /*
     * UCP objects: client_ep as communication endpoint for the worker.
     *              status for function error code check.
     */
    ucs_status_t status;

    /* ep initialization and exchange with server over sockets */
    debugmsg("Creating Client endpoint.\n");
    status = create_client_endpoint();
    if (status != UCS_OK) {
        fprintf(stderr, "failed to start client (%s)\n", ucs_status_string(status));
        return -1;
    }

    ret = send_query(query);
    if(ret!=0){
        debugmsg("Failed to connect to Server.\n");
    }

    return ret;
}

EDIT 2编辑 2

I managed to get a good step forward thanks to Laurenz Albe.感谢 Laurenz Albe,我成功地向前迈出了一大步。 But i still have a problem with a shared library used in my shared library.但是我的共享库中使用的共享库仍然存在问题。 Do I also need to link to shared libraries used in my own shared library, even though i linked that as i compiled my shared library before distribution?我是否还需要链接到我自己的共享库中使用的共享库,即使我在分发之前编译我的共享库时链接了它?

what I did:我做了什么:

I added SHLIB_LINK = -lwarp_client to the Makefile and also needed the line PG_LDFLAGS += -L.我在 Makefile 中添加了SHLIB_LINK = -lwarp_client并且还需要PG_LDFLAGS += -L. for the linker to find libwarp_client.so.让链接器找到 libwarp_client.so。 I also managed to include the environment variable LD_LIBRARY_PATH for the postgres service, so that it can find my library in the standard places.我还设法为 postgres 服务包含环境变量 LD_LIBRARY_PATH,以便它可以在标准位置找到我的库。 And removed the library from the DATA flag in the Makefile.并从 Makefile 中的 DATA 标志中删除了该库。

New Makefile:新生成文件:

EXTENSION = bachelor_fdw
MODULE_big = bachelor_fdw
DATA = bachelor_fdw--0.1.sql
OBJS = bachelor_fdw.o

ifdef DEBUG
$(info $(shell echo "debug ist an"))
endif

PG_LIBS = -lpq
SHLIB_LINK = -lwarp_client
PG_LDFLAGS += -L.

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)

Enrivonment variables:环境变量:

/proc/1551/environ | xargs -0 -n 1 echo
LD_LIBRARY_PATH=/usr/include/:/usr/include/ucx/:/usr/lib/:/usr/lib/ucx/
...

When using CREATE on the extension, my library gets used but postgres complains about another shared library, which my library uses.在扩展上使用 CREATE 时,我的库被使用,但 postgres 抱怨我的库使用的另一个共享库。

psql:only_create.sql:3: ERROR:  could not load library "/usr/lib/postgresql/12/lib/bachelor_fdw.so": /usr/lib/warpdrive/libwarp_client.so: undefined symbol: ucp_ep_create

The error clearly says, it uses my shared library from a subdirectory "warpdrive" in the included standard directory.该错误清楚地表明,它使用了我在包含的标准目录中的子目录“warpdrive”中的共享库。 The shared library from UCP is also in that standard directory: UCP 的共享库也在该标准目录中:

ls /usr/lib/ucx
cmake            libjucx.so.0.0.0  libucp.a         libucs.la        libuct.so
jucx-1.12.1.jar  libucm.a          libucp.la        libucs.so        libuct.so.0
libjucx.a        libucm.la         libucp.so        libucs.so.0      libuct.so.0.0.0
libjucx.la       libucm.so         libucp.so.0      libucs.so.0.0.0  pkgconfig
libjucx.so       libucm.so.0       libucp.so.0.0.0  libuct.a         ucx
libjucx.so.0     libucm.so.0.0.0   libucs.a         libuct.la

That looks like warpclient_getData gets used in your code, but you didn't link your shared object with the library that provides the function.这看起来像是在您的代码中使用了warpclient_getData ,但您没有将共享对象与提供该函数的库链接。 Add the library to the SHLIB_LINK variable:将库添加到SHLIB_LINK变量:

SHLIB_LINK = -lwarp

(That example assumes a library called libwarp.so .) (该示例假设一个名为libwarp.so的库。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM