Interoperability & C++ Compilers

Interoperability among C++ compilers is a good thing. All it takes is a common Application Binary Interface.


March 01, 2004
URL:http://www.drdobbs.com/interoperability-c-compilers/184401769

March 04: Interoperability & C++ Compilers

When new compilers are introduced on existing platforms, it is important that they work with other compilers on that same platform. Users need to be able to mix code generated by the new compiler with code generated by the existing ones. Interoperability is the ability to mix the object files and libraries generated by more than one compiler and expect the resulting executable image to run successfully.

Application Binary Interfaces (ABI) describe the contents of the object files and executable images emitted by compilers. Platform descriptions have included common C ABI documents for years. As a result, interoperable C compilers are a common occurrence. However, C++ compilers have not been able to achieve this level of interoperability due to the lack of a common C++ ABI.

Recently, a common C++ ABI was developed that has been adopted on multiple platforms. As a result, it is now possible to develop interoperable C++ compilers. The advantages of using ABI-conformant C++ compilers include:

In this article, I'll describe what is required for C++ compilers to be interoperable, why this level of interoperability can be achieved today, and how interoperability benefits programmers.

What Does Compiler Interoperability Mean?

Two compilers are considered to be interoperable if:

This applies to any two source files that share common data structures and/or have at least one function call from one file to a function defined in the other file.

When the topic of interoperability between two compilers arises, some people believe that conforming to the programming language standard, emitting the same object file format, and emitting the same debug format as another compiler is sufficient. It is true that these are important interoperability requirements. No further requirements would be needed if the two files do not share any data structures and there are no calls to functions defined in another source file.

Few useful applications can be organized into files that do not share anything between them. Once information sharing starts happening, the format of the information shared must be specified. Therefore, language conformance, a common object file format, and a common debug format are only the beginning of what is required for compiler interoperability.

Programming language standards define the syntax and semantics of a language. They usually also define a set of standard library routines. The library routines constitute an API. This information is sufficient for users who develop an application on one platform, port that application to another platform, and expect their source to compile if standard language constructs are used.

However, programming language standards do not specify how two conforming compilers work together. For example, the C and C++ Standards specify a long type. However, these documents do not specify the size or alignment of long. One compiler could recognize long as a 32-bit quantity and another compiler could recognize it as a 64-bit quantity. Both compilers conform to the programming language standard, but the output of these compilers is not interoperable.

The ABI for a programming language and platform defines what it means for compilers supporting that language and platform to interoperate. This is the document that specifies whether long has a size of 32 bits or 64 bits, and whether it is 4-byte aligned or 8-byte aligned. Other details must be specified in this document for interoperability to become a reality.

C Interoperability Requirements

The first step in achieving C++ interoperability is achieving C interoperability. Interoperability between two C compilers adds the requirements that the two compilers must:

Data structure layout and calling conventions are usually described in the ABI. An example of a C ABI is described in the IA-64 Software Conventions and Runtime Architecture Guide [4].

Note that it is not sufficient for the two compilers to provide their own standard header files. If the internal representation of the standard data structures do not match, it is likely that the result of the mixed compilation will not run. This violates the definition of compiler interoperability. Therefore, it is customary that interoperable C compilers use the same set of system headers.

Similar preprocessor symbol definitions are required to deal with situations such as this:

#ifdef FOO
int foo(int a, int b, int c);
#else
int foo(int a, int b);
#endif

If this code is in a header file included by both source files and one compiler defines FOO while the other compiler does not define FOO, the generated code will not be interoperable. This is because the function foo has a different argument list depending on which compiler is used.

C++ Interoperability Requirements

In addition to the C requirements, C++ interoperability requires that interoperable compilers implement the same C++ object model. The C++ object model has received a lot less coverage than most C++ application programming issues. A detailed description of C++ object models is provided in Stanley Lippman's Inside the C++ Object Model [1]. In general, a C++ object model defines the following:

