Taihe: Cut Cross-Language Binding Code by 95% with IDL
Taihe is a HarmonyOS cross-language tool that replaces 200+ lines of manual NAPI binding code with a 4-line IDL definition, generating type-safe C++, ArkTS, and NAPI bindings through a compiler pipeline with stable ABI and language projections.
The Problem: Manual Cross-Language Binding Is Painful
In HarmonyOS development, ArkTS applications often need to call C++ core capabilities. The traditional approach requires developers to master NAPI, type conversion, and memory management simultaneously. A typical Calculator interface with a single add method demands over 200 lines of handwritten code across C++, NAPI bridge, and ArkTS declarations:
// C++ implementation
class Calculator {
public:
int add(int a, int b) { return a + b; }
};
// NAPI binding (simplified; real code is longer)
static napi_value Add(napi_env env, napi_callback_info info) {
size_t argc = 2;
napi_value args[2];
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
int32_t a, b;
napi_get_value_int32(env, args[0], &a);
napi_get_value_int32(env, args[1], &b);
Calculator* calc = new Calculator();
int result = calc->add(a, b);
napi_value napiResult;
napi_create_int32(env, result, &napiResult);
return napiResult;
}
// ArkTS side still needs matching type declarations
export declare class Calculator {
add(a: number, b: number): number;
}Any interface change forces synchronized edits in three places; a single omission causes crashes or memory leaks.
What Is Taihe?
Taihe is a cross-language interface definition and code generation tool for the HarmonyOS ecosystem. Its mission: provide a reliable, efficient, maintainable cross-language solution through a unified Interface Definition Language (IDL) .
Toolchain: taihec Compiler
The core CLI taihec parses .ohidl files and generates target-language code via pluggable backends:
taihec [taihe_files ...] [options ...] taihe_files: one or more IDL files (wildcards supported, e.g., path/to/idl/*.ohidl) options: control code generation (see command-line options table in article)
Backends include:
Common backend – shared infrastructure
C/C++ backend – generates C++ projection headers and implementation templates
ArkTS backend – generates .d.ts declarations
NAPI bridge backend – generates NAPI glue code
Example:
taihec path/to/idl/*.ohidl -O path/to/generated -Gnapi-bridge -Gcpp-authorproduces a full directory tree with ABI headers, C++ user/impl headers, NAPI bridge .cpp/.h, registration files, and ArkTS declarations.
Core Philosophy: Interface as Contract
Taihe starts from a clear premise: the interface definition is the core of cross-language development; languages are mere implementation details . Developers describe what the interface looks like in IDL; Taihe generates idiomatic bindings for each target language.
Concise Interface Definition
A complete cross-language interface in 4 lines:
// my.package.ohidl
interface ICalculator {
add(a: i32, b: i32): i32;
hello(name: String): String;
}Automatically Generated Multi-Language Bindings
Running taihec on the above yields:
path/to/generated/
├── include/
│ ├── my.package.abi.h // ABI layer: aggregate header
│ ├── my.package.proj.hpp // C++ layer: common aggregate header
│ ├── my.package.user.hpp // C++ layer: consumer-facing header
│ ├── my.package.impl.hpp // C++ layer: provider-facing header
│ └── my.package.napi.h // NAPI layer: bridge header
├── src/
│ ├── my.package.napi.cpp // NAPI layer: bridge implementation
│ └── my.package.abi.c // ABI layer: IID symbol definitions
└── temp/
├── my.package.napi_register.cpp // NAPI layer: registration
└── my.package.impl.cpp // C++ layer: provider implementation template
└── my.package.d.ts // ArkTS declaration fileEach language gets its own idiomatic API; developers consume generated code without worrying about low-level details.
System Architecture: Compiler, ABI, and Language Projection
Taihe's power stems from three pillars:
1. Taihe Compiler ( taihec ) – Classic Three-Stage Design
Frontend : Parses IDL source into an Intermediate Representation (IR).
Semantic Analysis : Type-checks and validates IR; processes annotations for fine-grained codegen control.
Code Generation : Pluggable language backends transform verified IR into target-language code.
2. Stable ABI (Application Binary Interface)
The compiler emits a C-based ABI that precisely defines memory layout of data types and calling conventions. This ABI acts as a universal binary language understood by all target languages, forming the foundation for interoperability.
3. Language Projection
Direct ABI usage is tedious and error-prone. Taihe automatically generates language projections – high-level, ergonomic API wrappers per language:
C++ developers get C++ types, reference-counted interface objects, macros/templates for exporting implementations, and STL-style containers.
ArkTS developers get native ArkTS classes and functions; cross-language communication details are handled transparently.
Core Technical Advantages
Multi-Target Languages: One Definition, Multiple Implementations
Taihe supports ArkTS, C++, and more simultaneously. A single IDL produces:
C ABI layer – low-level foundation
C++ projection layer – comfortable C++ API
NAPI binding – for ArkTS consumption
All artifacts are generated at compile time , fully decoupled, with minimal runtime overhead. Taihe is not a compatibility layer; it auto-generates independent bindings per language.
Binary Isolation: Provider/Consumer Decoupling
Taihe cleanly separates roles:
Provider : Defines interface in .ohidl, runs taihec with provider-oriented backends, implements logic in native code using generated macros/templates, exports via TH_EXPORT_CPP_API_*.
Consumer : Imports generated consumer-facing headers/modules, calls IDL-defined classes/functions like a regular library; ABI interaction is automatic.
The C ABI middle layer ensures binary compatibility across compilers and platforms.
Additional Features
Full OOP support : Single and multiple interface inheritance via precise v-table and RTTI layout, enabling efficient static casts and safe dynamic casts.
Automatic memory management : Reference counting for interface objects and most containers, with strong/weak references.
Rich containers & data types : Value-semantic Array<T>, Optional<T>; ref-counted String, Vector<T>, Map<K,V>, Set<T>; plus function closures.
Flexible annotation system : Annotations like @readonly, @get, @promise control codegen (e.g., map methods to property getters/setters, generate async functions).
Real-World Development Workflow: Calculator Example
Step 1: Write IDL
interface ICalculator {
add(a: i32, b: i32): i32;
subtract(a: i32, b: i32): i32;
multiply(a: i32, b: i32): i32;
divide(a: i32, b: i32): i32;
hello(name: String): String;
}
function create(): ICalculator;Step 2: Compile with taihec
taihec calculator.ohidl -O generated -Gnapi-bridge -Gcpp-authorGenerates the full directory structure (see article for screenshot).
Step 3: Implement C++ Interface
Fill in the generated implementation template:
// calculator.impl.cpp
class CalculatorImpl {
public:
int32_t add(int32_t a, int32_t b) {
return a + b;
}
int32_t subtract(int32_t a, int32_t b) {
return a - b;
}
int32_t multiply(int32_t a, int32_t b) {
return a * b;
}
int32_t divide(int32_t a, int32_t b) {
if (b == 0) return 0;
return a / b;
}
::taihe::string hello(::taihe::string_view name) {
return "Hello, " + name + "!";
}
};
ICalculator create() {
return ::taihe::make_holder<CalculatorImpl, ICalculator>();
}
// Export interface
TH_EXPORT_CPP_API_create(create);Step 4: Call from ArkTS
// Index.ets
import testNapi from 'libentry.so';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize($r('app.float.page_text_font_size'))
.fontWeight(FontWeight.Bold)
.onClick(() => {
hilog.info(DOMAIN, 'testTag', '---------------------start test-----------------------');
let calculator: testNapi.ICalculator = testNapi.create();
hilog.info(DOMAIN, 'testTag', 'Test calculator add 2 + 3 = %{public}d', calculator.add(2, 3));
hilog.info(DOMAIN, 'testTag', 'Test calculator subtract 2 - 3 = %{public}d', calculator.subtract(2, 3));
hilog.info(DOMAIN, 'testTag', 'Test calculator multiply 2 * 3 = %{public}d', calculator.multiply(2, 3));
hilog.info(DOMAIN, 'testTag', 'Test calculator divide 2 / 3 = %{public}d', calculator.divide(2, 3));
hilog.info(DOMAIN, 'testTag', 'Test calculator hello %{public}s', calculator.hello("Alice"));
hilog.info(DOMAIN, 'testTag', '---------------------end test-----------------------');
})
.width('100%')
}
.height('100%')
}
}
}Running the app produces log output confirming each arithmetic operation and the greeting string.
Trade-offs and Considerations
Learning curve : Requires learning Taihe IDL syntax and target-language specifics; still simpler than handwritten bindings but not zero-cost.
Type mapping limits : Not all C++ types map directly; complex templates, pointers, references need extra handling.
Error-handling overhead : Type safety incurs runtime cost – each binding layer adds conversion and checking.
Build complexity : Integrating into existing projects needs Taihe compiler, runtime, and build template configuration.
These are inherent to cross-language development; Taihe merely reduces the complexity dramatically.
Summary
Taihe solves cross-language pain points by:
Replacing 200+ lines of boilerplate with a 4-line IDL
Generating type-safe, idiomatic bindings for C++, ArkTS, and NAPI at compile time
Providing a stable C ABI for binary compatibility
Delivering ergonomic language projections that hide ABI complexity
Supporting OOP, automatic memory management, rich containers, and annotation-driven customization
Developers focus on business logic; Taihe handles cross-language plumbing. As the HarmonyOS ecosystem matures, Taihe represents a paradigm shift – from how to implement to what to implement .
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
HarmonyOS Developer Technology
HarmonyOS developers provide key technology analysis, version updates, Codelabs practice, and event information for HarmonyOS. Welcome developers to join the HarmonyOS ecosystem and create infinite possibilities together!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
