Re: Why do we test a build using g++?

[email protected] (Leon Timmermans) Tue, 30 Jun 2026 01:39:37 +0200
Newsgroups perl.perl5.porters
Message-ID <CAHhgV8gBtFs3wcpjA1fUW+qHnwxnZ6EZZGrzBr21P9Z7RdZN7g@mail.gmail.com>
--0000000000005ce07e06556cf9fb
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Mon, Jun 29, 2026 at 11:42=E2=80=AFPM Paul "LeoNerd" Evans <
[email protected]> wrote:

> TL;DR: We have some CI test builds that use -Dcc=3D'g++', to test if we c=
an
>   build perl using g++ as the "C" compiler. I wonder - why do we do this?
>   Perl is written in C, not C++, which is a different language. Can we
>   please not?


Actually, we have one file in Windows that uses C++ (on IMPLICIT_SYS builds
at least).


> I ask because it's increasingly annoying and getting in the way. Before
> we added C99 (and thus were only using C89 features), this wasn't so
> bad, but we introduced C99 specifically so we could use some features
> that were introduced only 25 years ago, instead of having to stick to
> features that are over 35 years old.
>
> One feature of C99 that I intend to use a lot is the ability to
> initialise structures with named initialisers, and to be able to omit
> fields to imply the compiler-assigned defaults of zero for integers or
> NULL for pointers. This makes it nicely convenient to initialise
> structures that, for example, have optional "flags" or other features
> in them, or pointers that are rarely used, and so most of the time you
> leave them as NULL. Not having to write lots of extra lines in the
> source makes the code clearer.
>
> The default C99-and-not-C++ compiler is perfectly happy for me to write
> code such as:
>
>   static const struct MagicFunctions magicfuncs_customop_xop =3D {
>       .ver   =3D 2,
>       .shape =3D MGv2s_BASE,
>       .debug_name =3D "customop_xop",
>       .free_mg =3D &customop_xop_free,
>   };
>
> This is relatively easy on the human eye, because it draws attention to
> only those fields that we're putting something interesting in, without
> a lot of extra clutter. It's almost as nice as having named parameters
> with optional defaults in them. ;)
>
> But g++ doesn't like this; it complains:
>
>   op.c:16427:1: warning: missing initializer for member
>       =E2=80=98MagicFunctions::_v1_vtbl=E2=80=99 [-Wmissing-field-initial=
izers]
>   16427 | };
>         | ^
>   op.c:16427:1: warning: missing initializer for member
>       =E2=80=98MagicFunctions::flags=E2=80=99 [-Wmissing-field-initialize=
rs]
>   op.c:16427:1: warning: missing initializer for member
>       =E2=80=98MagicFunctions::user_size=E2=80=99 [-Wmissing-field-initia=
lizers]
>   op.c:16427:1: warning: missing initializer for member
>       =E2=80=98MagicFunctions::clone_mg=E2=80=99 [-Wmissing-field-initial=
izers]
>
> In order to appease it, I tried just adding a bunch of zero/NULL/{}
> fields at the end of the struct; but then it complains:
>
>   op.c:16432:1: error: designator order for field =E2=80=98MagicFunctions=
::flags=E2=80=99
>       does not match declaration order in =E2=80=98const MagicFunctions=
=E2=80=99
>
> It also still gets upset that initialisers that I have in fact written
> aren't there, because it doesn't see them. Or something. I don't know,
> I'm not a C++ programmer. I write in C.
>
> It seems the only way to make it happy is to write a lot more noisy
> structure, that's far worse on the human reader:
>
>   static const struct MagicFunctions magicfuncs_customop_xop =3D {
>       ._v1_vtbl =3D {},
>       .ver   =3D 2,
>       .shape =3D MGv2s_BASE,
>       .flags =3D 0,
>       .debug_name =3D "customop_xop",
>       .user_size =3D 0,
>       .free_mg =3D &customop_xop_free,
>       .clone_mg =3D NULL,
>   };
>
> I find this quite a bit worse to look at, because of all those empty
> junk lines being added. It makes it harder to see what's "interesting"
> about this struct, as even the zeroes and the NULLs are in there. Plus
> that leading ._v1_vtbl is even worse. It's present in the structure
> definition itself in order to make a compatible hole with (version 1)
> MAGIC structure, but shouldn't really be thought about or visible as
> part of the v2 API. So having to add it in *every* struct
> initialisation is very annoying indeed.
>
> Aside from being more cluttered and less clear to look at to the human
> reader, I also find this worse for longterm maintainability. A key
> selling point of C99's ability to imply zeroes/etc.. for fields you
> don't name, is that if you later extend the struct definition by adding
> more fields to it, you don't have to go around all your initialisers
> everywhere to add more ".foo =3D 0" lines. You can just ignore them,
> knowing they will default to zeroes if you don't need them. It makes it
> easier and nicer to extend those data types later without breaking
> existing source code. Plus, an actual C99 compiler doesn't care if the
> named initialisers don't appear in the same order as the fields in the
> struct. The whole point of naming them is that now order doesn't
> matter. You can reorder the elements in the struct without upsetting
> users of that struct, even in initialisers. Yes you'll still have to
> recompile it - but that's fine for all the code within the source tree.
> You just don't have to manually edit all your .c files.
>
>
> I think therefore I have made a reasonable case for wanting to be able
> to use this C99 named initialiser syntax. So now I want to understand
> why we care if we can compile perl source using g++.
>
> I understand that historically we have used this as a test to see that
> perl's *headers* are suitable for use by both a C compiler and a C++
> compiler, for those folks who want to write XS extensions in C++. That
> made sense when we were only using C89, and the C++ compilers were
> basically able to handle a superset of that anyway. But C99 and C++
> diverge a little, so that is no longer really true.
>
> I'm not aware of any direct reason why the source of the perl binary
> itself needs to be compilable by a C++ compiler; especially not since
> it gets in the way of us writing the code we want to write - in C99.
>