Interoperable C++ compilers must also support template instantiation mechanisms that can work with each other. If one compiler requires a prelinking phase while the other compiler emits all instantiations and expects the linker to eliminate duplicates, link-time conflicts will likely result. Template instantiation alternatives are described in C++ Templates: The Complete Guide, by David Vandevoorde and Nicolai M. Josuttis [3].

It is also desirable to make sure that other external files generated by the compilers are compatible or do not interfere with each other. For example, if two compilers support precompiled headers and output differently formatted files using the same file naming convention, the application build will take longer. This is because the precompiled header files will keep conflicting and need to be regenerated. If the precompiled header file formats are different, the compilers should have different file-naming conventions. The situation is similar for source browser files.

Why C++ Interoperability Can Be Achieved Today

When a new platform is developed, it is traditional for the owner of the platform to specify the C ABI. Any compiler vendor developing a C compiler for that platform would then conform to that ABI. However, the C++ ABI is traditionally specified by the compiler vendor. This means that each C++ compiler for a given platform implements a different C++ object model. As a result, C++ interoperability between two compilers is a rare occurrence.

A few years ago, a consortium of compiler vendors realized that C++ interoperability could not happen with this model of development. The result of this consortium was the C++ ABI described in [2]. The first implementation of this ABI was for the Intel Itanium processor. Implementations of this ABI have also been done for the Pentium, ARM, and other processors by multiple C++ compiler vendors. The C++ ABI has also been endorsed by the Linux Standard Base (LSB) for use with C++ compilers on Linux systems.

Additionally, test suites have been developed to measure conformance to the C++ ABI [6]. These suites check that the code generated by the C++ compiler conforms to the C++ ABI specification.

The availability of multiple C++ compilers that conform to the C++ ABI has presented another validation opportunity. It is now possible to generate tests that are partially compiled by two C++ ABI-conformant compilers and compare the results. This approach finds problems that the conformance suites might miss, or finds issues in areas the conformance suites do not address.

The techniques I've described here have been used to create two compilers that conform to the C++ ABI and have established interoperability with each other. The Intel Compilers for the Pentium and Itanium families can interoperate with GCC 3.2 and its current successors on Linux platforms [7]. This demonstrates that C++ interoperability can indeed become a reality.

The existence of the C++ ABI represents a movement from compiler-specific C++ ABI specifications to a platform-specific ABI specification, as was done in [5]. The availability of conforming compilers and conformance suites allows the conformance levels of C++ compilers to be measured. Therefore, we have reached a point in the evolution of C++ where C++ interoperability can achieve the availability that C interoperability has enjoyed for years.

The Benefits of C++ Interoperability

C++ interoperability provides a significant benefit to many vendors in the C++ market. The fact that object files generated by different C++ compilers can be linked together to form an executable image that runs correctly creates several opportunities.

Conclusion

C compilers have been interoperable with each other for years. With the development of the C++ ABI specification [2] and the broad support it has received, interoperable C++ compilers have become a reality. C++ interoperability will benefit compiler vendors, third-party C++ vendors, and C++ users for years to come.

References

[1] Lippman, Stanley B., Inside the C++ Object Model, Addison-Wesley, 1996. ISBN 0-201-83454-5.

[2] Itanium C++ ABI, http://www.codesourcery.com/cxx-abi.

[3] Vandevoorde, David and Nicolai M. Josuttis, C++ Templates: The Complete Guide, Addison-Wesley, 2003. ISBN 0-201-73484-2.

[4] "Itanium Software Conventions and Runtime Architecture Reference Guide," http://developer.intel.com/design/itanium/downloads/245358.htm.

[5] Application Binary Interface for the ARM Architecture, http://www.armdevzone.com/ EABI/bsabi.pdf.

[6] C++ ABI Test Suite, http://www.codesourcery.com/abi_testsuite.

[7] Intel Compilers for Linux: Compatibility with GNU Compilers, http://www.intel.com/software/products/compilers/techtopics/LinuxCompilersCompatibility.htm.


Joe Goodman is a member of the Compiler Lab at Intel. He has been working with C++ compilers for over 10 years. Joe can be contacted at [email protected].


March 04:

Figure 1: C++ compiler interfaces.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.