手工生成DuckDB 1.4版c++插件的简单步骤
-
到https://github.com/duckdb/extension-template 下载模板源代码压缩包, 把其中的src目录解压缩到/par/cppext14
-
到https://github.com/duckdb/duckdb/releases 下载1.4版动态库和静态库压缩包, 解压缩到/par/libduckdb
-
到https://github.com/duckdb/extension-ci-tools 下载https://github.com/duckdb/extension-ci-tools/blob/main/scripts/append_extension_metadata.py 文件到/par。
-
编译
g++ -fPIC -shared -o libtest2.so quack_extension.cpp -I /par/libduckdb -lssl -lcrypto -I include -lduckdb -L /par/libduckdb
编译出错,
quack_extension.cpp:5:10: fatal error: duckdb/common/exception.hpp: No such file or directory5 | #include "duckdb/common/exception.hpp"
将quack_extension.cpp中如下3行注释掉,因为他们的内容在动态库自带的duckdb.hpp都有。
//#include "duckdb/common/exception.hpp"
//#include "duckdb/function/scalar_function.hpp"
//#include <duckdb/parser/parsed_data/create_scalar_function_info.hpp>
5.添加元数据
注意要把版本号写为v1.4.0
root@6ae32a5ffcde:/par/agg# python3 /par/appendmetadata.py -l libtest2.so -n quack -dv v1.4.0 --duckdb-platform linux_amd64 --extension-version 0.1 --abi-type ""
Creating extension binary:- Input file: libtest2.so- Output file: quack.duckdb_extension- Metadata:- FIELD8 (unused) = EMPTY- FIELD7 (unused) = EMPTY- FIELD6 (unused) = EMPTY- FIELD5 (abi_type) =- FIELD4 (extension_version) = 0.1- FIELD3 (duckdb_version) = v1.4.0- FIELD2 (duckdb_platform) = linux_amd64- FIELD1 (header signature) = 4 (special value to identify a duckdb extension)
8.加载运行
因为动态库不在搜索路径,所以直接加载报错,设置环境变量LD_LIBRARY_PATH就好了
root@6ae32a5ffcde:/par/cppext14/src# /par/duckdb140 -unsigned
DuckDB v1.4.0 (Andium) b8a06e4a22
Enter ".help" for usage hints.
D load '/par/cppext14/src/quack.duckdb_extension';
IO Error:
Extension "/par/cppext14/src/quack.duckdb_extension" could not be loaded: libduckdb.so.1.4: cannot open shared object file: No such file or directory
D .exitroot@6ae32a5ffcde:/par/cppext14/src# export LD_LIBRARY_PATH=/par/libduckdbroot@6ae32a5ffcde:/par/cppext14/src# /par/duckdb140 -unsigned
DuckDB v1.4.0 (Andium) b8a06e4a22
Enter ".help" for usage hints.
D load '/par/cppext14/src/quack.duckdb_extension';
D select quack('asdf');
┌───────────────┐
│ quack('asdf') │
│ varchar │
├───────────────┤
│ Quack asdf 🐥 │
└───────────────┘
D select quack_openssl_version('abcd');
┌────────────────────────────────────────────────────────────────────┐
│ quack_openssl_version('abcd') │
│ varchar │
├────────────────────────────────────────────────────────────────────┤
│ Quack abcd, my linked OpenSSL version is OpenSSL 3.0.15 3 Sep 2024 │
└────────────────────────────────────────────────────────────────────┘
以上步骤比官方步骤最大的优势是不用编译DuckDB源代码,节省大量时间,等开发测试完成,正式发布前再用官方步骤执行。
我曾经想用链接静态库libduckdb_static.a来编译,结果编出来的文件大了许多,ldd看也不依赖duckdb动态库,但是仍然缺少符号,看来静态库里的函数不如动态库全。
root@6ae32a5ffcde:/par/cppext14/src# mv quack.duckdb_extension quack.duckdb_extension.14root@6ae32a5ffcde:/par/cppext14/src# g++ -fPIC -shared -o libtest2.so quack_extension.cpp -I /par/libduckdb -lssl -lcrypto -I include /par/libduckdb/libduckdb_static.a
root@6ae32a5ffcde:/par/cppext14/src# python3 /par/appendmetadata.py -l libtest2.so -n quack -dv v1.4.0 --duckdb-platform linux_amd64 --extension-version 0.1 --abi-type ""
Creating extension binary:- Input file: libtest2.so- Output file: quack.duckdb_extension- Metadata:- FIELD8 (unused) = EMPTY- FIELD7 (unused) = EMPTY- FIELD6 (unused) = EMPTY- FIELD5 (abi_type) =- FIELD4 (extension_version) = 0.1- FIELD3 (duckdb_version) = v1.4.0- FIELD2 (duckdb_platform) = linux_amd64- FIELD1 (header signature) = 4 (special value to identify a duckdb extension)
root@6ae32a5ffcde:/par/cppext14/src# ls -l quack.duckdb_extension*
-rwxrwxrwx 1 root root 37309110 Sep 29 12:54 quack.duckdb_extension
-rwxrwxrwx 1 root root 222182 Sep 29 12:39 quack.duckdb_extension.14
root@6ae32a5ffcde:/par/cppext14/src# /par/duckdb140 -unsigned
DuckDB v1.4.0 (Andium) b8a06e4a22
Enter ".help" for usage hints.
D load '/par/cppext14/src/quack.duckdb_extension';
IO Error:
Extension "/par/cppext14/src/quack.duckdb_extension" could not be loaded: /par/cppext14/src/quack.duckdb_extension: undefined symbol: _ZN10duckdb_fmt2v68internal10basic_dataIvE6digitsE
D .exit
root@6ae32a5ffcde:/par/cppext14/src# ldd quack.duckdb_extensionlinux-vdso.so.1 (0x00007fff8cfd2000)libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3 (0x00007f297d687000)libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x00007f297d201000)libstdc++.so.6 => /usr/local/lib64/libstdc++.so.6 (0x00007f297cf93000)libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f297ceb3000)libgcc_s.so.1 => /usr/local/lib64/libgcc_s.so.1 (0x00007f297ce86000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f297cca2000)/lib64/ld-linux-x86-64.so.2 (0x00007f297f514000)
root@6ae32a5ffcde:/par/cppext14/src# ldd quack.duckdb_extension.14linux-vdso.so.1 (0x00007ffe62ded000)libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3 (0x00007fd662763000)libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x00007fd6622dd000)libduckdb.so.1.4 => /par/libduckdb/libduckdb.so.1.4 (0x00007fd65ec99000)libstdc++.so.6 => /usr/local/lib64/libstdc++.so.6 (0x00007fd65ea2b000)libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd65e94b000)libgcc_s.so.1 => /usr/local/lib64/libgcc_s.so.1 (0x00007fd65e91c000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd65e73a000)libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fd65e735000)libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd65e730000)/lib64/ld-linux-x86-64.so.2 (0x00007fd662841000)
用工具查看,确实如此
root@6ae32a5ffcde:/par/cppext14/src# readelf -c /par/libduckdb/libduckdb_static.a |grep _ZN10duckdb_fmt2v68internal10basic_dataIvE6digitsEroot@6ae32a5ffcde:/par/cppext14/src# nm -D /par/libduckdb/libduckdb.so |grep _ZN10duckdb_fmt2v68internal10basic_dataIvE6digitsE
0000000003432280 u _ZN10duckdb_fmt2v68internal10basic_dataIvE6digitsE