Cross-Language Invocation of C++ Components on Linux for Python and Java

Meituan Search solves costly multi‑language maintenance by building a core C++ library, wrapping it with a C interface, and exposing the functions to Python via ctypes and to Java via JNI or JNA, enabling shared logic, easier packaging, and lower latency on Linux.

Meituan Technology Team
Meituan Technology Team
Meituan Technology Team
Cross-Language Invocation of C++ Components on Linux for Python and Java

This article describes a practical solution used in Meituan Search for sharing a core C++ component across multiple languages (Python and Java) on Linux. It explains why developing the same functionality in different languages increases maintenance cost and can lead to inconsistent behavior, and proposes building the component once in C++ and exposing it via cross‑language calls.

Background : Query Understanding (QU) is a core module of Meituan Search written in C++. Offline data processing pipelines are implemented in Python and Java, which need to use the same text‑processing logic as the online service. Maintaining separate implementations would be costly, so a unified native library is required.

Solution Overview : A C++ library (libstr_print_cpp) is wrapped with a C‑style interface (c_wrapper) to make it callable from both Python (using ctypes) and Java (using JNI or JNA). The wrapper converts C++ symbols to C symbols (extern "C") and provides simple functions such as str_print that print a string.

Implementation Details :

3.1 Functional Code : The example C++ header and source files define a StrPrint class with a print method. The header ( str_print.h) and implementation ( str_print.cpp) are compiled into a shared object ( libstr_print_cpp.so) or static library.

3.1.2 c_wrapper : A thin C wrapper ( c_wrapper.cpp) exposes a C function str_print(const char* text) that internally creates a StrPrint instance and forwards the call.

3.1.3 Building the Shared Library : Three build options are provided:

Option 1 – source‑dependency: compile both C++ code and wrapper together into libstr_print.so.

Option 2 – dynamic link: build libstr_print.so that depends on libstr_print_cpp.so.

Option 3 – static link: link the static archive libstr_print_cpp.a into the shared object.

3.1.4 Python Integration : Using ctypes, the shared library is loaded and str_print is called. Helper functions handle Python‑2/3 compatibility and UTF‑8 encoding.

3.1.5 Java Integration : Two approaches are shown:

JNI – generate a native header with javah, implement Java_JniDemo_print, and compile a shared library.

JNA – declare a Java interface extending Library, load the native library with Native.load, and call str_print directly without writing C glue code.

Packaging and Distribution : The article explains how to package the native library together with language‑specific code. For Python, a wheel is built with setup.py, MANIFEST.in, and the shared object placed under the package directory. For Java, the JAR includes the native library and uses the Maven Assembly plugin to create an “uber‑jar” with dependencies.

Usability Optimizations :

Python version compatibility (handling bytes vs str).

Dependency management – ensuring required libstdc++.so and other system libraries are discoverable via LD_LIBRARY_PATH or java.library.path.

Principles : The need for a C wrapper stems from C++ name mangling; exposing C symbols guarantees stable lookup via dlsym. Parameter passing differs between primitive types (value copy) and complex objects (pointer/reference), requiring careful mapping in JNI/JNA.

Performance Analysis : Benchmarks compare pure C, Java, JNI, JNA, and JNA DirectMapping for a cosine computation loop. Results show C > Java > JNI ≈ JNA DirectMapping > JNA, with JNA being the slowest due to additional proxy overhead.

Application Cases :

Offline tasks – replacing RPC calls with native calls saved hours of network latency and eliminated failure points.

Online services – native calls reduced latency and resource consumption for query‑understanding features.

Conclusion : Cross‑language native calls can reduce development cost and improve performance when the computation is lightweight and latency‑sensitive. The article provides a complete reference implementation and discusses limitations (e.g., Linux‑only, missing Windows/macOS support).

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaperformancePythonCLinuxJNICross-languageJNA
Meituan Technology Team
Written by

Meituan Technology Team

Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.