Yeah, that is an annoying issue. We also hit it in PR#24390


> I'd like to propose that (if there isn't another valid reason that is
> stronger than our desire to use C99 features) we find another way to
> test if the perl headers are compatible with C++. For example, could we
> ship a tiny "helloworld.cpp" program that also pulls in <perl.h> and
> <XSUB.h> or somesuch? Or maybe we write a tiny XS extension in C++ and
> compiled with g++, to use for such testing purposes?
>

Well volunteered! ;-)

Leon

--0000000000005ce07e06556cf9fb
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr">On Mon, Jun 29, 2026 at =
11:42=E2=80=AFPM Paul &quot;LeoNerd&quot; Evans &lt;<a href=3D"mailto:leone=
[email protected]" target=3D"_blank">[email protected]</a>&gt; wrote:<=
/div><div dir=3D"ltr"><div class=3D"gmail_quote"><blockquote class=3D"gmail=
_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204=
,204);padding-left:1ex">TL;DR: We have some CI test builds that use -Dcc=3D=
&#39;g++&#39;, to test if we can<br>
=C2=A0 build perl using g++ as the &quot;C&quot; compiler. I wonder - why d=
o we do this?<br>
=C2=A0 Perl is written in C, not C++, which is a different language. Can we=
<br>
=C2=A0 please not?</blockquote><div><br></div><div>Actually, we have one fi=
le in Windows that uses C++ (on IMPLICIT_SYS builds at least).</div><div>=
=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

