
技术分享 | 使用Golang开发鸿蒙模块 原创 精华
背景
最近在社区和交流群中看到许多开发者在询问:如何将使用 Golang 开发的动态/静态链接库在鸿蒙中进行适配?
其实鸿蒙原生开发本质上对于语言没有太大的限制,只要是能够构建出符合标准的动态/静态链接库即可在Native层进行载入。那么我们是否可以在鸿蒙上也使用 Golang 开发一些能力来供给上层的 ArkTS 使用呢?
本文我们尝试将 Golang 写的代码编译成动态库,并在鸿蒙应用上进行加载运行。
关于 Golang
关于 Golang 的开发环境配置、项目初始化等能力这里不做过多的讲解。
截至到目前2025年8月13日为止,在OpenHarmony SIG组织内有发现一个ohos_golang_go适配库,但需要使用该库编译出 Golang二进制包才能进行后续开发使用。且目前该仓库是关闭状态。所以暂时没有使用该库进行尝试。下面我们将使用普通的 Golang 发行版进行尝试。
实现一个简单的程序
我们先写一个简单的CGO程序main.go,实现一个Add方法计算2数相加,实现一个Hello方法输出"Hello, HarmonyOS"。
package main
import "C"
//export Add
func Add(x, y C.double) C.double {
return x + y
}
//export Hello
func Hello () *C.char {
return C.CString("Hello, HarmonyOS")
}
func main() {}
接下来编写编译脚本build.sh,因为普通的 Golang 发行版不支持GOOS=openharmony,这里我们先用android的,因为安卓也是继续llvm工具链进行编译。方便替换。
export GOARCH=arm64
export GOOS=android
export CGO_ENABLED=1
export LLVMCONFIG=$OHOS_SDK/native/llvm/bin/llvm-config
export CGO_CFLAGS="-g -O2 `$LLVMCONFIG --cflags` --target=aarch64-linux-ohos --sysroot=$OHOS_SDK/native/sysroot"
export CGO_LDFLAGS="--target=aarch64-linux-ohos -fuse-ld=lld"
export CC="$OHOS_SDK/native/llvm/bin/clang"
export CXX="$OHOS_SDK/native/llvm/bin/clang++"
export AR="$OHOS_SDK/native/llvm/bin/llvm-ar"
export LD="$OHOS_SDK/native/llvm/bin/lld"
go build -buildmode=c-shared -v -x -o libohos.so main.go
执行build.sh版本编译,这时候应该就报错了,信息如下:
WORK=/tmp/go-build1732306041
runtime/cgo
mkdir -p $WORK/b003/
echo -n > $WORK/b003/preferlinkext # internal
cd /usr/local/go/src/runtime/cgo
... ...
# runtime/cgo
gcc_android.c:6:10: fatal error: 'android/log.h' file not found
因为使用了GOOS=android,所以找不到对应的头文件和动态库。
实现一个 liblog 动态库
我们使用鸿蒙的hilog实现一个兼容安卓接口的log库,创建log.h、log.c和CMakeLists.txt文件
#ifndef LOG_H
#define LOG_H
#include <stdarg.h>
enum android_LogPriority {
ANDROID_LOG_UNKNOWN = 0,
ANDROID_LOG_DEFAULT,
ANDROID_LOG_VERBOSE,
ANDROID_LOG_DEBUG,
ANDROID_LOG_INFO,
ANDROID_LOG_WARN,
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL,
ANDROID_LOG_SILENT
};
#ifdef __cplusplus
extern "C" {
#endif
int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap);
#ifdef __cplusplus
}
#endif
#endif // LOG_H
#include <stdarg.h>
#include <stdio.h>
#include "hilog/log.h"
int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) {
char buffer[4096];
vsnprintf(buffer, sizeof(buffer), fmt, ap);
OH_LOG_DEBUG(LOG_APP, "[%s] %s\n", tag, buffer);
return 0;
}
cmake_minimum_required(VERSION 3.15)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(log)
include_directories(/home/groot/ohos-sdk-41/linux/native/sysroot/usr/include)
link_directories(/home/groot/ohos-sdk-41/linux/native/sysroot/usr/lib/aarch64-linux-ohos)
add_library(log SHARED
${CMAKE_SOURCE_DIR}/log.h
${CMAKE_SOURCE_DIR}/log.c
)
target_link_libraries(log PUBLIC libace_napi.z.so libhilog_ndk.z.so)
使用鸿蒙编译工具链编译出liblog.so,然后将liblog.so和log.h拷贝到鸿蒙SDK目录下:
mkdir $OHOS_SDK/native/sysroot/usr/include/android
cp log.h $OHOS_SDK/native/sysroot/usr/include/android/
cp liblog.so $OHOS_SDK/native/sysroot/usr/lib/aarch64-linux-ohos/
重新编译CGO程序
这时候我们重新编译CGO程序就能顺利完成了,最终输出libohos.h和libohos.so
groot@ohosdev:/data/go/src/libohos$ sh build.sh
WORK=/tmp/go-build774055739
runtime/cgo
mkdir -p $WORK/b003/
echo -n > $WORK/b003/preferlinkext # internal
... ...
mkdir -p $WORK/b001/exe/
cd $WORK/b001/exe/
GOROOT='/usr/local/go' /usr/local/go/pkg/tool/linux_amd64/link -o a.out -importcfg $WORK/b001/importcfg.link -installsuffix shared -X=runtime.godebugDefault=asynctimerchan=1,gotypesalias=0,httplaxcontentlength=1,httpmuxgo121=1,httpservecontentkeepheaders=1,netedns0=0,panicnil=1,tls10server=1,tls3des=1,tlskyber=0,tlsrsakex=1,tlsunsafeekm=1,winreadlinkvolume=0,winsymlink=0,x509keypairleaf=0,x509negativeserial=1 -buildmode=c-shared -buildid=WkidA50M_C-Y65VsHGXj/PQ13pVuInutHJMPDnVLU/Xj9KziFAvg-H7w0gsy_I/WkidA50M_C-Y65VsHGXj -extld=/home/groot/ohos-sdk-41/linux/native/llvm/bin/clang $WORK/b001/_pkg_.a
/usr/local/go/pkg/tool/linux_amd64/buildid -w $WORK/b001/exe/a.out # internal
mv $WORK/b001/_cgo_install.h libohos.h
mv $WORK/b001/exe/a.out libohos.so
rm -rf $WORK/b001/
groot@ohosdev:/data/go/src/libohos$ ls
build.sh go.mod libohos.h libohos.so main.go
这时候就可以将输出的动态库放到鸿蒙应用内加载使用了。
鸿蒙应用加载
将libohos.so和liblog.so这2个动态库拷贝到应用的entry/libs/arm64-v8a目录下
将libohos.h拷贝到应用的entry/src/main/cpp目录下,并修改该目录下的CMakeLists.txt配置加载libohos动态库
cmake_minimum_required(VERSION 3.4.1)
project(MyApplication)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include
)
link_directories("${NATIVERENDER_ROOT_PATH}/../../../libs/${OHOS_ARCH}")
add_library(entry SHARED hello.cpp)
target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libohos.so)
调用Golang方法
#include "napi/native_api.h"
#include "libohos.h"
#include <thread>
void threadCallGolangFunction(std::promise<int> &&promiseObj) {
Hello();
double result = Add(99, 99);
promiseObj.set_value(result);
}
static napi_value NapiAdd(napi_env env, napi_callback_info info) {
std::promise<int> promiseObj;
std::future<int> futureObj = promiseObj.get_future();
std::thread async_thread(threadCallGolangFunction, std::move(promiseObj));
int returnValue = futureObj.get();
async_thread.join();
OH_LOG_DEBUG(LOG_APP, "#####%d", returnValue);
return NULL;
}
结束
至此我们已经成功的在鸿蒙应用上加载并运行 Golang 模块提供的功能!
