Component of the Week #40: bsls_linkcoercion

Summary:
  • Provides a macro to force a link-time dependency on a symbol.

  • Useful for generating link-time failures when library version mismatches occur.

The bsls_linkcoercion component provides a single macro, BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY, that forces a link-time dependency on a specified symbol. This macro is particularly useful for preventing binary-incompatible object files from being successfully linked together.

Basic Usage

To use link coercion, you need to:

  1. Define a macro that produces different symbol names for different build configurations or different library versions

  2. Declare the external symbol in a header of your library that is included by all headers

  3. Use BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY to create the dependency

  4. Define the symbol in the .cpp file corresponding to the header

Here’s an example that prevents linking code compiled against different major versions of a library:

// mylib_version.h
#include <bsls_linkcoercion.h>

#define MYLIB_VERSION_MAJOR 2

#if MYLIB_VERSION_MAJOR == 1
    #define MYLIB_LINKSYMBOL mylib_version_1
#elif MYLIB_VERSION_MAJOR == 2
    #define MYLIB_LINKSYMBOL mylib_version_2
#else
    #error Unsupported MYLIB version
#endif

extern const char* MYLIB_LINKSYMBOL;

BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY(const char *,
                                          mylib_version_coercion,
                                          MYLIB_LINKSYMBOL)
// mylib_version.cpp
#include <mylib_version.h>

const char *MYLIB_LINKSYMBOL = "mylib 2.x";

With this setup, if a client compiles their code with 2.x headers but tries to link against a 1.x library (which only defines mylib_version_1), the linker will fail with an undefined symbol error for mylib_version_2.

How It Works

The macro creates a static variable that references the external symbol. The implementation varies by platform to ensure the reference is not optimized away by the compiler or removed by linker garbage collection.

Because the name of the generated symbol will appear in the error message whenever we try to link against a library that doesn’t define exactly the same symbol we do our best to use symbol names that will be descriptive and helpful. For example, the symbols used to be sure that the correct version of bde libraries include the name of the library, the version of the library, and then compiled_this_object (i.e., s_version_BSL_4_33_compiled_this_object) to include sufficient information in the linker error to be self-explanatory.

For more information, see the documentation for bsls_linkcoercion.