OpenHarmony Platform¶
Complete guide to building C++ libraries for OpenHarmony (OHOS) with CCGO.
Overview¶
CCGO provides comprehensive OpenHarmony support with:
- Multiple architectures: ARMv7, ARM64, x86_64
- Output formats: HAR packages, Static libraries (.a), Shared libraries (.so)
- Build methods: Local (DevEco Studio) or Docker (cross-platform)
- IDE support: DevEco Studio project generation
- Publishing: OHPM registry integration
- ArkTS integration: Native module interface (NAPI) support
- API compatibility: OpenHarmony 3.2+
Prerequisites¶
Option 1: Local Build (OpenHarmony SDK Required)¶
Install DevEco Studio:
- Download from OpenHarmony Developer Portal
- Install OpenHarmony SDK through DevEco Studio
- Configure SDK path
Required tools:
# Install Node.js (for OHPM)
# Download from nodejs.org
# Install OHPM (OpenHarmony Package Manager)
npm install -g @ohos/hpm-cli
# Verify installation
node --version
ohpm --version
Environment setup:
# Set OHOS SDK path
export OHOS_SDK_HOME="/path/to/ohos-sdk"
export PATH="$OHOS_SDK_HOME/native/build-tools/cmake/bin:$PATH"
# Verify
cmake --version
Option 2: Docker Build (Any OS)¶
Build OpenHarmony libraries on any OS using Docker.
Required: - Docker Desktop installed and running - 4GB+ disk space for Docker image
Advantages: - Build on any operating system - No DevEco Studio required - Consistent build environment - Pre-configured OHOS SDK
Limitations: - Cannot run on OpenHarmony devices - Cannot use DevEco Studio integration - Larger initial download (~1.5GB image)
See Docker Builds section for details.
Quick Start¶
Basic Build¶
# Build for default architecture (arm64-v8a)
ccgo build ohos
# Build with Docker (cross-compile from any OS)
ccgo build ohos --docker
# Specify architecture
ccgo build ohos --arch armeabi-v7a # 32-bit ARM
ccgo build ohos --arch arm64-v8a # 64-bit ARM (default)
ccgo build ohos --arch x86_64 # x86_64 emulator
# Build multiple architectures
ccgo build ohos --arch armeabi-v7a,arm64-v8a,x86_64
# Build types
ccgo build ohos --build-type debug # Debug build
ccgo build ohos --build-type release # Release build (default)
# Link types
ccgo build ohos --build-as static # Static library only
ccgo build ohos --build-as shared # Shared library only
ccgo build ohos --build-as both # Both types (default)
# Generate HAR package
ccgo build ohos --har # Creates .har package
Generate DevEco Studio Project¶
# Generate DevEco Studio project
ccgo build ohos --ide-project
# Open in DevEco Studio
# File -> Open -> cmake_build/ohos/
Output Structure¶
Default Output (target/ohos/)¶
target/ohos/
├── MyLib_OHOS_SDK-1.0.0.zip # Main package
│ ├── lib/
│ │ ├── static/
│ │ │ ├── armeabi-v7a/
│ │ │ │ └── libmylib.a # 32-bit ARM static
│ │ │ ├── arm64-v8a/
│ │ │ │ └── libmylib.a # 64-bit ARM static
│ │ │ └── x86_64/
│ │ │ └── libmylib.a # x86_64 static
│ │ └── shared/
│ │ ├── armeabi-v7a/
│ │ │ └── libmylib.so # 32-bit ARM shared
│ │ ├── arm64-v8a/
│ │ │ └── libmylib.so # 64-bit ARM shared
│ │ └── x86_64/
│ │ └── libmylib.so # x86_64 shared
│ ├── haars/
│ │ └── mylib-1.0.0.har # HAR package
│ ├── include/
│ │ └── mylib/ # Header files
│ │ ├── mylib.h
│ │ └── version.h
│ └── build_info.json # Build metadata
│
└── MyLib_OHOS_SDK-1.0.0-SYMBOLS.zip # Debug symbols
└── obj/
├── armeabi-v7a/
│ └── libmylib.so # Unstripped library
├── arm64-v8a/
│ └── libmylib.so
└── x86_64/
└── libmylib.so
HAR Package¶
HAR (Harmony Archive) is OpenHarmony's library package format:
Structure:
mylib-1.0.0.har
├── libs/
│ ├── armeabi-v7a/
│ │ └── libmylib.so
│ ├── arm64-v8a/
│ │ └── libmylib.so
│ └── x86_64/
│ └── libmylib.so
├── include/
│ └── mylib/
│ ├── mylib.h
│ └── version.h
├── oh-package.json5 # Package metadata
└── module.json5 # Module configuration
oh-package.json5:
{
"name": "mylib",
"version": "1.0.0",
"description": "My OpenHarmony library",
"main": "index.ets",
"author": "Your Name",
"license": "MIT",
"dependencies": {},
"devDependencies": {}
}
Build Metadata¶
build_info.json contains:
{
"project": {
"name": "MyLib",
"version": "1.0.0",
"description": "My OpenHarmony library"
},
"build": {
"platform": "ohos",
"architectures": ["armeabi-v7a", "arm64-v8a", "x86_64"],
"build_type": "release",
"link_types": ["static", "shared"],
"timestamp": "2024-01-15T10:30:00Z",
"ccgo_version": "0.1.0",
"ohos_sdk_version": "10",
"api_version": "10"
},
"outputs": {
"libraries": {
"static": {
"armeabi-v7a": "lib/static/armeabi-v7a/libmylib.a",
"arm64-v8a": "lib/static/arm64-v8a/libmylib.a",
"x86_64": "lib/static/x86_64/libmylib.a"
},
"shared": {
"armeabi-v7a": "lib/shared/armeabi-v7a/libmylib.so",
"arm64-v8a": "lib/shared/arm64-v8a/libmylib.so",
"x86_64": "lib/shared/x86_64/libmylib.so"
}
},
"har": "haars/mylib-1.0.0.har",
"headers": "include/mylib/"
}
}
Using Libraries in OpenHarmony¶
In ArkTS/eTS Application¶
1. Add HAR dependency:
2. Create native module wrapper:
// src/native/mylib_napi.cpp
#include <napi/native_api.h>
#include <mylib/mylib.h>
static napi_value DoWork(napi_env env, napi_callback_info info) {
mylib::MyClass obj;
obj.do_work();
napi_value result;
napi_create_int32(env, 0, &result);
return result;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor desc[] = {
{ "doWork", nullptr, DoWork, nullptr, nullptr, nullptr, napi_default, nullptr }
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
static napi_module myLibModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "mylib",
.nm_priv = nullptr,
.reserved = { 0 },
};
extern "C" __attribute__((constructor)) void RegisterMyLibModule() {
napi_module_register(&myLibModule);
}
3. Use in ArkTS:
// src/main/ets/pages/Index.ets
import mylib from 'libmylib.so';
@Entry
@Component
struct Index {
build() {
Button('Do Work')
.onClick(() => {
mylib.doWork();
})
}
}
In C++ Application¶
CMakeLists.txt:
# Link static library
target_link_libraries(myapp PRIVATE
${CMAKE_SOURCE_DIR}/libs/${OHOS_ARCH}/libmylib.a
)
target_include_directories(myapp PRIVATE
${CMAKE_SOURCE_DIR}/include
)
Direct usage:
Docker Builds¶
Build OpenHarmony libraries on any OS using Docker:
Prerequisites¶
# Install Docker Desktop
# Download from: https://www.docker.com/products/docker-desktop/
# Verify Docker is running
docker ps
Build with Docker¶
# First build downloads prebuilt image (~1.5GB)
ccgo build ohos --docker
# Subsequent builds are fast
ccgo build ohos --docker --arch arm64-v8a
# All standard options work
ccgo build ohos --docker --arch armeabi-v7a,arm64-v8a --har
How It Works¶
- CCGO uses prebuilt
ccgo-builder-ohosimage from Docker Hub - Project directory mounted into container
- Build runs with OHOS SDK and toolchain
- Output written to host filesystem
Limitations¶
- Cannot run: No OpenHarmony runtime in Docker
- Cannot test: No device or emulator access
- No DevEco Studio: Cannot generate IDE projects
Publishing to OHPM¶
OHPM (OpenHarmony Package Manager) is the official package registry.
Setup¶
# Login to OHPM
ohpm login
# Configure registry (if using private registry)
ohpm config set registry https://your-registry.com
Publish¶
# Publish HAR to official OHPM registry
ccgo publish ohos --registry official
# Publish to private registry
ccgo publish ohos --registry private --url https://your-registry.com
# Skip build and publish existing HAR
ccgo publish ohos --skip-build
Package Configuration¶
Ensure CCGO.toml has correct metadata:
[package]
name = "mylib"
version = "1.0.0"
description = "My OpenHarmony library"
authors = ["Your Name <your.email@example.com>"]
license = "MIT"
homepage = "https://github.com/yourusername/mylib"
repository = "https://github.com/yourusername/mylib"
[ohos]
min_api_version = 9
target_api_version = 10
Platform Configuration¶
CCGO.toml Settings¶
[package]
name = "mylib"
version = "1.0.0"
[library]
type = "both" # static, shared, or both
[build]
cpp_standard = "17" # C++ standard
[ohos]
min_api_version = 9 # Minimum API version
target_api_version = 10 # Target API version
compile_sdk_version = 10 # Compile SDK version
ndk_version = "4.0.0" # NDK version
CMake Variables¶
When building for OpenHarmony:
${PLATFORM} # "ohos"
${OHOS_ARCH} # "armeabi-v7a", "arm64-v8a", or "x86_64"
${BUILD_TYPE} # "Debug" or "Release"
${LINK_TYPE} # "static", "shared", or "both"
${OHOS_API_VERSION} # Target API version
${OHOS_SDK_HOME} # OHOS SDK path
Conditional Compilation¶
// Platform detection
#ifdef __OHOS__
// OpenHarmony-specific code
#include <hilog/log.h>
#ifdef __aarch64__
// ARM64-specific code
#elif defined(__arm__)
// ARMv7-specific code
#elif defined(__x86_64__)
// x86_64-specific code
#endif
#endif
// API version detection
#if __OHOS_API_VERSION__ >= 10
// API 10+ features
#else
// Fallback for older APIs
#endif
// Logging
#ifdef __OHOS__
#define LOG_TAG "MyLib"
#define LOG_INFO(fmt, ...) \
OH_LOG_INFO(LOG_APP, fmt, ##__VA_ARGS__)
#else
#define LOG_INFO(fmt, ...) \
printf(fmt "\n", ##__VA_ARGS__)
#endif
Best Practices¶
1. Use HAR Packages¶
Package libraries as HAR for easy distribution:
2. Support Multiple Architectures¶
Build for all common architectures:
3. Implement NAPI Wrappers¶
Provide ArkTS/eTS bindings for C++ code:
// Always wrap native code with NAPI
static napi_value ExportFunction(napi_env env, napi_callback_info info) {
// Implementation
}
4. Use HiLog for Logging¶
Use OpenHarmony's logging system:
#include <hilog/log.h>
#define LOG_DOMAIN 0x0001
#define LOG_TAG "MyLib"
void log_message() {
OH_LOG_INFO(LOG_APP, "Message from MyLib");
}
5. Handle API Versioning¶
Check API version at runtime:
#include <parameter/system_parameter.h>
int get_api_version() {
char value[32];
int ret = GetParameter("const.ohos.apiversion", "", value, sizeof(value));
if (ret > 0) {
return atoi(value);
}
return 0;
}
6. Test on Real Devices¶
Always test on physical OpenHarmony devices: - Different API versions (9, 10, 11+) - Different architectures (ARM32, ARM64) - Different OEMs and device types
7. Minimize Library Size¶
Reduce HAR size for faster downloads:
Troubleshooting¶
OHOS SDK Not Found¶
Solution:
# Set OHOS SDK path
export OHOS_SDK_HOME="/path/to/ohos-sdk"
# Or in CCGO.toml
[ohos]
sdk_path = "/path/to/ohos-sdk"
# Verify
ls $OHOS_SDK_HOME/native
HAR Import Failed¶
Solutions:
-
Check oh-package.json5:
-
Verify HAR structure:
-
Reinstall dependencies:
NAPI Symbol Not Found¶
Solutions:
-
Check library is in HAR:
-
Verify module name matches:
-
Check build.gradle:
API Version Mismatch¶
Solution:
Update device or lower minimum API version:
Architecture Not Supported¶
Solution:
Build for missing architecture:
Performance Tips¶
1. Use ARM NEON Instructions¶
Enable NEON optimizations for ARM:
2. Link-Time Optimization¶
3. Optimize for Size¶
OpenHarmony devices often have limited storage:
[build]
cxxflags = ["-Os", "-ffunction-sections", "-fdata-sections"]
ldflags = ["-Wl,--gc-sections"]
4. Static Linking for Performance¶
Static libraries can be faster:
5. Profile on Device¶
Use HiPerf for profiling:
Migration Guides¶
From Native C++ Module¶
Before:
After:
-
Create CCGO project:
-
Add NAPI wrapper:
-
Build HAR:
From Android NDK Library¶
Many similarities with Android:
Differences: - Use HAR instead of AAR - Use OHPM instead of Maven - Use NAPI instead of JNI - Different build system (Hvigor vs Gradle)
Migration steps:
- Copy C++ code to CCGO project
-
Update build configuration:
-
Replace JNI with NAPI:
-
Build:
Advanced Topics¶
Multi-Module HAR¶
Create HAR with multiple modules:
mylib/
├── core/ # Core module
│ ├── src/
│ └── include/
├── ui/ # UI module
│ ├── src/
│ └── include/
└── CCGO.toml
[package]
name = "mylib"
[[modules]]
name = "core"
path = "core"
[[modules]]
name = "ui"
path = "ui"
dependencies = ["core"]
Embedding Resources¶
Include resources in HAR:
mylib-1.0.0.har
├── libs/
├── include/
├── resources/
│ ├── base/
│ │ └── element/
│ └── rawfile/
│ └── data.bin
└── oh-package.json5
Code Signing¶
Sign HAR for distribution:
# Generate key
hapsigner generate-keypair -keyAlias mylib -keyAlg RSA
# Sign HAR
hapsigner sign-app -mode localSign \
-keyAlias mylib \
-signAlg SHA256withRSA \
-inputFile mylib-1.0.0.har \
-outputFile mylib-1.0.0-signed.har
Obfuscation¶
Protect C++ code: