如何让 PostgreSQL 加载依赖 DLL 的 C 模块?

Posted

技术标签:

【中文标题】如何让 PostgreSQL 加载依赖 DLL 的 C 模块?【英文标题】:How to make PostgreSQL to load a C-module that depends on a DLL? 【发布时间】:2016-07-21 00:47:42 【问题描述】:

我尝试从依赖于 Windows 中另一个 DLL 的模块在 PostgreSQL 中创建 C 语言函数,但没有成功。

例如,假设我想创建一个sum函数,它将两个数字相加,这两个数字由它自己的 DLL 中的number函数返回。

number.h 的代码是:

#ifndef NUMBER_H
#define NUMBER_H

#ifdef NUMBER_EXPORTS
#define NUMBER_API __declspec(dllexport)
#else
#define NUMBER_API __declspec(dllimport)
#endif

extern "C" NUMBER_API int number();

#endif

number.cpp 的代码是:

#include "number.h"
extern "C" int number()  return 1; 

sum.cpp 的代码是:

extern "C" 

#include <postgres.h>
#include <fmgr.h>
#include <utils/geo_decls.h>
#include "number.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

__declspec(dllexport) PG_FUNCTION_INFO_V1(sum);

Datum sum(PG_FUNCTION_ARGS)

    int32 a number();
    int32 b number();
    int32 result a + b;
    PG_RETURN_INT32(result);


 // extern "C"

假设 PostgreSQL 安装在 C:\Program Files\PostgreSQL\9.5 上,我使用这个 build.bat 文件创建 number.dllsum.dll

SET PG_DIR=C:\Program Files\PostgreSQL\9.5
SET PG_INCLUDES=/I%PG_DIR%\include /I%PG_DIR%\include\server /I%PG_DIR%\include\server\port\win32
CL number.cpp /EHsc /MD /DNUMBER_EXPORTS /LD
CL sum.cpp /EHsc /MD %PG_INCLUDES% /LD /link number.lib

然后我将两个 DLL 复制到 C:\Program Files\PostgreSQL\9.5\lib 并编写 SQL 用于在 sum.sql 中创建函数:

CREATE OR REPLACE FUNCTION sum() RETURNS void AS
'sum'
LANGUAGE C STRICT;

运行psql -U postgres -f sum.sql后,出现如下错误:

psql:sum.sql:3: ERROR:  could not load library "C:/Program Files/PostgreSQL/9.5/lib/sum.dll": The specified module could not be found.

请注意,此错误与“找不到文件”错误不同。似乎 PostgreSQL 找到了该文件,但没有将其识别为有效模块。但是,如果我改为创建num.cpp 的静态库并将其链接到sum.dll,则该函数创建成功。换句话说,PostgreSQL 只有在模块包含它需要的所有代码时才加载它。

为什么会发生这种情况,我如何让 PostgreSQL 在创建 sum 函数时知道 number.dll

【问题讨论】:

看看sum.dll in-place in lib/ with Depenency Walker (depends.exe),它可能很有启发性。 感谢您的建议。我在sum.dll 上尝试了depends.exe 工具。正如预期的那样,number.dll 显示为依赖项,但 psql 拒绝加载它。 没有依赖 walker 抱怨依赖,但是?我通常通过 Visual Studio 使用 msbuild 构建 Pg 扩展;见blog.2ndquadrant.com/…。 PostgreSQL 不关心扩展 DLL 需要的任何额外库,操作系统负责加载它们。 The specified module could not be found. 是来自 Windows 的 LoadLibrary 调用的错误,而不是 PostgreSQL 内部生成的错误。它可能引用您的扩展 sum.dllsum.dll 所需的任何其他 DLL,但遗憾的是没有说明是哪个 我看了这篇文章,自己做的。那里有一些我没有考虑过的方面。但是,DemoExtension 不引用其他 DLL,这使得它非常简单。我尝试使用我自己的代码执行相同的步骤,但我仍然遇到同样的问题。此外,DemoExtension 是一个纯 C 示例,我需要它用于 C++。文章说 PostgreSQL 不能与 C++ 一起工作,但根据文档,它可以按照 C++ 可扩展性指南工作。 这是一个最小的例子。随意提交一个更复杂的示例来演示其他库和 C++ 的使用,我很乐意将其合并。使用其他库的工作方式与任何其他代码库非常相似,但如果它是具有 C++ 接口的库,则必须通过 C/C++ 包装器/适配器层使用它。 【参考方案1】:

在启动 PostgreSQL 服务器之前,依赖 DLL 的目录必须存在于 PATH 中。

转到:

Control Panel
 System and Security
  System
   Advanced System Settings
    Advanced
     Environment Variables
      Path

打开它并添加依赖 DLL 所在的所有目录的完整路径。重启PostgreSQL服务器,完成,psql将成功执行C模块。

【讨论】:

以上是关于如何让 PostgreSQL 加载依赖 DLL 的 C 模块?的主要内容,如果未能解决你的问题,请参考以下文章

WinXP下如何修复DWMAPI.DLL延迟加载依赖?

如何让 AssImp 正常工作?

仅在需要时加载 DLL [重复]

如何查看exe或dll的依赖库dll

Ctypes找不到我加载的dll的dll依赖

如何在 Python 中从 SXS 加载 C DLL?