Can I use extern "C" in an extension so I can use C++?

Started by Isaac Morlandover 5 years ago5 messages
#1Isaac Morland
isaac.morland@gmail.com

I'm writing a small extension, and I'm trying to use C++ constructs. I'm
not actually doing anything that needs C++, but I *really* like declaring
variables when I first initialize them (for example), and I also *really*
like warning-free compiles.

The C++ compiler is mangling the names so they aren't visible to the
extension mechanism. The following page suggests using extern C (it doesn't
specify that this means extern "C", but I suppose anybody who actually knew
what they were doing would have known that immediately):

https://www.postgresql.org/docs/current/xfunc-c.html

So I'm writing my functions to start:

extern "C" Datum ...

The problem is that PG_FUNCTION_INFO_V1 generates its own function
declaration with a conflicting extern specification (just plain extern,
which I guess means "C++" in the context of C++ code).

I also tried wrapping everything - both the functions and
the PG_FUNCTION_INFO_V1 invocations - in extern "C" { ... }, but now a
variable declaration from fmgr.h conflicts with one from the macros.

Is there a simple fix I'm missing? Any hints much appreciated.

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Isaac Morland (#1)
1 attachment(s)
Re: Can I use extern "C" in an extension so I can use C++?

Isaac Morland <isaac.morland@gmail.com> writes:

I'm writing a small extension, and I'm trying to use C++ constructs. I'm
not actually doing anything that needs C++, but I *really* like declaring
variables when I first initialize them (for example), and I also *really*
like warning-free compiles.

Well, you could get that with -Wno-declaration-after-statement ...
but yeah, this is supposed to work, modulo all the caveats on the
page you already found.

The C++ compiler is mangling the names so they aren't visible to the
extension mechanism.

Something like the attached works for me; what problem are you having
*exactly*?

$ g++ -Wall -fno-strict-aliasing -fwrapv -g -O2 -D_GNU_SOURCE -c -I/home/postgres/pgsql/src/include -o test.o test.cpp
$ nm --ext --def test.o
0000000000000000 T Pg_magic_func
0000000000000010 T pg_finfo_silly_func
0000000000000020 T silly_func

regards, tom lane

Attachments:

test.cpptext/x-c; charset=us-ascii; name=test.cppDownload
#3Isaac Morland
isaac.morland@gmail.com
In reply to: Tom Lane (#2)
2 attachment(s)
Re: Can I use extern "C" in an extension so I can use C++?

On Sun, 5 Jul 2020 at 18:07, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Isaac Morland <isaac.morland@gmail.com> writes:

I'm writing a small extension, and I'm trying to use C++ constructs. I'm
not actually doing anything that needs C++, but I *really* like declaring
variables when I first initialize them (for example), and I also *really*
like warning-free compiles.

Well, you could get that with -Wno-declaration-after-statement ...
but yeah, this is supposed to work, modulo all the caveats on the
page you already found.

The C++ compiler is mangling the names so they aren't visible to the
extension mechanism.

Something like the attached works for me; what problem are you having
*exactly*?

I've attached a .cpp file. When I run "make", I get:

g++ -Wall -Wpointer-arith -Wendif-labels -Wmissing-format-attribute
-Wformat-security -fno-strict-aliasing -fwrapv -g -g -O2
-fstack-protector-strong -Wformat -Werror=format-security -I. -I./
-I/usr/include/postgresql/12/server -I/usr/include/postgresql/internal
-Wdate-time -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -I/usr/include/libxml2
-I/usr/include/mit-krb5 -c -o hashblob.o hashblob.cpp
hashblob.cpp:9:18: error: conflicting declaration of ‘Datum
hashblob_touch(FunctionCallInfo)’ with ‘C’ linkage
9 | extern "C" Datum hashblob_touch (PG_FUNCTION_ARGS) {
| ^~~~~~~~~~~~~~
In file included from hashblob.cpp:2:
hashblob.cpp:6:21: note: previous declaration with ‘C++’ linkage
6 | PG_FUNCTION_INFO_V1(hashblob_touch);
| ^~~~~~~~~~~~~~
/usr/include/postgresql/12/server/fmgr.h:405:14: note: in definition of
macro ‘PG_FUNCTION_INFO_V1’
405 | extern Datum funcname(PG_FUNCTION_ARGS); \
| ^~~~~~~~
[... and then the same set of 3 errors again for the other function ...]

Without the extern "C" stuff it compiles fine but the names are mangled;
renaming to .c makes it compile fine with non-mangled names. It also
compiles if I get rid of the PG_FUNCTION_INFO_V1 invocations; but the same
documentation page is pretty clear that is supposed to be needed; and then
I think it C++-mangles the names of functions that get called behind the
scenes ("undefined symbol: _Z23pg_detoast_datum_packedP7varlena" when I try
to CREATE EXTENSION).

I should add I'm using a Makefile I've also attached; it uses PGXS with
nothing special, but on the other hand it means I don't really understand
everything that is going on (in particular, I didn't pick whether to say
g++ or gcc, nor did I explicitly choose any of the arguments to the
command).

$ g++ -Wall -fno-strict-aliasing -fwrapv -g -O2 -D_GNU_SOURCE -c

Show quoted text

-I/home/postgres/pgsql/src/include -o test.o test.cpp
$ nm --ext --def test.o
0000000000000000 T Pg_magic_func
0000000000000010 T pg_finfo_silly_func
0000000000000020 T silly_func

Attachments:

Makefileapplication/octet-stream; name=MakefileDownload
hashblob.cppapplication/octet-stream; name=hashblob.cppDownload
#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Isaac Morland (#3)
Re: Can I use extern "C" in an extension so I can use C++?

Isaac Morland <isaac.morland@gmail.com> writes:

On Sun, 5 Jul 2020 at 18:07, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Something like the attached works for me; what problem are you having
*exactly*?

I've attached a .cpp file.

My example wrapped the Postgres #include's, the PG_MODULE_MAGIC call,
and the PG_FUNCTION_INFO_V1 call(s) in extern "C" { ... }. I'm pretty
sure you need to do all three of those things to get a working result
without mangled external function names.

regards, tom lane

#5Isaac Morland
isaac.morland@gmail.com
In reply to: Tom Lane (#4)
Re: Can I use extern "C" in an extension so I can use C++?

On Sun, 5 Jul 2020 at 18:49, Tom Lane <tgl@sss.pgh.pa.us> wrote:

My example wrapped the Postgres #include's, the PG_MODULE_MAGIC call,
and the PG_FUNCTION_INFO_V1 call(s) in extern "C" { ... }. I'm pretty
sure you need to do all three of those things to get a working result
without mangled external function names.

I wrapped my entire file - #includes and all - in extern "C" { ... } and it
worked perfectly. Thanks very much for your assistance and patience.