Hello, and welcome to C++ Weekly. I'm your host Jason Turner. I am available for code
reviews and on-site training. Make sure you check out the video description for
info about upcoming conference workshops and swag and ways that you can support the channel,
as well as buying books that I have published. In this episode I'm going to talk a little bit
about ABI, ODR violations and tools that can prevent you from making those mistakes.
[Music]
All right. This episode is presumably going to be pretty short - let's give it a go. Now I have this
simple interface here where I've got something that uses data and forward declared data,
and I have something that provides data and a forward declared Data. In my main
I am using data with the get_data, and
my use_data function simply prints x and y. My get_data function has the values 1.23 and 4,
and I execute this, and without any real meaningful warnings (this is just a warning
about CMake here) I am getting what is clearly the absolutely wrong value printed, but no other
warnings to speak of from the compiler. So what went wrong here? Now if you were paying
careful attention you might have observed that in file1.cpp I have data declared as float y, int x
and in file2.cpp I have it as int x, float y, so the layout is different between these two types
but the compiler has no visibility into that. This is a very clear ODR violation; this is also
a problem with ABI. ODR stands for One Definition Rule - that is you can have only one definition of
a thing in a project, and ABI is the Application Binary Interface - these are things that I have
talked about in previous episodes. Now I'm going to show you a neat little trick that I recently
learned that can tell us when things have gone awry. In my CMake file I have this option to
enable interprocedural optimization - I did an episode specifically about IPO not that long ago.
So I'm just going to go ahead and enable that, and we're going to go back to our output window here,
and we're going to see that we now actually get a link time error that says "'struct Data' violates
the C++ One Definition Rule. A different type is defined in another translation unit. The first
difference of corresponding definitions is field 'y'. A field with a different name is defined in
another translation unit." So right there, there you have it. That is the entire issue found for
you by your compiler and debugged. Problem solved. No reason to worry about ABI or ODR issues at all
anymore - you just simply have to use IPO, which is also known as link time optimization. Now I'm
saying this slightly tongue-in-cheek because obviously it's not going to catch a hundred
percent of all issues, but I am now leaning strongly in towards saying that IPO (or LTO)
should always be the default for your programs. It can catch an entirely new class of bugs;
in many cases actually results in faster build times. Now builds are faster, links are slower,
but if you use a modern linker such as Mold, then you're going to get much faster linking
and results and higher performing code, so it's kinda hard to find a
downside here except for the fact that you have to compile all of your dependencies
with IPO enabled to get all of the benefits and prefer static linking.
Well, anyhow, thanks for watching this episode of C++ Weekly.
[Music]