# C++ interface inline or not?

**URL:** <https://swi-prolog.discourse.group/t/c-interface-inline-or-not/6409>\
**Category:** Discussion\
**Created:** [March 26, 2023, 7:30pm UTC](https://swi-prolog.discourse.group/t/c-interface-inline-or-not/6409 "2023-03-26T19:30:20Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [March 26, 2023, 7:30pm UTC](https://swi-prolog.discourse.group/t/c-interface-inline-or-not/6409/1 "2023-03-26T19:30:20Z")

</div>

In a related issue (maybe I should start a new thread?), I’m becoming concerned that `SWI-cpp2.h` will result in executable bloat, because every function is being marked as `inline` (there is no `SWI-cpp2.cpp` that contains the implementation of any of the functions or methods).

The reason for using `inline` everywhere is that it avoids the problems of different compilers’ name mangling – otherwise, we’d need multiple `libswpl.so`s – one for each possible compiler.

But I’m wondering if there’s an alternative – the user could build a `SWI-cpp2.o` (or `SWI-cpp2.cpp.o`) for their particular compiler and “statically” link that with their code. I don’t know enough about how `cmake` works to know how to package this, but maybe it wouldn’t be necessary because the “pack” install uses `make` (although there might be some `make`/`cmake` interactions that I don’t understand).

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 27, 2023, 10:10am UTC](https://swi-prolog.discourse.group/t/c-interface-inline-or-not/6409/2 "2023-03-27T10:10:53Z")

</div>

> [@peter.ludemann](#):
>
> I’m becoming concerned that `SWI-cpp2.h` will result in executable bloat, because every function is being marked as `inline` (there is no `SWI-cpp2.cpp` that contains the implementation of any of the functions or methods).

For now I prefer the portability and simplicity. With a library, we have to deal with different ABIs as well as different versions, making it all pretty complex. And, luckily most interfaces are rather small. The two tests you wrote do seem to indicate that the C++ binary is a lot longer (\>10 times) than the C one. I haven’t checked in how far the tested functionality is comparable.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [March 27, 2023, 9:32pm UTC](https://swi-prolog.discourse.group/t/c-interface-inline-or-not/6409/3 "2023-03-27T21:32:31Z")

</div>

My proposal is to make a file `SWI-cpp2.cpp`, which contains all the non-inline code. This would _not_ be compiled as part of `libswpl.so` – instead, it would be compiled (as a separate `.o`) as part of whatever foreign predicate code uses `SWI-cpp2.h`. This avoids the problem of different ABIs (everything is built with the same compiler) and also prevents a code size explosion from everything being marked `inline`.

It’s a bit of work to do the splitting-up, so I’d like agreement before proceeding. (And there’s always a chance that it won’t work – C++ compilers and the language spec can have some unpleasant subtleties; but I presume that a package can have multiple `.o` files, which are combined into a single `.so` for the foreign predicates code; and I presume there’s no problem with the same `extern` functions appearing in multiple `.so` files.)

Right now, the following is the biggest “inline” function (I’ve removed the comments). All the code inside the `if (!rc)` could be done with a non-inline function, but currently it’s done for every call to a `PL_*()` function that has a return code (which is most of them).

```cpp
template<typename C_t> [[nodiscard]] C_t
PlWrap(C_t rc, qid_t qid)
{ if ( !rc )
  { PlTerm_term_t ex(PL_exception(qid));
    if ( ex.not_null() )
    { static PlFunctor FUNCTOR_error_2("error", 2);
      static PlFunctor FUNCTOR_resource_error_1("resource_error", 1);
      if ( ex.is_functor(FUNCTOR_error_2) &&
           ex[1].is_functor(FUNCTOR_resource_error_1) )
        throw PlFail();
      const PlException ex2(ex);
      PL_clear_exception();
      throw ex2;
    }
  }
  return rc;
}

```

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [March 27, 2023, 9:52pm UTC](https://swi-prolog.discourse.group/t/c-interface-inline-or-not/6409/4 "2023-03-27T21:52:07Z")

</div>

It seems that the compiler isn’t required to obey an `inline` directive (and if it doesn’t inline, it also won’t produce the multiple-definition errors): [Inline (Using the GNU Compiler Collection (GCC))](https://gcc.gnu.org/onlinedocs/gcc/Inline.html)

However, we need at least 3 ways of specifying “you don’t need to inline this” (g++, clan, plus whatever MacOS uses; and then there’s Windows), possibly over multiple versions of the compilers. So, I’d prefer a straightforward approach that doesn’t get into compiler-specific details. I _think_ that what I’m proposing is simple for people to use and avoids the ABI-incompatibility problems.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [March 28, 2023, 7:33am UTC](https://swi-prolog.discourse.group/t/c-interface-inline-or-not/6409/5 "2023-03-28T07:33:04Z")

</div>

> [@peter.ludemann](#):
>
> It’s a bit of work to do the splitting-up, so I’d like agreement before proceeding.

I still don’t really see the point of it, but there seems to be a simple in between: split and use a macro that allows defining how the functions of SWI-cpp2.cpp are defined, which can be one of `inline`, `static` or just global such that you can create a library from it. People can use it as they like.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [March 28, 2023, 4:52pm UTC](https://swi-prolog.discourse.group/t/c-interface-inline-or-not/6409/6 "2023-03-28T16:52:09Z")

</div>

> [@jan](#):
>
> I still don’t really see the point of it

Removes generated code bloat and makes compilation faster.  
And it seems to have exposed some other issues with order of constructors … more fun times for me with gdb. ☹

> [@jan](#):
>
> a macro that allows defining how the functions of SWI-cpp2.cpp are defined, which can be one of `inline`, `static` or just global such that you can create a library from it.

This will be easy to add if needed. For now, I’m trying to reduce the complications as much as possible.  
The easiest way of using my current code is by adding `#include <SWI-cpp2.cpp>` in the foreign predicate’s source file (which is what I did to `swipl-win/main.cpp`), or by adding `SWI-cpp2.cpp` to the `swipl_plugin` stanza.