I ask because it&#39;s increasingly annoying and getting in the way. Before=
<br>
we added C99 (and thus were only using C89 features), this wasn&#39;t so<br=
>
bad, but we introduced C99 specifically so we could use some features<br>
that were introduced only 25 years ago, instead of having to stick to<br>
features that are over 35 years old.<br>
<br>
One feature of C99 that I intend to use a lot is the ability to<br>
initialise structures with named initialisers, and to be able to omit<br>
fields to imply the compiler-assigned defaults of zero for integers or<br>
NULL for pointers. This makes it nicely convenient to initialise<br>
structures that, for example, have optional &quot;flags&quot; or other feat=
ures<br>
in them, or pointers that are rarely used, and so most of the time you<br>
leave them as NULL. Not having to write lots of extra lines in the<br>
source makes the code clearer.<br>
<br>
The default C99-and-not-C++ compiler is perfectly happy for me to write<br>
code such as:<br>
<br>
=C2=A0 static const struct MagicFunctions magicfuncs_customop_xop =3D {<br>
=C2=A0 =C2=A0 =C2=A0 .ver=C2=A0 =C2=A0=3D 2,<br>
=C2=A0 =C2=A0 =C2=A0 .shape =3D MGv2s_BASE,<br>
=C2=A0 =C2=A0 =C2=A0 .debug_name =3D &quot;customop_xop&quot;,<br>
=C2=A0 =C2=A0 =C2=A0 .free_mg =3D &amp;customop_xop_free,<br>
=C2=A0 };<br>
<br>
This is relatively easy on the human eye, because it draws attention to<br>
only those fields that we&#39;re putting something interesting in, without<=
br>
a lot of extra clutter. It&#39;s almost as nice as having named parameters<=
br>
with optional defaults in them. ;)<br>
<br>
But g++ doesn&#39;t like this; it complains:<br>
<br>
=C2=A0 op.c:16427:1: warning: missing initializer for member<br>
=C2=A0 =C2=A0 =C2=A0 =E2=80=98MagicFunctions::_v1_vtbl=E2=80=99 [-Wmissing-=
field-initializers]<br>
=C2=A0 16427 | };<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 | ^<br>
=C2=A0 op.c:16427:1: warning: missing initializer for member<br>
=C2=A0 =C2=A0 =C2=A0 =E2=80=98MagicFunctions::flags=E2=80=99 [-Wmissing-fie=
ld-initializers]<br>
=C2=A0 op.c:16427:1: warning: missing initializer for member<br>
=C2=A0 =C2=A0 =C2=A0 =E2=80=98MagicFunctions::user_size=E2=80=99 [-Wmissing=
-field-initializers]<br>
=C2=A0 op.c:16427:1: warning: missing initializer for member<br>
=C2=A0 =C2=A0 =C2=A0 =E2=80=98MagicFunctions::clone_mg=E2=80=99 [-Wmissing-=
field-initializers]<br>
<br>
In order to appease it, I tried just adding a bunch of zero/NULL/{}<br>
fields at the end of the struct; but then it complains:<br>
<br>
=C2=A0 op.c:16432:1: error: designator order for field =E2=80=98MagicFuncti=
ons::flags=E2=80=99<br>
=C2=A0 =C2=A0 =C2=A0 does not match declaration order in =E2=80=98const Mag=
icFunctions=E2=80=99<br>
<br>
It also still gets upset that initialisers that I have in fact written<br>
aren&#39;t there, because it doesn&#39;t see them. Or something. I don&#39;=
t know,<br>
I&#39;m not a C++ programmer. I write in C.<br>
<br>
It seems the only way to make it happy is to write a lot more noisy<br>
structure, that&#39;s far worse on the human reader:<br>
<br>
=C2=A0 static const struct MagicFunctions magicfuncs_customop_xop =3D {<br>
=C2=A0 =C2=A0 =C2=A0 ._v1_vtbl =3D {},<br>
=C2=A0 =C2=A0 =C2=A0 .ver=C2=A0 =C2=A0=3D 2,<br>
=C2=A0 =C2=A0 =C2=A0 .shape =3D MGv2s_BASE,<br>
=C2=A0 =C2=A0 =C2=A0 .flags =3D 0,<br>
=C2=A0 =C2=A0 =C2=A0 .debug_name =3D &quot;customop_xop&quot;,<br>
=C2=A0 =C2=A0 =C2=A0 .user_size =3D 0,<br>
=C2=A0 =C2=A0 =C2=A0 .free_mg =3D &amp;customop_xop_free,<br>
=C2=A0 =C2=A0 =C2=A0 .clone_mg =3D NULL,<br>
=C2=A0 };<br>
<br>
I find this quite a bit worse to look at, because of all those empty<br>
junk lines being added. It makes it harder to see what&#39;s &quot;interest=
ing&quot;<br>
about this struct, as even the zeroes and the NULLs are in there. Plus<br>
that leading ._v1_vtbl is even worse. It&#39;s present in the structure<br>
definition itself in order to make a compatible hole with (version 1)<br>
MAGIC structure, but shouldn&#39;t really be thought about or visible as<br=
>
part of the v2 API. So having to add it in *every* struct<br>
initialisation is very annoying indeed.<br>
<br>
Aside from being more cluttered and less clear to look at to the human<br>
reader, I also find this worse for longterm maintainability. A key<br>
selling point of C99&#39;s ability to imply zeroes/etc.. for fields you<br>
don&#39;t name, is that if you later extend the struct definition by adding=
<br>
more fields to it, you don&#39;t have to go around all your initialisers<br=
>
everywhere to add more &quot;.foo =3D 0&quot; lines. You can just ignore th=
em,<br>
knowing they will default to zeroes if you don&#39;t need them. It makes it=
<br>
easier and nicer to extend those data types later without breaking<br>
existing source code. Plus, an actual C99 compiler doesn&#39;t care if the<=
br>
named initialisers don&#39;t appear in the same order as the fields in the<=
br>
struct. The whole point of naming them is that now order doesn&#39;t<br>
matter. You can reorder the elements in the struct without upsetting<br>
users of that struct, even in initialisers. Yes you&#39;ll still have to<br=
>
recompile it - but that&#39;s fine for all the code within the source tree.=
<br>
You just don&#39;t have to manually edit all your .c files.<br>
<br>
<br>
I think therefore I have made a reasonable case for wanting to be able<br>
to use this C99 named initialiser syntax. So now I want to understand<br>
why we care if we can compile perl source using g++.<br>
<br>
I understand that historically we have used this as a test to see that<br>
perl&#39;s *headers* are suitable for use by both a C compiler and a C++<br=
>
compiler, for those folks who want to write XS extensions in C++. That<br>
made sense when we were only using C89, and the C++ compilers were<br>
basically able to handle a superset of that anyway. But C99 and C++<br>
diverge a little, so that is no longer really true.<br>
<br>
I&#39;m not aware of any direct reason why the source of the perl binary<br=
>
itself needs to be compilable by a C++ compiler; especially not since<br>
it gets in the way of us writing the code we want to write - in C99.<br></b=
lockquote><div><br></div><div>Yeah, that is an annoying issue. We also hit =
it in PR#24390</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddin=
g-left:1ex">
I&#39;d like to propose that (if there isn&#39;t another valid reason that =
is<br>
stronger than our desire to use C99 features) we find another way to<br>
test if the perl headers are compatible with C++. For example, could we<br>
ship a tiny &quot;helloworld.cpp&quot; program that also pulls in &lt;perl.=
h&gt; and<br>
&lt;XSUB.h&gt; or somesuch? Or maybe we write a tiny XS extension in C++ an=
d<br>
compiled with g++, to use for such testing purposes?<br></blockquote><div><=
br></div><div>Well volunteered! ;-)</div><div><br></div><div>Leon</div></di=
v></div>
</div>
</div>

--0000000000005ce07e06556cf9fb--