emmtrix Link Stubber
The emmtrix Link Stubber is a Clang-based tool designed to augment C and C++ source files in a way that makes them linkable, even in the absence of complete implementations. This tool is particularly useful in early development phases, integration testing, unit testing, static analysis, or code generation pipelines where certain source components or libraries may not yet be available.
Motivation
Modern software development — especially in embedded and safety-critical domains — often involves compiling and analyzing incomplete systems. Missing function definitions or global variables can prevent successful linking, which blocks further tool-based processing like:
- Binary generation
- Static timing analysis
- Code instrumentation
- Unit test compilation
- Cross-module analysis
The emmtrix Link Stubber solves this by generating stub implementations for unresolved symbols, allowing compilation and linking to proceed without requiring full source availability.
Features
- Automatic Stub Generation
Automatically generates minimal placeholder implementations for:- Undefined functions, member functions, constructors or destructors
- External global or static variables
- Forward-declared classes and structs
- Function and class templates
- Abstract classes (with pure virtuals) are handled by:
- Finding a suitable concrete derived class
- Or generating a new one if none exists
- Multi-Translation-Unit (TU) Support
- Definitions can be generated across multiple input files
- Emits one output file per TU
- Clang Integration
Built on top of Clang’s frontend infrastructure for full compatibility with standard C/C++ codebases. - Minimal Intrusiveness
Generates valid, syntactically correct C/C++ code that can be:- Output as a separate file, or
- Directly appended to the end of the processed C/C++ source file.
- Inline Stub Insertion
In a common usage scenario, the stub code is inserted at the end of the original .cpp file, keeping everything in one translation unit. This avoids changes to build configurations and simplifies testing or integration. - Aggregate Initialization
Aggregate types are initialized with brace-enclosed initializer lists. - Selective Stubbing
Users can control symbol exclusion via opt-out list - Configuration
YAML config for advanced scenarios and per-file options
Use Cases
- Isolated Unit Testing
During unit testing, individual classes or functions are compiled without all dependent files. By appending stubs to the test target file, developers can:- Compile isolated .cpp files
- Avoid linker errors due to missing symbols
- Easily test legacy code with unknown or complex dependencies
- Static performance analysis on partial codebases.
- Early integration of modules before all dependencies are available.
- CI/CD build stability even with missing components.
- C/C++ to other language migration workflows (e.g., Rust), where linkability is required before full conversion.
Example
The following table shows examples of output generated by the link stubber. To simplify the examples, the main function is omitted. The tool can optionally generate a `main` function if missing.
Input C++ Source | Generated Stubs |
---|---|
extern int var1;
namespace ns {
extern int var2;
}
void func() {
var1 = 0;
ns::var2 = 1;
}
|
Demonstrates the generation of global variables across namespaces.
int ns::var2 = (int)0;
int var1 = (int)0;
|
struct B1 {
B1(int i);
int i;
};
struct S1 : public B1 {
S1(int j);
int j;
};
extern S1 var1;
void func() {
var1.i = 1;
var1.j = 1;
}
|
Shows constructor stubbing with inheritance and initialization of extern objects.
B1::B1(int i) {
}
int __tmp1 = (int)0;
S1::S1(int j) : B1(__tmp1) {
}
int __tmp0 = (int)0;
S1 var1(__tmp0);
|
class C {
public:
static void func2();
int func3();
};
void func() {
C::func2();
C().func3();
}
|
Handles stub generation for static and non-static member functions.
int __tmp0 = (int)0;
int C::func3() {
return __tmp0;
}
void C::func2() {
}
|
class V1 {
public:
V1();
virtual ~V1();
virtual void test() = 0;
};
class C1 : public V1 {
public:
C1();
void test();
};
extern C1 var1;
void func() {
var1.test();
}
|
Demonstrates stub generation for abstract base classes and virtual methods.
V1::V1() {
}
C1::C1() : V1() {
}
V1::~V1() noexcept {
}
C1 var1;
void C1::test() {
}
|
#include <vector>
extern std::vector<int> var1;
int func1() {
return var1.size();
}
|
Handles standard library containers such as std::vector.
std::vector<int, std::allocator<int>> var1;
|
Limitations
- Stub implementations are not functional — they only satisfy the linker.
- Care must be taken to avoid executing stubbed functions in functional tests.
- Test engineers can use the generated stubs as templates and extend them with realistic behavior if needed.